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 PolarSSL 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 /* mbedTLS headers */ 47 #include <polarssl/asn1.h> 48 #include <polarssl/oid.h> 49 #include <polarssl/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 "mbedTLS 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 asn1_buf tbs; 61 static asn1_buf v3_ext; 62 static asn1_buf pk; 63 static asn1_buf sig_alg; 64 static 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 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 asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 90 91 while (p < end) { 92 memset(&extn_oid, 0x0, sizeof(extn_oid)); 93 is_critical = 0; /* DEFAULT FALSE */ 94 95 asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 96 end_ext_data = p + len; 97 98 /* Get extension ID */ 99 extn_oid.tag = *p; 100 asn1_get_tag(&p, end, &extn_oid.len, ASN1_OID); 101 extn_oid.p = p; 102 p += extn_oid.len; 103 104 /* Get optional critical */ 105 asn1_get_bool(&p, end_ext_data, &is_critical); 106 107 /* Extension data */ 108 asn1_get_tag(&p, end_ext_data, &len, ASN1_OCTET_STRING); 109 end_ext_octet = p + len; 110 111 /* Detect requested extension */ 112 oid_len = oid_get_numeric_string(oid_str, 113 MAX_OID_STR_LEN, &extn_oid); 114 if (oid_len == POLARSSL_ERR_OID_BUF_TOO_SMALL) { 115 return IMG_PARSER_ERR; 116 } 117 if ((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 * Extract the relevant data that will be used later during authentication. 134 */ 135 static int cert_parse(void *img, unsigned int img_len) 136 { 137 int ret, is_critical; 138 size_t len; 139 unsigned char *p, *end, *crt_end; 140 asn1_buf sig_alg1, sig_alg2; 141 142 p = (unsigned char *)img; 143 len = img_len; 144 end = p + len; 145 146 /* 147 * Certificate ::= SEQUENCE { 148 * tbsCertificate TBSCertificate, 149 * signatureAlgorithm AlgorithmIdentifier, 150 * signatureValue BIT STRING } 151 */ 152 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 153 if (ret != 0) { 154 return IMG_PARSER_ERR_FORMAT; 155 } 156 157 if (len > (size_t)(end - p)) { 158 return IMG_PARSER_ERR_FORMAT; 159 } 160 crt_end = p + len; 161 162 /* 163 * TBSCertificate ::= SEQUENCE { 164 */ 165 tbs.p = p; 166 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 167 if (ret != 0) { 168 return IMG_PARSER_ERR_FORMAT; 169 } 170 end = p + len; 171 tbs.len = end - tbs.p; 172 173 /* 174 * Version ::= INTEGER { v1(0), v2(1), v3(2) } 175 */ 176 ret = asn1_get_tag(&p, end, &len, 177 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0); 178 if (ret != 0) { 179 return IMG_PARSER_ERR_FORMAT; 180 } 181 p += len; 182 183 /* 184 * CertificateSerialNumber ::= INTEGER 185 */ 186 ret = asn1_get_tag(&p, end, &len, ASN1_INTEGER); 187 if (ret != 0) { 188 return IMG_PARSER_ERR_FORMAT; 189 } 190 p += len; 191 192 /* 193 * signature AlgorithmIdentifier 194 */ 195 sig_alg1.p = p; 196 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 197 if (ret != 0) { 198 return IMG_PARSER_ERR_FORMAT; 199 } 200 if ((end - p) < 1) { 201 return IMG_PARSER_ERR_FORMAT; 202 } 203 sig_alg1.len = (p + len) - sig_alg1.p; 204 p += len; 205 206 /* 207 * issuer Name 208 */ 209 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 210 if (ret != 0) { 211 return IMG_PARSER_ERR_FORMAT; 212 } 213 p += len; 214 215 /* 216 * Validity ::= SEQUENCE { 217 * notBefore Time, 218 * notAfter Time } 219 * 220 */ 221 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 222 if (ret != 0) { 223 return IMG_PARSER_ERR_FORMAT; 224 } 225 p += len; 226 227 /* 228 * subject Name 229 */ 230 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 231 if (ret != 0) { 232 return IMG_PARSER_ERR_FORMAT; 233 } 234 p += len; 235 236 /* 237 * SubjectPublicKeyInfo 238 */ 239 pk.p = p; 240 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 241 if (ret != 0) { 242 return IMG_PARSER_ERR_FORMAT; 243 } 244 pk.len = (p + len) - pk.p; 245 p += len; 246 247 /* 248 * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 249 */ 250 ret = asn1_get_tag(&p, end, &len, 251 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1); 252 if (ret != 0) { 253 if (ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG) { 254 return IMG_PARSER_ERR_FORMAT; 255 } 256 } else { 257 p += len; 258 } 259 260 /* 261 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 262 */ 263 ret = asn1_get_tag(&p, end, &len, 264 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 2); 265 if (ret != 0) { 266 if (ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG) { 267 return IMG_PARSER_ERR_FORMAT; 268 } 269 } else { 270 p += len; 271 } 272 273 /* 274 * extensions [3] EXPLICIT Extensions OPTIONAL 275 */ 276 ret = asn1_get_tag(&p, end, &len, 277 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3); 278 if (ret != 0) { 279 return IMG_PARSER_ERR_FORMAT; 280 } 281 282 /* 283 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension 284 */ 285 v3_ext.p = p; 286 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 287 if (ret != 0) { 288 return IMG_PARSER_ERR_FORMAT; 289 } 290 v3_ext.len = (p + len) - v3_ext.p; 291 292 /* 293 * Check extensions integrity 294 */ 295 while (p < end) { 296 ret = asn1_get_tag(&p, end, &len, 297 ASN1_CONSTRUCTED | ASN1_SEQUENCE); 298 if (ret != 0) { 299 return IMG_PARSER_ERR_FORMAT; 300 } 301 302 /* Get extension ID */ 303 ret = asn1_get_tag(&p, end, &len, ASN1_OID); 304 if (ret != 0) { 305 return IMG_PARSER_ERR_FORMAT; 306 } 307 p += len; 308 309 /* Get optional critical */ 310 ret = asn1_get_bool(&p, end, &is_critical); 311 if ((ret != 0) && (ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG)) { 312 return IMG_PARSER_ERR_FORMAT; 313 } 314 315 /* Data should be octet string type */ 316 ret = asn1_get_tag(&p, end, &len, ASN1_OCTET_STRING); 317 if (ret != 0) { 318 return IMG_PARSER_ERR_FORMAT; 319 } 320 p += len; 321 } 322 323 if (p != end) { 324 return IMG_PARSER_ERR_FORMAT; 325 } 326 327 end = crt_end; 328 329 /* 330 * } 331 * -- end of TBSCertificate 332 * 333 * signatureAlgorithm AlgorithmIdentifier 334 */ 335 sig_alg2.p = p; 336 ret = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 337 if (ret != 0) { 338 return IMG_PARSER_ERR_FORMAT; 339 } 340 if ((end - p) < 1) { 341 return IMG_PARSER_ERR_FORMAT; 342 } 343 sig_alg2.len = (p + len) - sig_alg2.p; 344 p += len; 345 346 /* Compare both signature algorithms */ 347 if (sig_alg1.len != sig_alg2.len) { 348 return IMG_PARSER_ERR_FORMAT; 349 } 350 if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) { 351 return IMG_PARSER_ERR_FORMAT; 352 } 353 memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg)); 354 355 /* 356 * signatureValue BIT STRING 357 */ 358 signature.p = p; 359 ret = asn1_get_tag(&p, end, &len, ASN1_BIT_STRING); 360 if (ret != 0) { 361 return IMG_PARSER_ERR_FORMAT; 362 } 363 signature.len = (p + len) - signature.p; 364 p += len; 365 366 /* Check certificate length */ 367 if (p != end) { 368 return IMG_PARSER_ERR_FORMAT; 369 } 370 371 return IMG_PARSER_OK; 372 } 373 374 375 /* Exported functions */ 376 377 static void init(void) 378 { 379 mbedtls_init(); 380 } 381 382 static int check_integrity(void *img, unsigned int img_len) 383 { 384 return cert_parse(img, img_len); 385 } 386 387 /* 388 * Extract an authentication parameter from an X509v3 certificate 389 */ 390 static int get_auth_param(const auth_param_type_desc_t *type_desc, 391 void *img, unsigned int img_len, 392 void **param, unsigned int *param_len) 393 { 394 int rc = IMG_PARSER_OK; 395 396 /* We do not use img because the check_integrity function has already 397 * extracted the relevant data (v3_ext, pk, sig_alg, etc) */ 398 399 switch (type_desc->type) { 400 case AUTH_PARAM_RAW_DATA: 401 /* Data to be signed */ 402 *param = (void *)tbs.p; 403 *param_len = (unsigned int)tbs.len; 404 break; 405 case AUTH_PARAM_HASH: 406 /* All these parameters are included as X509v3 extensions */ 407 rc = get_ext(type_desc->cookie, param, param_len); 408 break; 409 case AUTH_PARAM_PUB_KEY: 410 if (type_desc->cookie != 0) { 411 /* Get public key from extension */ 412 rc = get_ext(type_desc->cookie, param, param_len); 413 } else { 414 /* Get the subject public key */ 415 *param = (void *)pk.p; 416 *param_len = (unsigned int)pk.len; 417 } 418 break; 419 case AUTH_PARAM_SIG_ALG: 420 /* Get the certificate signature algorithm */ 421 *param = (void *)sig_alg.p; 422 *param_len = (unsigned int)sig_alg.len; 423 break; 424 case AUTH_PARAM_SIG: 425 /* Get the certificate signature */ 426 *param = (void *)signature.p; 427 *param_len = (unsigned int)signature.len; 428 break; 429 default: 430 rc = IMG_PARSER_ERR_NOT_FOUND; 431 break; 432 } 433 434 return rc; 435 } 436 437 REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \ 438 check_integrity, get_auth_param); 439