1 /* 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 /* 32 * X509 parser based on mbed TLS 33 * 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 46 /* mbed TLS headers */ 47 #include <mbedtls/asn1.h> 48 #include <mbedtls/oid.h> 49 #include <mbedtls/platform.h> 50 51 /* Maximum OID string length ("a.b.c.d.e.f ...") */ 52 #define MAX_OID_STR_LEN 64 53 54 #define LIB_NAME "mbed TLS X509v3" 55 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 */ 60 static mbedtls_asn1_buf tbs; 61 static mbedtls_asn1_buf v3_ext; 62 static mbedtls_asn1_buf pk; 63 static mbedtls_asn1_buf sig_alg; 64 static mbedtls_asn1_buf signature; 65 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 */ 73 static 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]; 81 mbedtls_asn1_buf extn_oid; 82 int is_critical; 83 84 assert(oid != NULL); 85 86 p = v3_ext.p; 87 end = v3_ext.p + v3_ext.len; 88 89 mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 90 MBEDTLS_ASN1_SEQUENCE); 91 92 while (p < end) { 93 memset(&extn_oid, 0x0, sizeof(extn_oid)); 94 is_critical = 0; /* DEFAULT FALSE */ 95 96 mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 97 MBEDTLS_ASN1_SEQUENCE); 98 end_ext_data = p + len; 99 100 /* Get extension ID */ 101 extn_oid.tag = *p; 102 mbedtls_asn1_get_tag(&p, end, &extn_oid.len, MBEDTLS_ASN1_OID); 103 extn_oid.p = p; 104 p += extn_oid.len; 105 106 /* Get optional critical */ 107 mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical); 108 109 /* Extension data */ 110 mbedtls_asn1_get_tag(&p, end_ext_data, &len, 111 MBEDTLS_ASN1_OCTET_STRING); 112 end_ext_octet = p + len; 113 114 /* Detect requested extension */ 115 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) { 119 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 */ 139 static 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; 144 mbedtls_asn1_buf sig_alg1, sig_alg2; 145 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 */ 156 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 157 MBEDTLS_ASN1_SEQUENCE); 158 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; 171 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 172 MBEDTLS_ASN1_SEQUENCE); 173 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 */ 182 ret = mbedtls_asn1_get_tag(&p, end, &len, 183 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 184 MBEDTLS_ASN1_CONSTRUCTED | 0); 185 if (ret != 0) { 186 return IMG_PARSER_ERR_FORMAT; 187 } 188 p += len; 189 190 /* 191 * CertificateSerialNumber ::= INTEGER 192 */ 193 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER); 194 if (ret != 0) { 195 return IMG_PARSER_ERR_FORMAT; 196 } 197 p += len; 198 199 /* 200 * signature AlgorithmIdentifier 201 */ 202 sig_alg1.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 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 */ 217 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 218 MBEDTLS_ASN1_SEQUENCE); 219 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 */ 230 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 231 MBEDTLS_ASN1_SEQUENCE); 232 if (ret != 0) { 233 return IMG_PARSER_ERR_FORMAT; 234 } 235 p += len; 236 237 /* 238 * subject Name 239 */ 240 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 241 MBEDTLS_ASN1_SEQUENCE); 242 if (ret != 0) { 243 return IMG_PARSER_ERR_FORMAT; 244 } 245 p += len; 246 247 /* 248 * SubjectPublicKeyInfo 249 */ 250 pk.p = p; 251 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 252 MBEDTLS_ASN1_SEQUENCE); 253 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 */ 262 ret = mbedtls_asn1_get_tag(&p, end, &len, 263 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 264 MBEDTLS_ASN1_CONSTRUCTED | 1); 265 if (ret != 0) { 266 if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 267 return IMG_PARSER_ERR_FORMAT; 268 } 269 } else { 270 p += len; 271 } 272 273 /* 274 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 275 */ 276 ret = mbedtls_asn1_get_tag(&p, end, &len, 277 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 278 MBEDTLS_ASN1_CONSTRUCTED | 2); 279 if (ret != 0) { 280 if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 281 return IMG_PARSER_ERR_FORMAT; 282 } 283 } else { 284 p += len; 285 } 286 287 /* 288 * extensions [3] EXPLICIT Extensions OPTIONAL 289 */ 290 ret = mbedtls_asn1_get_tag(&p, end, &len, 291 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 292 MBEDTLS_ASN1_CONSTRUCTED | 3); 293 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; 301 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 302 MBEDTLS_ASN1_SEQUENCE); 303 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) { 312 ret = mbedtls_asn1_get_tag(&p, end, &len, 313 MBEDTLS_ASN1_CONSTRUCTED | 314 MBEDTLS_ASN1_SEQUENCE); 315 if (ret != 0) { 316 return IMG_PARSER_ERR_FORMAT; 317 } 318 319 /* Get extension ID */ 320 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID); 321 if (ret != 0) { 322 return IMG_PARSER_ERR_FORMAT; 323 } 324 p += len; 325 326 /* Get optional critical */ 327 ret = mbedtls_asn1_get_bool(&p, end, &is_critical); 328 if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) { 329 return IMG_PARSER_ERR_FORMAT; 330 } 331 332 /* Data should be octet string type */ 333 ret = mbedtls_asn1_get_tag(&p, end, &len, 334 MBEDTLS_ASN1_OCTET_STRING); 335 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; 354 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 355 MBEDTLS_ASN1_SEQUENCE); 356 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; 378 ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_BIT_STRING); 379 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 396 static void init(void) 397 { 398 mbedtls_init(); 399 } 400 401 static 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 */ 409 static 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 456 REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \ 457 check_integrity, get_auth_param); 458