blob: 092c346b0bd220e9b2410cd7f206a54f2e038e04 [file] [log] [blame]
Juan Castilloa57a4d52015-04-02 15:44:20 +01001/*
Antonio Nino Diaz30eb9672017-01-13 15:03:19 +00002 * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
Juan Castilloa57a4d52015-04-02 15:44:20 +01003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/*
Juan Castillobae6b2a2015-11-05 09:24:53 +000032 * X509 parser based on mbed TLS
Juan Castilloa57a4d52015-04-02 15:44:20 +010033 *
34 * This module implements functions to check the integrity of a X509v3
35 * certificate ASN.1 structure and extract authentication parameters from the
36 * extensions field, such as an image hash or a public key.
37 */
38
Antonio Nino Diaz30eb9672017-01-13 15:03:19 +000039#include <arch_helpers.h>
Juan Castilloa57a4d52015-04-02 15:44:20 +010040#include <assert.h>
41#include <img_parser_mod.h>
42#include <mbedtls_common.h>
43#include <stddef.h>
44#include <stdint.h>
45#include <string.h>
Douglas Raillarda8954fc2017-01-26 15:54:44 +000046#include <utils.h>
Juan Castilloa57a4d52015-04-02 15:44:20 +010047
Juan Castillobae6b2a2015-11-05 09:24:53 +000048/* mbed TLS headers */
49#include <mbedtls/asn1.h>
50#include <mbedtls/oid.h>
51#include <mbedtls/platform.h>
Juan Castilloa57a4d52015-04-02 15:44:20 +010052
53/* Maximum OID string length ("a.b.c.d.e.f ...") */
54#define MAX_OID_STR_LEN 64
55
Juan Castillobae6b2a2015-11-05 09:24:53 +000056#define LIB_NAME "mbed TLS X509v3"
Juan Castilloa57a4d52015-04-02 15:44:20 +010057
58/* Temporary variables to speed up the authentication parameters search. These
59 * variables are assigned once during the integrity check and used any time an
60 * authentication parameter is requested, so we do not have to parse the image
61 * again */
Juan Castillobae6b2a2015-11-05 09:24:53 +000062static mbedtls_asn1_buf tbs;
63static mbedtls_asn1_buf v3_ext;
64static mbedtls_asn1_buf pk;
65static mbedtls_asn1_buf sig_alg;
66static mbedtls_asn1_buf signature;
Juan Castilloa57a4d52015-04-02 15:44:20 +010067
68/*
Antonio Nino Diaz30eb9672017-01-13 15:03:19 +000069 * Clear all static temporary variables.
70 */
71static void clear_temp_vars(void)
72{
73#define ZERO_AND_CLEAN(x) \
74 do { \
Douglas Raillarda8954fc2017-01-26 15:54:44 +000075 zeromem(&x, sizeof(x)); \
Antonio Nino Diaz30eb9672017-01-13 15:03:19 +000076 clean_dcache_range((uintptr_t)&x, sizeof(x)); \
77 } while (0);
78
79 ZERO_AND_CLEAN(tbs)
80 ZERO_AND_CLEAN(v3_ext);
81 ZERO_AND_CLEAN(pk);
82 ZERO_AND_CLEAN(sig_alg);
83 ZERO_AND_CLEAN(signature);
84
85#undef ZERO_AND_CLEAN
86}
87
88/*
Juan Castilloa57a4d52015-04-02 15:44:20 +010089 * Get X509v3 extension
90 *
91 * Global variable 'v3_ext' must point to the extensions region
92 * in the certificate. No need to check for errors since the image has passed
93 * the integrity check.
94 */
95static int get_ext(const char *oid, void **ext, unsigned int *ext_len)
96{
97 int oid_len;
98 size_t len;
99 unsigned char *end_ext_data, *end_ext_octet;
100 unsigned char *p;
101 const unsigned char *end;
102 char oid_str[MAX_OID_STR_LEN];
Juan Castillobae6b2a2015-11-05 09:24:53 +0000103 mbedtls_asn1_buf extn_oid;
Juan Castilloa57a4d52015-04-02 15:44:20 +0100104 int is_critical;
105
106 assert(oid != NULL);
107
108 p = v3_ext.p;
109 end = v3_ext.p + v3_ext.len;
110
Juan Castillobae6b2a2015-11-05 09:24:53 +0000111 mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
112 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100113
114 while (p < end) {
Douglas Raillarda8954fc2017-01-26 15:54:44 +0000115 zeromem(&extn_oid, sizeof(extn_oid));
Juan Castilloa57a4d52015-04-02 15:44:20 +0100116 is_critical = 0; /* DEFAULT FALSE */
117
Juan Castillobae6b2a2015-11-05 09:24:53 +0000118 mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
119 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100120 end_ext_data = p + len;
121
122 /* Get extension ID */
123 extn_oid.tag = *p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000124 mbedtls_asn1_get_tag(&p, end, &extn_oid.len, MBEDTLS_ASN1_OID);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100125 extn_oid.p = p;
126 p += extn_oid.len;
127
128 /* Get optional critical */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000129 mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100130
131 /* Extension data */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000132 mbedtls_asn1_get_tag(&p, end_ext_data, &len,
133 MBEDTLS_ASN1_OCTET_STRING);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100134 end_ext_octet = p + len;
135
136 /* Detect requested extension */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000137 oid_len = mbedtls_oid_get_numeric_string(oid_str,
138 MAX_OID_STR_LEN,
139 &extn_oid);
140 if (oid_len == MBEDTLS_ERR_OID_BUF_TOO_SMALL) {
Juan Castilloa57a4d52015-04-02 15:44:20 +0100141 return IMG_PARSER_ERR;
142 }
143 if ((oid_len == strlen(oid_str)) && !strcmp(oid, oid_str)) {
144 *ext = (void *)p;
145 *ext_len = (unsigned int)len;
146 return IMG_PARSER_OK;
147 }
148
149 /* Next */
150 p = end_ext_octet;
151 }
152
153 return IMG_PARSER_ERR_NOT_FOUND;
154}
155
156
157/*
158 * Check the integrity of the certificate ASN.1 structure.
Antonio Nino Diaz30eb9672017-01-13 15:03:19 +0000159 *
Juan Castilloa57a4d52015-04-02 15:44:20 +0100160 * Extract the relevant data that will be used later during authentication.
Antonio Nino Diaz30eb9672017-01-13 15:03:19 +0000161 *
162 * This function doesn't clear the static variables located on the top of this
163 * file in case of an error. It is only called from check_integrity(), which
164 * performs the cleanup if necessary.
Juan Castilloa57a4d52015-04-02 15:44:20 +0100165 */
166static int cert_parse(void *img, unsigned int img_len)
167{
168 int ret, is_critical;
169 size_t len;
170 unsigned char *p, *end, *crt_end;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000171 mbedtls_asn1_buf sig_alg1, sig_alg2;
Juan Castilloa57a4d52015-04-02 15:44:20 +0100172
173 p = (unsigned char *)img;
174 len = img_len;
175 end = p + len;
176
177 /*
178 * Certificate ::= SEQUENCE {
179 * tbsCertificate TBSCertificate,
180 * signatureAlgorithm AlgorithmIdentifier,
181 * signatureValue BIT STRING }
182 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000183 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
184 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100185 if (ret != 0) {
186 return IMG_PARSER_ERR_FORMAT;
187 }
188
189 if (len > (size_t)(end - p)) {
190 return IMG_PARSER_ERR_FORMAT;
191 }
192 crt_end = p + len;
193
194 /*
195 * TBSCertificate ::= SEQUENCE {
196 */
197 tbs.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000198 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
199 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100200 if (ret != 0) {
201 return IMG_PARSER_ERR_FORMAT;
202 }
203 end = p + len;
204 tbs.len = end - tbs.p;
205
206 /*
207 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
208 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000209 ret = mbedtls_asn1_get_tag(&p, end, &len,
210 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
211 MBEDTLS_ASN1_CONSTRUCTED | 0);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100212 if (ret != 0) {
213 return IMG_PARSER_ERR_FORMAT;
214 }
215 p += len;
216
217 /*
218 * CertificateSerialNumber ::= INTEGER
219 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000220 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100221 if (ret != 0) {
222 return IMG_PARSER_ERR_FORMAT;
223 }
224 p += len;
225
226 /*
227 * signature AlgorithmIdentifier
228 */
229 sig_alg1.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000230 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
231 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100232 if (ret != 0) {
233 return IMG_PARSER_ERR_FORMAT;
234 }
235 if ((end - p) < 1) {
236 return IMG_PARSER_ERR_FORMAT;
237 }
238 sig_alg1.len = (p + len) - sig_alg1.p;
239 p += len;
240
241 /*
242 * issuer Name
243 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000244 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
245 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100246 if (ret != 0) {
247 return IMG_PARSER_ERR_FORMAT;
248 }
249 p += len;
250
251 /*
252 * Validity ::= SEQUENCE {
253 * notBefore Time,
254 * notAfter Time }
255 *
256 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000257 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
258 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100259 if (ret != 0) {
260 return IMG_PARSER_ERR_FORMAT;
261 }
262 p += len;
263
264 /*
265 * subject Name
266 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000267 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
268 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100269 if (ret != 0) {
270 return IMG_PARSER_ERR_FORMAT;
271 }
272 p += len;
273
274 /*
275 * SubjectPublicKeyInfo
276 */
277 pk.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000278 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
279 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100280 if (ret != 0) {
281 return IMG_PARSER_ERR_FORMAT;
282 }
283 pk.len = (p + len) - pk.p;
284 p += len;
285
286 /*
287 * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
288 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000289 ret = mbedtls_asn1_get_tag(&p, end, &len,
290 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
291 MBEDTLS_ASN1_CONSTRUCTED | 1);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100292 if (ret != 0) {
Juan Castillobae6b2a2015-11-05 09:24:53 +0000293 if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
Juan Castilloa57a4d52015-04-02 15:44:20 +0100294 return IMG_PARSER_ERR_FORMAT;
295 }
296 } else {
297 p += len;
298 }
299
300 /*
301 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
302 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000303 ret = mbedtls_asn1_get_tag(&p, end, &len,
304 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
305 MBEDTLS_ASN1_CONSTRUCTED | 2);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100306 if (ret != 0) {
Juan Castillobae6b2a2015-11-05 09:24:53 +0000307 if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
Juan Castilloa57a4d52015-04-02 15:44:20 +0100308 return IMG_PARSER_ERR_FORMAT;
309 }
310 } else {
311 p += len;
312 }
313
314 /*
315 * extensions [3] EXPLICIT Extensions OPTIONAL
316 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000317 ret = mbedtls_asn1_get_tag(&p, end, &len,
318 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
319 MBEDTLS_ASN1_CONSTRUCTED | 3);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100320 if (ret != 0) {
321 return IMG_PARSER_ERR_FORMAT;
322 }
323
324 /*
325 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
326 */
327 v3_ext.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000328 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
329 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100330 if (ret != 0) {
331 return IMG_PARSER_ERR_FORMAT;
332 }
333 v3_ext.len = (p + len) - v3_ext.p;
334
335 /*
336 * Check extensions integrity
337 */
338 while (p < end) {
Juan Castillobae6b2a2015-11-05 09:24:53 +0000339 ret = mbedtls_asn1_get_tag(&p, end, &len,
340 MBEDTLS_ASN1_CONSTRUCTED |
341 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100342 if (ret != 0) {
343 return IMG_PARSER_ERR_FORMAT;
344 }
345
346 /* Get extension ID */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000347 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100348 if (ret != 0) {
349 return IMG_PARSER_ERR_FORMAT;
350 }
351 p += len;
352
353 /* Get optional critical */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000354 ret = mbedtls_asn1_get_bool(&p, end, &is_critical);
355 if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
Juan Castilloa57a4d52015-04-02 15:44:20 +0100356 return IMG_PARSER_ERR_FORMAT;
357 }
358
359 /* Data should be octet string type */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000360 ret = mbedtls_asn1_get_tag(&p, end, &len,
361 MBEDTLS_ASN1_OCTET_STRING);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100362 if (ret != 0) {
363 return IMG_PARSER_ERR_FORMAT;
364 }
365 p += len;
366 }
367
368 if (p != end) {
369 return IMG_PARSER_ERR_FORMAT;
370 }
371
372 end = crt_end;
373
374 /*
375 * }
376 * -- end of TBSCertificate
377 *
378 * signatureAlgorithm AlgorithmIdentifier
379 */
380 sig_alg2.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000381 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
382 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100383 if (ret != 0) {
384 return IMG_PARSER_ERR_FORMAT;
385 }
386 if ((end - p) < 1) {
387 return IMG_PARSER_ERR_FORMAT;
388 }
389 sig_alg2.len = (p + len) - sig_alg2.p;
390 p += len;
391
392 /* Compare both signature algorithms */
393 if (sig_alg1.len != sig_alg2.len) {
394 return IMG_PARSER_ERR_FORMAT;
395 }
Antonio Nino Diaz0ca1afa2017-02-09 10:26:54 +0000396 if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) {
Juan Castilloa57a4d52015-04-02 15:44:20 +0100397 return IMG_PARSER_ERR_FORMAT;
398 }
399 memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg));
400
401 /*
402 * signatureValue BIT STRING
403 */
404 signature.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000405 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_BIT_STRING);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100406 if (ret != 0) {
407 return IMG_PARSER_ERR_FORMAT;
408 }
409 signature.len = (p + len) - signature.p;
410 p += len;
411
412 /* Check certificate length */
413 if (p != end) {
414 return IMG_PARSER_ERR_FORMAT;
415 }
416
417 return IMG_PARSER_OK;
418}
419
420
421/* Exported functions */
422
423static void init(void)
424{
425 mbedtls_init();
426}
427
Antonio Nino Diaz30eb9672017-01-13 15:03:19 +0000428/*
429 * Wrapper for cert_parse() that clears the static variables used by it in case
430 * of an error.
431 */
Juan Castilloa57a4d52015-04-02 15:44:20 +0100432static int check_integrity(void *img, unsigned int img_len)
433{
Antonio Nino Diaz30eb9672017-01-13 15:03:19 +0000434 int rc = cert_parse(img, img_len);
435
436 if (rc != IMG_PARSER_OK)
437 clear_temp_vars();
438
439 return rc;
Juan Castilloa57a4d52015-04-02 15:44:20 +0100440}
441
442/*
443 * Extract an authentication parameter from an X509v3 certificate
Juan Castillobfb7fa62016-01-22 11:05:57 +0000444 *
445 * This function returns a pointer to the extracted data and its length.
446 * Depending on the type of parameter, a pointer to the data stored in the
447 * certificate may be returned (i.e. an octet string containing a hash). Other
448 * data may need to be copied and formatted (i.e. integers). In the later case,
449 * a buffer of the correct type needs to be statically allocated, filled and
450 * returned.
Juan Castilloa57a4d52015-04-02 15:44:20 +0100451 */
452static int get_auth_param(const auth_param_type_desc_t *type_desc,
453 void *img, unsigned int img_len,
454 void **param, unsigned int *param_len)
455{
456 int rc = IMG_PARSER_OK;
457
458 /* We do not use img because the check_integrity function has already
459 * extracted the relevant data (v3_ext, pk, sig_alg, etc) */
460
461 switch (type_desc->type) {
462 case AUTH_PARAM_RAW_DATA:
463 /* Data to be signed */
464 *param = (void *)tbs.p;
465 *param_len = (unsigned int)tbs.len;
466 break;
467 case AUTH_PARAM_HASH:
Juan Castillobfb7fa62016-01-22 11:05:57 +0000468 case AUTH_PARAM_NV_CTR:
Juan Castilloa57a4d52015-04-02 15:44:20 +0100469 /* All these parameters are included as X509v3 extensions */
470 rc = get_ext(type_desc->cookie, param, param_len);
471 break;
472 case AUTH_PARAM_PUB_KEY:
473 if (type_desc->cookie != 0) {
474 /* Get public key from extension */
475 rc = get_ext(type_desc->cookie, param, param_len);
476 } else {
477 /* Get the subject public key */
478 *param = (void *)pk.p;
479 *param_len = (unsigned int)pk.len;
480 }
481 break;
482 case AUTH_PARAM_SIG_ALG:
483 /* Get the certificate signature algorithm */
484 *param = (void *)sig_alg.p;
485 *param_len = (unsigned int)sig_alg.len;
486 break;
487 case AUTH_PARAM_SIG:
488 /* Get the certificate signature */
489 *param = (void *)signature.p;
490 *param_len = (unsigned int)signature.len;
491 break;
492 default:
493 rc = IMG_PARSER_ERR_NOT_FOUND;
494 break;
495 }
496
497 return rc;
498}
499
500REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \
501 check_integrity, get_auth_param);