blob: 52e697193c9a16d0157328a7e91a38c9dfbc8ada [file] [log] [blame]
Juan Castilloa57a4d52015-04-02 15:44:20 +01001/*
2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
3 *
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
39#include <assert.h>
40#include <img_parser_mod.h>
41#include <mbedtls_common.h>
42#include <stddef.h>
43#include <stdint.h>
44#include <string.h>
45
Juan Castillobae6b2a2015-11-05 09:24:53 +000046/* mbed TLS headers */
47#include <mbedtls/asn1.h>
48#include <mbedtls/oid.h>
49#include <mbedtls/platform.h>
Juan Castilloa57a4d52015-04-02 15:44:20 +010050
51/* Maximum OID string length ("a.b.c.d.e.f ...") */
52#define MAX_OID_STR_LEN 64
53
Juan Castillobae6b2a2015-11-05 09:24:53 +000054#define LIB_NAME "mbed TLS X509v3"
Juan Castilloa57a4d52015-04-02 15:44:20 +010055
56/* Temporary variables to speed up the authentication parameters search. These
57 * variables are assigned once during the integrity check and used any time an
58 * authentication parameter is requested, so we do not have to parse the image
59 * again */
Juan Castillobae6b2a2015-11-05 09:24:53 +000060static mbedtls_asn1_buf tbs;
61static mbedtls_asn1_buf v3_ext;
62static mbedtls_asn1_buf pk;
63static mbedtls_asn1_buf sig_alg;
64static mbedtls_asn1_buf signature;
Juan Castilloa57a4d52015-04-02 15:44:20 +010065
66/*
67 * Get X509v3 extension
68 *
69 * Global variable 'v3_ext' must point to the extensions region
70 * in the certificate. No need to check for errors since the image has passed
71 * the integrity check.
72 */
73static int get_ext(const char *oid, void **ext, unsigned int *ext_len)
74{
75 int oid_len;
76 size_t len;
77 unsigned char *end_ext_data, *end_ext_octet;
78 unsigned char *p;
79 const unsigned char *end;
80 char oid_str[MAX_OID_STR_LEN];
Juan Castillobae6b2a2015-11-05 09:24:53 +000081 mbedtls_asn1_buf extn_oid;
Juan Castilloa57a4d52015-04-02 15:44:20 +010082 int is_critical;
83
84 assert(oid != NULL);
85
86 p = v3_ext.p;
87 end = v3_ext.p + v3_ext.len;
88
Juan Castillobae6b2a2015-11-05 09:24:53 +000089 mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
90 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +010091
92 while (p < end) {
93 memset(&extn_oid, 0x0, sizeof(extn_oid));
94 is_critical = 0; /* DEFAULT FALSE */
95
Juan Castillobae6b2a2015-11-05 09:24:53 +000096 mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
97 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +010098 end_ext_data = p + len;
99
100 /* Get extension ID */
101 extn_oid.tag = *p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000102 mbedtls_asn1_get_tag(&p, end, &extn_oid.len, MBEDTLS_ASN1_OID);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100103 extn_oid.p = p;
104 p += extn_oid.len;
105
106 /* Get optional critical */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000107 mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100108
109 /* Extension data */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000110 mbedtls_asn1_get_tag(&p, end_ext_data, &len,
111 MBEDTLS_ASN1_OCTET_STRING);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100112 end_ext_octet = p + len;
113
114 /* Detect requested extension */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000115 oid_len = mbedtls_oid_get_numeric_string(oid_str,
116 MAX_OID_STR_LEN,
117 &extn_oid);
118 if (oid_len == MBEDTLS_ERR_OID_BUF_TOO_SMALL) {
Juan Castilloa57a4d52015-04-02 15:44:20 +0100119 return IMG_PARSER_ERR;
120 }
121 if ((oid_len == strlen(oid_str)) && !strcmp(oid, oid_str)) {
122 *ext = (void *)p;
123 *ext_len = (unsigned int)len;
124 return IMG_PARSER_OK;
125 }
126
127 /* Next */
128 p = end_ext_octet;
129 }
130
131 return IMG_PARSER_ERR_NOT_FOUND;
132}
133
134
135/*
136 * Check the integrity of the certificate ASN.1 structure.
137 * Extract the relevant data that will be used later during authentication.
138 */
139static int cert_parse(void *img, unsigned int img_len)
140{
141 int ret, is_critical;
142 size_t len;
143 unsigned char *p, *end, *crt_end;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000144 mbedtls_asn1_buf sig_alg1, sig_alg2;
Juan Castilloa57a4d52015-04-02 15:44:20 +0100145
146 p = (unsigned char *)img;
147 len = img_len;
148 end = p + len;
149
150 /*
151 * Certificate ::= SEQUENCE {
152 * tbsCertificate TBSCertificate,
153 * signatureAlgorithm AlgorithmIdentifier,
154 * signatureValue BIT STRING }
155 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000156 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
157 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100158 if (ret != 0) {
159 return IMG_PARSER_ERR_FORMAT;
160 }
161
162 if (len > (size_t)(end - p)) {
163 return IMG_PARSER_ERR_FORMAT;
164 }
165 crt_end = p + len;
166
167 /*
168 * TBSCertificate ::= SEQUENCE {
169 */
170 tbs.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000171 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
172 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100173 if (ret != 0) {
174 return IMG_PARSER_ERR_FORMAT;
175 }
176 end = p + len;
177 tbs.len = end - tbs.p;
178
179 /*
180 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
181 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000182 ret = mbedtls_asn1_get_tag(&p, end, &len,
183 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
184 MBEDTLS_ASN1_CONSTRUCTED | 0);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100185 if (ret != 0) {
186 return IMG_PARSER_ERR_FORMAT;
187 }
188 p += len;
189
190 /*
191 * CertificateSerialNumber ::= INTEGER
192 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000193 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100194 if (ret != 0) {
195 return IMG_PARSER_ERR_FORMAT;
196 }
197 p += len;
198
199 /*
200 * signature AlgorithmIdentifier
201 */
202 sig_alg1.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000203 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
204 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100205 if (ret != 0) {
206 return IMG_PARSER_ERR_FORMAT;
207 }
208 if ((end - p) < 1) {
209 return IMG_PARSER_ERR_FORMAT;
210 }
211 sig_alg1.len = (p + len) - sig_alg1.p;
212 p += len;
213
214 /*
215 * issuer Name
216 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000217 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
218 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100219 if (ret != 0) {
220 return IMG_PARSER_ERR_FORMAT;
221 }
222 p += len;
223
224 /*
225 * Validity ::= SEQUENCE {
226 * notBefore Time,
227 * notAfter Time }
228 *
229 */
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 p += len;
236
237 /*
238 * subject Name
239 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000240 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
241 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100242 if (ret != 0) {
243 return IMG_PARSER_ERR_FORMAT;
244 }
245 p += len;
246
247 /*
248 * SubjectPublicKeyInfo
249 */
250 pk.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000251 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
252 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100253 if (ret != 0) {
254 return IMG_PARSER_ERR_FORMAT;
255 }
256 pk.len = (p + len) - pk.p;
257 p += len;
258
259 /*
260 * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
261 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000262 ret = mbedtls_asn1_get_tag(&p, end, &len,
263 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
264 MBEDTLS_ASN1_CONSTRUCTED | 1);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100265 if (ret != 0) {
Juan Castillobae6b2a2015-11-05 09:24:53 +0000266 if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
Juan Castilloa57a4d52015-04-02 15:44:20 +0100267 return IMG_PARSER_ERR_FORMAT;
268 }
269 } else {
270 p += len;
271 }
272
273 /*
274 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
275 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000276 ret = mbedtls_asn1_get_tag(&p, end, &len,
277 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
278 MBEDTLS_ASN1_CONSTRUCTED | 2);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100279 if (ret != 0) {
Juan Castillobae6b2a2015-11-05 09:24:53 +0000280 if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
Juan Castilloa57a4d52015-04-02 15:44:20 +0100281 return IMG_PARSER_ERR_FORMAT;
282 }
283 } else {
284 p += len;
285 }
286
287 /*
288 * extensions [3] EXPLICIT Extensions OPTIONAL
289 */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000290 ret = mbedtls_asn1_get_tag(&p, end, &len,
291 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
292 MBEDTLS_ASN1_CONSTRUCTED | 3);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100293 if (ret != 0) {
294 return IMG_PARSER_ERR_FORMAT;
295 }
296
297 /*
298 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
299 */
300 v3_ext.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000301 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
302 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100303 if (ret != 0) {
304 return IMG_PARSER_ERR_FORMAT;
305 }
306 v3_ext.len = (p + len) - v3_ext.p;
307
308 /*
309 * Check extensions integrity
310 */
311 while (p < end) {
Juan Castillobae6b2a2015-11-05 09:24:53 +0000312 ret = mbedtls_asn1_get_tag(&p, end, &len,
313 MBEDTLS_ASN1_CONSTRUCTED |
314 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100315 if (ret != 0) {
316 return IMG_PARSER_ERR_FORMAT;
317 }
318
319 /* Get extension ID */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000320 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100321 if (ret != 0) {
322 return IMG_PARSER_ERR_FORMAT;
323 }
324 p += len;
325
326 /* Get optional critical */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000327 ret = mbedtls_asn1_get_bool(&p, end, &is_critical);
328 if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
Juan Castilloa57a4d52015-04-02 15:44:20 +0100329 return IMG_PARSER_ERR_FORMAT;
330 }
331
332 /* Data should be octet string type */
Juan Castillobae6b2a2015-11-05 09:24:53 +0000333 ret = mbedtls_asn1_get_tag(&p, end, &len,
334 MBEDTLS_ASN1_OCTET_STRING);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100335 if (ret != 0) {
336 return IMG_PARSER_ERR_FORMAT;
337 }
338 p += len;
339 }
340
341 if (p != end) {
342 return IMG_PARSER_ERR_FORMAT;
343 }
344
345 end = crt_end;
346
347 /*
348 * }
349 * -- end of TBSCertificate
350 *
351 * signatureAlgorithm AlgorithmIdentifier
352 */
353 sig_alg2.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000354 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
355 MBEDTLS_ASN1_SEQUENCE);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100356 if (ret != 0) {
357 return IMG_PARSER_ERR_FORMAT;
358 }
359 if ((end - p) < 1) {
360 return IMG_PARSER_ERR_FORMAT;
361 }
362 sig_alg2.len = (p + len) - sig_alg2.p;
363 p += len;
364
365 /* Compare both signature algorithms */
366 if (sig_alg1.len != sig_alg2.len) {
367 return IMG_PARSER_ERR_FORMAT;
368 }
369 if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) {
370 return IMG_PARSER_ERR_FORMAT;
371 }
372 memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg));
373
374 /*
375 * signatureValue BIT STRING
376 */
377 signature.p = p;
Juan Castillobae6b2a2015-11-05 09:24:53 +0000378 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_BIT_STRING);
Juan Castilloa57a4d52015-04-02 15:44:20 +0100379 if (ret != 0) {
380 return IMG_PARSER_ERR_FORMAT;
381 }
382 signature.len = (p + len) - signature.p;
383 p += len;
384
385 /* Check certificate length */
386 if (p != end) {
387 return IMG_PARSER_ERR_FORMAT;
388 }
389
390 return IMG_PARSER_OK;
391}
392
393
394/* Exported functions */
395
396static void init(void)
397{
398 mbedtls_init();
399}
400
401static int check_integrity(void *img, unsigned int img_len)
402{
403 return cert_parse(img, img_len);
404}
405
406/*
407 * Extract an authentication parameter from an X509v3 certificate
408 */
409static int get_auth_param(const auth_param_type_desc_t *type_desc,
410 void *img, unsigned int img_len,
411 void **param, unsigned int *param_len)
412{
413 int rc = IMG_PARSER_OK;
414
415 /* We do not use img because the check_integrity function has already
416 * extracted the relevant data (v3_ext, pk, sig_alg, etc) */
417
418 switch (type_desc->type) {
419 case AUTH_PARAM_RAW_DATA:
420 /* Data to be signed */
421 *param = (void *)tbs.p;
422 *param_len = (unsigned int)tbs.len;
423 break;
424 case AUTH_PARAM_HASH:
425 /* All these parameters are included as X509v3 extensions */
426 rc = get_ext(type_desc->cookie, param, param_len);
427 break;
428 case AUTH_PARAM_PUB_KEY:
429 if (type_desc->cookie != 0) {
430 /* Get public key from extension */
431 rc = get_ext(type_desc->cookie, param, param_len);
432 } else {
433 /* Get the subject public key */
434 *param = (void *)pk.p;
435 *param_len = (unsigned int)pk.len;
436 }
437 break;
438 case AUTH_PARAM_SIG_ALG:
439 /* Get the certificate signature algorithm */
440 *param = (void *)sig_alg.p;
441 *param_len = (unsigned int)sig_alg.len;
442 break;
443 case AUTH_PARAM_SIG:
444 /* Get the certificate signature */
445 *param = (void *)signature.p;
446 *param_len = (unsigned int)signature.len;
447 break;
448 default:
449 rc = IMG_PARSER_ERR_NOT_FOUND;
450 break;
451 }
452
453 return rc;
454}
455
456REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \
457 check_integrity, get_auth_param);