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