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