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 <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 mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 89 MBEDTLS_ASN1_SEQUENCE); 90 91 while (p < end) { 92 zeromem(&extn_oid, sizeof(extn_oid)); 93 is_critical = 0; /* DEFAULT FALSE */ 94 95 mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 96 MBEDTLS_ASN1_SEQUENCE); 97 end_ext_data = p + len; 98 99 /* Get extension ID */ 100 extn_oid.tag = *p; 101 mbedtls_asn1_get_tag(&p, end, &extn_oid.len, MBEDTLS_ASN1_OID); 102 extn_oid.p = p; 103 p += extn_oid.len; 104 105 /* Get optional critical */ 106 mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical); 107 108 /* Extension data */ 109 mbedtls_asn1_get_tag(&p, end_ext_data, &len, 110 MBEDTLS_ASN1_OCTET_STRING); 111 end_ext_octet = p + len; 112 113 /* Detect requested extension */ 114 oid_len = mbedtls_oid_get_numeric_string(oid_str, 115 MAX_OID_STR_LEN, 116 &extn_oid); 117 if (oid_len == MBEDTLS_ERR_OID_BUF_TOO_SMALL) { 118 return IMG_PARSER_ERR; 119 } 120 if ((oid_len == strlen(oid_str)) && !strcmp(oid, oid_str)) { 121 *ext = (void *)p; 122 *ext_len = (unsigned int)len; 123 return IMG_PARSER_OK; 124 } 125 126 /* Next */ 127 p = end_ext_octet; 128 } 129 130 return IMG_PARSER_ERR_NOT_FOUND; 131 } 132 133 134 /* 135 * Check the integrity of the certificate ASN.1 structure. 136 * 137 * Extract the relevant data that will be used later during authentication. 138 * 139 * This function doesn't clear the static variables located on the top of this 140 * file in case of an error. It is only called from check_integrity(), which 141 * performs the cleanup if necessary. 142 */ 143 static int cert_parse(void *img, unsigned int img_len) 144 { 145 int ret, is_critical; 146 size_t len; 147 unsigned char *p, *end, *crt_end; 148 mbedtls_asn1_buf sig_alg1, sig_alg2; 149 150 p = (unsigned char *)img; 151 len = img_len; 152 end = p + len; 153 154 /* 155 * Certificate ::= SEQUENCE { 156 * tbsCertificate TBSCertificate, 157 * signatureAlgorithm AlgorithmIdentifier, 158 * signatureValue BIT STRING } 159 */ 160 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 161 MBEDTLS_ASN1_SEQUENCE); 162 if (ret != 0) { 163 return IMG_PARSER_ERR_FORMAT; 164 } 165 166 if (len > (size_t)(end - p)) { 167 return IMG_PARSER_ERR_FORMAT; 168 } 169 crt_end = p + len; 170 171 /* 172 * TBSCertificate ::= SEQUENCE { 173 */ 174 tbs.p = p; 175 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 176 MBEDTLS_ASN1_SEQUENCE); 177 if (ret != 0) { 178 return IMG_PARSER_ERR_FORMAT; 179 } 180 end = p + len; 181 tbs.len = end - tbs.p; 182 183 /* 184 * Version ::= INTEGER { v1(0), v2(1), v3(2) } 185 */ 186 ret = mbedtls_asn1_get_tag(&p, end, &len, 187 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 188 MBEDTLS_ASN1_CONSTRUCTED | 0); 189 if (ret != 0) { 190 return IMG_PARSER_ERR_FORMAT; 191 } 192 p += len; 193 194 /* 195 * CertificateSerialNumber ::= INTEGER 196 */ 197 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER); 198 if (ret != 0) { 199 return IMG_PARSER_ERR_FORMAT; 200 } 201 p += len; 202 203 /* 204 * signature AlgorithmIdentifier 205 */ 206 sig_alg1.p = p; 207 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 208 MBEDTLS_ASN1_SEQUENCE); 209 if (ret != 0) { 210 return IMG_PARSER_ERR_FORMAT; 211 } 212 if ((end - p) < 1) { 213 return IMG_PARSER_ERR_FORMAT; 214 } 215 sig_alg1.len = (p + len) - sig_alg1.p; 216 p += len; 217 218 /* 219 * issuer Name 220 */ 221 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 222 MBEDTLS_ASN1_SEQUENCE); 223 if (ret != 0) { 224 return IMG_PARSER_ERR_FORMAT; 225 } 226 p += len; 227 228 /* 229 * Validity ::= SEQUENCE { 230 * notBefore Time, 231 * notAfter Time } 232 * 233 */ 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 p += len; 240 241 /* 242 * subject Name 243 */ 244 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 245 MBEDTLS_ASN1_SEQUENCE); 246 if (ret != 0) { 247 return IMG_PARSER_ERR_FORMAT; 248 } 249 p += len; 250 251 /* 252 * SubjectPublicKeyInfo 253 */ 254 pk.p = p; 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 pk.len = (p + len) - pk.p; 261 p += len; 262 263 /* 264 * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 265 */ 266 ret = mbedtls_asn1_get_tag(&p, end, &len, 267 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 268 MBEDTLS_ASN1_CONSTRUCTED | 1); 269 if (ret != 0) { 270 if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 271 return IMG_PARSER_ERR_FORMAT; 272 } 273 } else { 274 p += len; 275 } 276 277 /* 278 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 279 */ 280 ret = mbedtls_asn1_get_tag(&p, end, &len, 281 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 282 MBEDTLS_ASN1_CONSTRUCTED | 2); 283 if (ret != 0) { 284 if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 285 return IMG_PARSER_ERR_FORMAT; 286 } 287 } else { 288 p += len; 289 } 290 291 /* 292 * extensions [3] EXPLICIT Extensions OPTIONAL 293 */ 294 ret = mbedtls_asn1_get_tag(&p, end, &len, 295 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 296 MBEDTLS_ASN1_CONSTRUCTED | 3); 297 if (ret != 0) { 298 return IMG_PARSER_ERR_FORMAT; 299 } 300 301 /* 302 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension 303 */ 304 v3_ext.p = p; 305 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 306 MBEDTLS_ASN1_SEQUENCE); 307 if (ret != 0) { 308 return IMG_PARSER_ERR_FORMAT; 309 } 310 v3_ext.len = (p + len) - v3_ext.p; 311 312 /* 313 * Check extensions integrity 314 */ 315 while (p < end) { 316 ret = mbedtls_asn1_get_tag(&p, end, &len, 317 MBEDTLS_ASN1_CONSTRUCTED | 318 MBEDTLS_ASN1_SEQUENCE); 319 if (ret != 0) { 320 return IMG_PARSER_ERR_FORMAT; 321 } 322 323 /* Get extension ID */ 324 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID); 325 if (ret != 0) { 326 return IMG_PARSER_ERR_FORMAT; 327 } 328 p += len; 329 330 /* Get optional critical */ 331 ret = mbedtls_asn1_get_bool(&p, end, &is_critical); 332 if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) { 333 return IMG_PARSER_ERR_FORMAT; 334 } 335 336 /* Data should be octet string type */ 337 ret = mbedtls_asn1_get_tag(&p, end, &len, 338 MBEDTLS_ASN1_OCTET_STRING); 339 if (ret != 0) { 340 return IMG_PARSER_ERR_FORMAT; 341 } 342 p += len; 343 } 344 345 if (p != end) { 346 return IMG_PARSER_ERR_FORMAT; 347 } 348 349 end = crt_end; 350 351 /* 352 * } 353 * -- end of TBSCertificate 354 * 355 * signatureAlgorithm AlgorithmIdentifier 356 */ 357 sig_alg2.p = p; 358 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 359 MBEDTLS_ASN1_SEQUENCE); 360 if (ret != 0) { 361 return IMG_PARSER_ERR_FORMAT; 362 } 363 if ((end - p) < 1) { 364 return IMG_PARSER_ERR_FORMAT; 365 } 366 sig_alg2.len = (p + len) - sig_alg2.p; 367 p += len; 368 369 /* Compare both signature algorithms */ 370 if (sig_alg1.len != sig_alg2.len) { 371 return IMG_PARSER_ERR_FORMAT; 372 } 373 if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) { 374 return IMG_PARSER_ERR_FORMAT; 375 } 376 memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg)); 377 378 /* 379 * signatureValue BIT STRING 380 */ 381 signature.p = p; 382 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_BIT_STRING); 383 if (ret != 0) { 384 return IMG_PARSER_ERR_FORMAT; 385 } 386 signature.len = (p + len) - signature.p; 387 p += len; 388 389 /* Check certificate length */ 390 if (p != end) { 391 return IMG_PARSER_ERR_FORMAT; 392 } 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 != 0) { 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