1 /* 2 * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 /* 8 * X509 parser based on mbed TLS 9 * 10 * This module implements functions to check the integrity of a X509v3 11 * certificate ASN.1 structure and extract authentication parameters from the 12 * extensions field, such as an image hash or a public key. 13 */ 14 15 #include <arch_helpers.h> 16 #include <assert.h> 17 #include <img_parser_mod.h> 18 #include <mbedtls_common.h> 19 #include <stddef.h> 20 #include <stdint.h> 21 #include <string.h> 22 #include <utils.h> 23 24 /* mbed TLS headers */ 25 #include <mbedtls/asn1.h> 26 #include <mbedtls/oid.h> 27 #include <mbedtls/platform.h> 28 29 /* Maximum OID string length ("a.b.c.d.e.f ...") */ 30 #define MAX_OID_STR_LEN 64 31 32 #define LIB_NAME "mbed TLS X509v3" 33 34 /* Temporary variables to speed up the authentication parameters search. These 35 * variables are assigned once during the integrity check and used any time an 36 * authentication parameter is requested, so we do not have to parse the image 37 * again */ 38 static mbedtls_asn1_buf tbs; 39 static mbedtls_asn1_buf v3_ext; 40 static mbedtls_asn1_buf pk; 41 static mbedtls_asn1_buf sig_alg; 42 static mbedtls_asn1_buf signature; 43 44 /* 45 * Clear all static temporary variables. 46 */ 47 static void clear_temp_vars(void) 48 { 49 #define ZERO_AND_CLEAN(x) \ 50 do { \ 51 zeromem(&x, sizeof(x)); \ 52 clean_dcache_range((uintptr_t)&x, sizeof(x)); \ 53 } while (0); 54 55 ZERO_AND_CLEAN(tbs) 56 ZERO_AND_CLEAN(v3_ext); 57 ZERO_AND_CLEAN(pk); 58 ZERO_AND_CLEAN(sig_alg); 59 ZERO_AND_CLEAN(signature); 60 61 #undef ZERO_AND_CLEAN 62 } 63 64 /* 65 * Get X509v3 extension 66 * 67 * Global variable 'v3_ext' must point to the extensions region 68 * in the certificate. No need to check for errors since the image has passed 69 * the integrity check. 70 */ 71 static int get_ext(const char *oid, void **ext, unsigned int *ext_len) 72 { 73 int oid_len; 74 size_t len; 75 unsigned char *end_ext_data, *end_ext_octet; 76 unsigned char *p; 77 const unsigned char *end; 78 char oid_str[MAX_OID_STR_LEN]; 79 mbedtls_asn1_buf extn_oid; 80 int is_critical; 81 82 assert(oid != NULL); 83 84 p = v3_ext.p; 85 end = v3_ext.p + v3_ext.len; 86 87 mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 88 MBEDTLS_ASN1_SEQUENCE); 89 90 while (p < end) { 91 zeromem(&extn_oid, sizeof(extn_oid)); 92 is_critical = 0; /* DEFAULT FALSE */ 93 94 mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 95 MBEDTLS_ASN1_SEQUENCE); 96 end_ext_data = p + len; 97 98 /* Get extension ID */ 99 extn_oid.tag = *p; 100 mbedtls_asn1_get_tag(&p, end, &extn_oid.len, MBEDTLS_ASN1_OID); 101 extn_oid.p = p; 102 p += extn_oid.len; 103 104 /* Get optional critical */ 105 mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical); 106 107 /* Extension data */ 108 mbedtls_asn1_get_tag(&p, end_ext_data, &len, 109 MBEDTLS_ASN1_OCTET_STRING); 110 end_ext_octet = p + len; 111 112 /* Detect requested extension */ 113 oid_len = mbedtls_oid_get_numeric_string(oid_str, 114 MAX_OID_STR_LEN, 115 &extn_oid); 116 if (oid_len == MBEDTLS_ERR_OID_BUF_TOO_SMALL) { 117 return IMG_PARSER_ERR; 118 } 119 if ((oid_len == strlen(oid_str)) && !strcmp(oid, oid_str)) { 120 *ext = (void *)p; 121 *ext_len = (unsigned int)len; 122 return IMG_PARSER_OK; 123 } 124 125 /* Next */ 126 p = end_ext_octet; 127 } 128 129 return IMG_PARSER_ERR_NOT_FOUND; 130 } 131 132 133 /* 134 * Check the integrity of the certificate ASN.1 structure. 135 * 136 * Extract the relevant data that will be used later during authentication. 137 * 138 * This function doesn't clear the static variables located on the top of this 139 * file in case of an error. It is only called from check_integrity(), which 140 * performs the cleanup if necessary. 141 */ 142 static int cert_parse(void *img, unsigned int img_len) 143 { 144 int ret, is_critical; 145 size_t len; 146 unsigned char *p, *end, *crt_end; 147 mbedtls_asn1_buf sig_alg1, sig_alg2; 148 149 p = (unsigned char *)img; 150 len = img_len; 151 end = p + len; 152 153 /* 154 * Certificate ::= SEQUENCE { 155 * tbsCertificate TBSCertificate, 156 * signatureAlgorithm AlgorithmIdentifier, 157 * signatureValue BIT STRING } 158 */ 159 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 160 MBEDTLS_ASN1_SEQUENCE); 161 if (ret != 0) { 162 return IMG_PARSER_ERR_FORMAT; 163 } 164 165 if (len > (size_t)(end - p)) { 166 return IMG_PARSER_ERR_FORMAT; 167 } 168 crt_end = p + len; 169 170 /* 171 * TBSCertificate ::= SEQUENCE { 172 */ 173 tbs.p = p; 174 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 175 MBEDTLS_ASN1_SEQUENCE); 176 if (ret != 0) { 177 return IMG_PARSER_ERR_FORMAT; 178 } 179 end = p + len; 180 tbs.len = end - tbs.p; 181 182 /* 183 * Version ::= INTEGER { v1(0), v2(1), v3(2) } 184 */ 185 ret = mbedtls_asn1_get_tag(&p, end, &len, 186 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 187 MBEDTLS_ASN1_CONSTRUCTED | 0); 188 if (ret != 0) { 189 return IMG_PARSER_ERR_FORMAT; 190 } 191 p += len; 192 193 /* 194 * CertificateSerialNumber ::= INTEGER 195 */ 196 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER); 197 if (ret != 0) { 198 return IMG_PARSER_ERR_FORMAT; 199 } 200 p += len; 201 202 /* 203 * signature AlgorithmIdentifier 204 */ 205 sig_alg1.p = p; 206 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 207 MBEDTLS_ASN1_SEQUENCE); 208 if (ret != 0) { 209 return IMG_PARSER_ERR_FORMAT; 210 } 211 if ((end - p) < 1) { 212 return IMG_PARSER_ERR_FORMAT; 213 } 214 sig_alg1.len = (p + len) - sig_alg1.p; 215 p += len; 216 217 /* 218 * issuer Name 219 */ 220 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 221 MBEDTLS_ASN1_SEQUENCE); 222 if (ret != 0) { 223 return IMG_PARSER_ERR_FORMAT; 224 } 225 p += len; 226 227 /* 228 * Validity ::= SEQUENCE { 229 * notBefore Time, 230 * notAfter Time } 231 * 232 */ 233 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 234 MBEDTLS_ASN1_SEQUENCE); 235 if (ret != 0) { 236 return IMG_PARSER_ERR_FORMAT; 237 } 238 p += len; 239 240 /* 241 * subject Name 242 */ 243 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 244 MBEDTLS_ASN1_SEQUENCE); 245 if (ret != 0) { 246 return IMG_PARSER_ERR_FORMAT; 247 } 248 p += len; 249 250 /* 251 * SubjectPublicKeyInfo 252 */ 253 pk.p = p; 254 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 255 MBEDTLS_ASN1_SEQUENCE); 256 if (ret != 0) { 257 return IMG_PARSER_ERR_FORMAT; 258 } 259 pk.len = (p + len) - pk.p; 260 p += len; 261 262 /* 263 * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 264 */ 265 ret = mbedtls_asn1_get_tag(&p, end, &len, 266 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 267 MBEDTLS_ASN1_CONSTRUCTED | 1); 268 if (ret != 0) { 269 if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 270 return IMG_PARSER_ERR_FORMAT; 271 } 272 } else { 273 p += len; 274 } 275 276 /* 277 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 278 */ 279 ret = mbedtls_asn1_get_tag(&p, end, &len, 280 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 281 MBEDTLS_ASN1_CONSTRUCTED | 2); 282 if (ret != 0) { 283 if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 284 return IMG_PARSER_ERR_FORMAT; 285 } 286 } else { 287 p += len; 288 } 289 290 /* 291 * extensions [3] EXPLICIT Extensions OPTIONAL 292 */ 293 ret = mbedtls_asn1_get_tag(&p, end, &len, 294 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 295 MBEDTLS_ASN1_CONSTRUCTED | 3); 296 if (ret != 0) { 297 return IMG_PARSER_ERR_FORMAT; 298 } 299 300 /* 301 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension 302 */ 303 v3_ext.p = p; 304 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 305 MBEDTLS_ASN1_SEQUENCE); 306 if (ret != 0) { 307 return IMG_PARSER_ERR_FORMAT; 308 } 309 v3_ext.len = (p + len) - v3_ext.p; 310 311 /* 312 * Check extensions integrity 313 */ 314 while (p < end) { 315 ret = mbedtls_asn1_get_tag(&p, end, &len, 316 MBEDTLS_ASN1_CONSTRUCTED | 317 MBEDTLS_ASN1_SEQUENCE); 318 if (ret != 0) { 319 return IMG_PARSER_ERR_FORMAT; 320 } 321 322 /* Get extension ID */ 323 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID); 324 if (ret != 0) { 325 return IMG_PARSER_ERR_FORMAT; 326 } 327 p += len; 328 329 /* Get optional critical */ 330 ret = mbedtls_asn1_get_bool(&p, end, &is_critical); 331 if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) { 332 return IMG_PARSER_ERR_FORMAT; 333 } 334 335 /* Data should be octet string type */ 336 ret = mbedtls_asn1_get_tag(&p, end, &len, 337 MBEDTLS_ASN1_OCTET_STRING); 338 if (ret != 0) { 339 return IMG_PARSER_ERR_FORMAT; 340 } 341 p += len; 342 } 343 344 if (p != end) { 345 return IMG_PARSER_ERR_FORMAT; 346 } 347 348 end = crt_end; 349 350 /* 351 * } 352 * -- end of TBSCertificate 353 * 354 * signatureAlgorithm AlgorithmIdentifier 355 */ 356 sig_alg2.p = p; 357 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 358 MBEDTLS_ASN1_SEQUENCE); 359 if (ret != 0) { 360 return IMG_PARSER_ERR_FORMAT; 361 } 362 if ((end - p) < 1) { 363 return IMG_PARSER_ERR_FORMAT; 364 } 365 sig_alg2.len = (p + len) - sig_alg2.p; 366 p += len; 367 368 /* Compare both signature algorithms */ 369 if (sig_alg1.len != sig_alg2.len) { 370 return IMG_PARSER_ERR_FORMAT; 371 } 372 if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) { 373 return IMG_PARSER_ERR_FORMAT; 374 } 375 memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg)); 376 377 /* 378 * signatureValue BIT STRING 379 */ 380 signature.p = p; 381 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_BIT_STRING); 382 if (ret != 0) { 383 return IMG_PARSER_ERR_FORMAT; 384 } 385 signature.len = (p + len) - signature.p; 386 p += len; 387 388 /* Check certificate length */ 389 if (p != end) { 390 return IMG_PARSER_ERR_FORMAT; 391 } 392 393 return IMG_PARSER_OK; 394 } 395 396 397 /* Exported functions */ 398 399 static void init(void) 400 { 401 mbedtls_init(); 402 } 403 404 /* 405 * Wrapper for cert_parse() that clears the static variables used by it in case 406 * of an error. 407 */ 408 static int check_integrity(void *img, unsigned int img_len) 409 { 410 int rc = cert_parse(img, img_len); 411 412 if (rc != IMG_PARSER_OK) 413 clear_temp_vars(); 414 415 return rc; 416 } 417 418 /* 419 * Extract an authentication parameter from an X509v3 certificate 420 * 421 * This function returns a pointer to the extracted data and its length. 422 * Depending on the type of parameter, a pointer to the data stored in the 423 * certificate may be returned (i.e. an octet string containing a hash). Other 424 * data may need to be copied and formatted (i.e. integers). In the later case, 425 * a buffer of the correct type needs to be statically allocated, filled and 426 * returned. 427 */ 428 static int get_auth_param(const auth_param_type_desc_t *type_desc, 429 void *img, unsigned int img_len, 430 void **param, unsigned int *param_len) 431 { 432 int rc = IMG_PARSER_OK; 433 434 /* We do not use img because the check_integrity function has already 435 * extracted the relevant data (v3_ext, pk, sig_alg, etc) */ 436 437 switch (type_desc->type) { 438 case AUTH_PARAM_RAW_DATA: 439 /* Data to be signed */ 440 *param = (void *)tbs.p; 441 *param_len = (unsigned int)tbs.len; 442 break; 443 case AUTH_PARAM_HASH: 444 case AUTH_PARAM_NV_CTR: 445 /* All these parameters are included as X509v3 extensions */ 446 rc = get_ext(type_desc->cookie, param, param_len); 447 break; 448 case AUTH_PARAM_PUB_KEY: 449 if (type_desc->cookie != 0) { 450 /* Get public key from extension */ 451 rc = get_ext(type_desc->cookie, param, param_len); 452 } else { 453 /* Get the subject public key */ 454 *param = (void *)pk.p; 455 *param_len = (unsigned int)pk.len; 456 } 457 break; 458 case AUTH_PARAM_SIG_ALG: 459 /* Get the certificate signature algorithm */ 460 *param = (void *)sig_alg.p; 461 *param_len = (unsigned int)sig_alg.len; 462 break; 463 case AUTH_PARAM_SIG: 464 /* Get the certificate signature */ 465 *param = (void *)signature.p; 466 *param_len = (unsigned int)signature.len; 467 break; 468 default: 469 rc = IMG_PARSER_ERR_NOT_FOUND; 470 break; 471 } 472 473 return rc; 474 } 475 476 REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \ 477 check_integrity, get_auth_param); 478