17d37aa17SJuan Castillo /* 2654b65b3SYann Gautier * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved. 37d37aa17SJuan Castillo * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 57d37aa17SJuan Castillo */ 67d37aa17SJuan Castillo 77d37aa17SJuan Castillo /* 8649dbf6fSJuan Castillo * X509 parser based on mbed TLS 97d37aa17SJuan Castillo * 107d37aa17SJuan Castillo * This module implements functions to check the integrity of a X509v3 117d37aa17SJuan Castillo * certificate ASN.1 structure and extract authentication parameters from the 127d37aa17SJuan Castillo * extensions field, such as an image hash or a public key. 137d37aa17SJuan Castillo */ 147d37aa17SJuan Castillo 157d37aa17SJuan Castillo #include <assert.h> 167d37aa17SJuan Castillo #include <stddef.h> 177d37aa17SJuan Castillo #include <stdint.h> 187d37aa17SJuan Castillo #include <string.h> 197d37aa17SJuan Castillo 207d37aa17SJuan Castillo /* mbed TLS headers */ 21649dbf6fSJuan Castillo #include <mbedtls/asn1.h> 22649dbf6fSJuan Castillo #include <mbedtls/oid.h> 23649dbf6fSJuan Castillo #include <mbedtls/platform.h> 247d37aa17SJuan Castillo 2509d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 2609d40e0eSAntonio Nino Diaz #include <drivers/auth/img_parser_mod.h> 2709d40e0eSAntonio Nino Diaz #include <drivers/auth/mbedtls/mbedtls_common.h> 2809d40e0eSAntonio Nino Diaz #include <lib/utils.h> 2909d40e0eSAntonio Nino Diaz 307d37aa17SJuan Castillo /* Maximum OID string length ("a.b.c.d.e.f ...") */ 317d37aa17SJuan Castillo #define MAX_OID_STR_LEN 64 327d37aa17SJuan Castillo 337d37aa17SJuan Castillo #define LIB_NAME "mbed TLS X509v3" 347d37aa17SJuan Castillo 357d37aa17SJuan Castillo /* Temporary variables to speed up the authentication parameters search. These 367d37aa17SJuan Castillo * variables are assigned once during the integrity check and used any time an 377d37aa17SJuan Castillo * authentication parameter is requested, so we do not have to parse the image 387d37aa17SJuan Castillo * again */ 39649dbf6fSJuan Castillo static mbedtls_asn1_buf tbs; 40649dbf6fSJuan Castillo static mbedtls_asn1_buf v3_ext; 41649dbf6fSJuan Castillo static mbedtls_asn1_buf pk; 42649dbf6fSJuan Castillo static mbedtls_asn1_buf sig_alg; 43649dbf6fSJuan Castillo static mbedtls_asn1_buf signature; 447d37aa17SJuan Castillo 457d37aa17SJuan Castillo /* 4651c5e1a2SAntonio Nino Diaz * Clear all static temporary variables. 4751c5e1a2SAntonio Nino Diaz */ 4851c5e1a2SAntonio Nino Diaz static void clear_temp_vars(void) 4951c5e1a2SAntonio Nino Diaz { 5051c5e1a2SAntonio Nino Diaz #define ZERO_AND_CLEAN(x) \ 5151c5e1a2SAntonio Nino Diaz do { \ 5232f0d3c6SDouglas Raillard zeromem(&x, sizeof(x)); \ 5351c5e1a2SAntonio Nino Diaz clean_dcache_range((uintptr_t)&x, sizeof(x)); \ 5451c5e1a2SAntonio Nino Diaz } while (0); 5551c5e1a2SAntonio Nino Diaz 5651c5e1a2SAntonio Nino Diaz ZERO_AND_CLEAN(tbs) 5751c5e1a2SAntonio Nino Diaz ZERO_AND_CLEAN(v3_ext); 5851c5e1a2SAntonio Nino Diaz ZERO_AND_CLEAN(pk); 5951c5e1a2SAntonio Nino Diaz ZERO_AND_CLEAN(sig_alg); 6051c5e1a2SAntonio Nino Diaz ZERO_AND_CLEAN(signature); 6151c5e1a2SAntonio Nino Diaz 6251c5e1a2SAntonio Nino Diaz #undef ZERO_AND_CLEAN 6351c5e1a2SAntonio Nino Diaz } 6451c5e1a2SAntonio Nino Diaz 6551c5e1a2SAntonio Nino Diaz /* 667d37aa17SJuan Castillo * Get X509v3 extension 677d37aa17SJuan Castillo * 687d37aa17SJuan Castillo * Global variable 'v3_ext' must point to the extensions region 69a987b89dSDemi Marie Obenour * in the certificate. OID may be NULL to request that get_ext() 70a987b89dSDemi Marie Obenour * is only being called for integrity checking. 717d37aa17SJuan Castillo */ 727d37aa17SJuan Castillo static int get_ext(const char *oid, void **ext, unsigned int *ext_len) 737d37aa17SJuan Castillo { 74a987b89dSDemi Marie Obenour int oid_len, ret, is_critical; 757d37aa17SJuan Castillo size_t len; 767d37aa17SJuan Castillo unsigned char *p; 777d37aa17SJuan Castillo const unsigned char *end; 787d37aa17SJuan Castillo char oid_str[MAX_OID_STR_LEN]; 79649dbf6fSJuan Castillo mbedtls_asn1_buf extn_oid; 807d37aa17SJuan Castillo 817d37aa17SJuan Castillo p = v3_ext.p; 827d37aa17SJuan Castillo end = v3_ext.p + v3_ext.len; 837d37aa17SJuan Castillo 84a987b89dSDemi Marie Obenour /* 85a987b89dSDemi Marie Obenour * Check extensions integrity. At least one extension is 86a987b89dSDemi Marie Obenour * required: the ASN.1 specifies a minimum size of 1, and at 87a987b89dSDemi Marie Obenour * least one extension is needed to authenticate the next stage 88a987b89dSDemi Marie Obenour * in the boot chain. 89a987b89dSDemi Marie Obenour */ 90a987b89dSDemi Marie Obenour do { 91a987b89dSDemi Marie Obenour unsigned char *end_ext_data; 927d37aa17SJuan Castillo 93a987b89dSDemi Marie Obenour ret = mbedtls_asn1_get_tag(&p, end, &len, 94a987b89dSDemi Marie Obenour MBEDTLS_ASN1_CONSTRUCTED | 95649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 96a987b89dSDemi Marie Obenour if (ret != 0) { 97a987b89dSDemi Marie Obenour return IMG_PARSER_ERR_FORMAT; 98a987b89dSDemi Marie Obenour } 997d37aa17SJuan Castillo end_ext_data = p + len; 1007d37aa17SJuan Castillo 1017d37aa17SJuan Castillo /* Get extension ID */ 102a987b89dSDemi Marie Obenour ret = mbedtls_asn1_get_tag(&p, end_ext_data, &extn_oid.len, 103a987b89dSDemi Marie Obenour MBEDTLS_ASN1_OID); 104a987b89dSDemi Marie Obenour if (ret != 0) { 105a987b89dSDemi Marie Obenour return IMG_PARSER_ERR_FORMAT; 106a987b89dSDemi Marie Obenour } 107a987b89dSDemi Marie Obenour extn_oid.tag = MBEDTLS_ASN1_OID; 1087d37aa17SJuan Castillo extn_oid.p = p; 1097d37aa17SJuan Castillo p += extn_oid.len; 1107d37aa17SJuan Castillo 1117d37aa17SJuan Castillo /* Get optional critical */ 112a987b89dSDemi Marie Obenour ret = mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical); 113a987b89dSDemi Marie Obenour if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) { 114a987b89dSDemi Marie Obenour return IMG_PARSER_ERR_FORMAT; 115a987b89dSDemi Marie Obenour } 1167d37aa17SJuan Castillo 117a987b89dSDemi Marie Obenour /* 118a987b89dSDemi Marie Obenour * Data should be octet string type and must use all bytes in 119a987b89dSDemi Marie Obenour * the Extension. 120a987b89dSDemi Marie Obenour */ 121a987b89dSDemi Marie Obenour ret = mbedtls_asn1_get_tag(&p, end_ext_data, &len, 122649dbf6fSJuan Castillo MBEDTLS_ASN1_OCTET_STRING); 123a987b89dSDemi Marie Obenour if ((ret != 0) || ((p + len) != end_ext_data)) { 124a987b89dSDemi Marie Obenour return IMG_PARSER_ERR_FORMAT; 125a987b89dSDemi Marie Obenour } 1267d37aa17SJuan Castillo 1277d37aa17SJuan Castillo /* Detect requested extension */ 128649dbf6fSJuan Castillo oid_len = mbedtls_oid_get_numeric_string(oid_str, 129649dbf6fSJuan Castillo MAX_OID_STR_LEN, 130649dbf6fSJuan Castillo &extn_oid); 131ed38366fSNicolas Toromanoff if ((oid_len == MBEDTLS_ERR_OID_BUF_TOO_SMALL) || (oid_len < 0)) { 1327d37aa17SJuan Castillo return IMG_PARSER_ERR; 1337d37aa17SJuan Castillo } 134a987b89dSDemi Marie Obenour 135a987b89dSDemi Marie Obenour if ((oid != NULL) && 136a987b89dSDemi Marie Obenour ((size_t)oid_len == strlen(oid_str)) && 137a987b89dSDemi Marie Obenour (strcmp(oid, oid_str) == 0)) { 138*22a53545SDemi Marie Obenour /* Extension must be ASN.1 DER */ 139*22a53545SDemi Marie Obenour if (len < 2) { 140*22a53545SDemi Marie Obenour /* too short */ 141*22a53545SDemi Marie Obenour return IMG_PARSER_ERR_FORMAT; 142*22a53545SDemi Marie Obenour } 143*22a53545SDemi Marie Obenour 144*22a53545SDemi Marie Obenour if ((p[0] & 0x1F) == 0x1F) { 145*22a53545SDemi Marie Obenour /* multi-byte ASN.1 DER tag, not allowed */ 146*22a53545SDemi Marie Obenour return IMG_PARSER_ERR_FORMAT; 147*22a53545SDemi Marie Obenour } 148*22a53545SDemi Marie Obenour 149*22a53545SDemi Marie Obenour if ((p[0] & 0xDF) == 0) { 150*22a53545SDemi Marie Obenour /* UNIVERSAL 0 tag, not allowed */ 151*22a53545SDemi Marie Obenour return IMG_PARSER_ERR_FORMAT; 152*22a53545SDemi Marie Obenour } 153*22a53545SDemi Marie Obenour 1547d37aa17SJuan Castillo *ext = (void *)p; 1557d37aa17SJuan Castillo *ext_len = (unsigned int)len; 156*22a53545SDemi Marie Obenour 157*22a53545SDemi Marie Obenour /* Advance past the tag byte */ 158*22a53545SDemi Marie Obenour p++; 159*22a53545SDemi Marie Obenour 160*22a53545SDemi Marie Obenour if (mbedtls_asn1_get_len(&p, end_ext_data, &len)) { 161*22a53545SDemi Marie Obenour /* not valid DER */ 162*22a53545SDemi Marie Obenour return IMG_PARSER_ERR_FORMAT; 163*22a53545SDemi Marie Obenour } 164*22a53545SDemi Marie Obenour 165*22a53545SDemi Marie Obenour if (p + len != end_ext_data) { 166*22a53545SDemi Marie Obenour /* junk after ASN.1 object */ 167*22a53545SDemi Marie Obenour return IMG_PARSER_ERR_FORMAT; 168*22a53545SDemi Marie Obenour } 169*22a53545SDemi Marie Obenour 1707d37aa17SJuan Castillo return IMG_PARSER_OK; 1717d37aa17SJuan Castillo } 1727d37aa17SJuan Castillo 1737d37aa17SJuan Castillo /* Next */ 174a987b89dSDemi Marie Obenour p = end_ext_data; 175a987b89dSDemi Marie Obenour } while (p < end); 1767d37aa17SJuan Castillo 177a987b89dSDemi Marie Obenour return (oid == NULL) ? IMG_PARSER_OK : IMG_PARSER_ERR_NOT_FOUND; 1787d37aa17SJuan Castillo } 1797d37aa17SJuan Castillo 1807d37aa17SJuan Castillo 1817d37aa17SJuan Castillo /* 1827d37aa17SJuan Castillo * Check the integrity of the certificate ASN.1 structure. 18351c5e1a2SAntonio Nino Diaz * 1847d37aa17SJuan Castillo * Extract the relevant data that will be used later during authentication. 18551c5e1a2SAntonio Nino Diaz * 18651c5e1a2SAntonio Nino Diaz * This function doesn't clear the static variables located on the top of this 18751c5e1a2SAntonio Nino Diaz * file in case of an error. It is only called from check_integrity(), which 18851c5e1a2SAntonio Nino Diaz * performs the cleanup if necessary. 1897d37aa17SJuan Castillo */ 1907d37aa17SJuan Castillo static int cert_parse(void *img, unsigned int img_len) 1917d37aa17SJuan Castillo { 192a987b89dSDemi Marie Obenour int ret; 1937d37aa17SJuan Castillo size_t len; 19494c0cfbbSDemi Marie Obenour unsigned char *p, *end, *crt_end, *pk_end; 19563cc49d0SDemi Marie Obenour mbedtls_asn1_buf sig_alg1; 196e9e4a2a6SDemi Marie Obenour /* 197e9e4a2a6SDemi Marie Obenour * The unique ASN.1 DER encoding of [0] EXPLICIT INTEGER { v3(2} }. 198e9e4a2a6SDemi Marie Obenour */ 199e9e4a2a6SDemi Marie Obenour static const char v3[] = { 200e9e4a2a6SDemi Marie Obenour /* The outer CONTEXT SPECIFIC 0 tag */ 201e9e4a2a6SDemi Marie Obenour MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0, 202e9e4a2a6SDemi Marie Obenour /* The number bytes used to encode the inner INTEGER */ 203e9e4a2a6SDemi Marie Obenour 3, 204e9e4a2a6SDemi Marie Obenour /* The tag of the inner INTEGER */ 205e9e4a2a6SDemi Marie Obenour MBEDTLS_ASN1_INTEGER, 206e9e4a2a6SDemi Marie Obenour /* The number of bytes needed to represent 2 */ 207e9e4a2a6SDemi Marie Obenour 1, 208e9e4a2a6SDemi Marie Obenour /* The actual value 2 */ 209e9e4a2a6SDemi Marie Obenour 2, 210e9e4a2a6SDemi Marie Obenour }; 2117d37aa17SJuan Castillo 2127d37aa17SJuan Castillo p = (unsigned char *)img; 2137d37aa17SJuan Castillo len = img_len; 214ddd9f675SDemi Marie Obenour crt_end = p + len; 215ddd9f675SDemi Marie Obenour end = crt_end; 2167d37aa17SJuan Castillo 2177d37aa17SJuan Castillo /* 2187d37aa17SJuan Castillo * Certificate ::= SEQUENCE { 2197d37aa17SJuan Castillo * tbsCertificate TBSCertificate, 2207d37aa17SJuan Castillo * signatureAlgorithm AlgorithmIdentifier, 2217d37aa17SJuan Castillo * signatureValue BIT STRING } 2227d37aa17SJuan Castillo */ 223649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 224649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 225ddd9f675SDemi Marie Obenour if ((ret != 0) || ((p + len) != end)) { 2267d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2277d37aa17SJuan Castillo } 2287d37aa17SJuan Castillo 2297d37aa17SJuan Castillo /* 2307d37aa17SJuan Castillo * TBSCertificate ::= SEQUENCE { 2317d37aa17SJuan Castillo */ 2327d37aa17SJuan Castillo tbs.p = p; 233649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 234649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 2357d37aa17SJuan Castillo if (ret != 0) { 2367d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2377d37aa17SJuan Castillo } 2387d37aa17SJuan Castillo end = p + len; 2397d37aa17SJuan Castillo tbs.len = end - tbs.p; 2407d37aa17SJuan Castillo 2417d37aa17SJuan Castillo /* 242e9e4a2a6SDemi Marie Obenour * Version ::= [0] EXPLICIT INTEGER { v1(0), v2(1), v3(2) } 243e9e4a2a6SDemi Marie Obenour * -- only v3 accepted 2447d37aa17SJuan Castillo */ 245e9e4a2a6SDemi Marie Obenour if (((end - p) <= (ptrdiff_t)sizeof(v3)) || 246e9e4a2a6SDemi Marie Obenour (memcmp(p, v3, sizeof(v3)) != 0)) { 2477d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2487d37aa17SJuan Castillo } 249e9e4a2a6SDemi Marie Obenour p += sizeof(v3); 2507d37aa17SJuan Castillo 2517d37aa17SJuan Castillo /* 2527d37aa17SJuan Castillo * CertificateSerialNumber ::= INTEGER 2537d37aa17SJuan Castillo */ 254649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER); 2557d37aa17SJuan Castillo if (ret != 0) { 2567d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2577d37aa17SJuan Castillo } 2587d37aa17SJuan Castillo p += len; 2597d37aa17SJuan Castillo 2607d37aa17SJuan Castillo /* 2617d37aa17SJuan Castillo * signature AlgorithmIdentifier 2627d37aa17SJuan Castillo */ 2637d37aa17SJuan Castillo sig_alg1.p = p; 264649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 265649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 2667d37aa17SJuan Castillo if (ret != 0) { 2677d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2687d37aa17SJuan Castillo } 2697d37aa17SJuan Castillo sig_alg1.len = (p + len) - sig_alg1.p; 2707d37aa17SJuan Castillo p += len; 2717d37aa17SJuan Castillo 2727d37aa17SJuan Castillo /* 2737d37aa17SJuan Castillo * issuer Name 2747d37aa17SJuan Castillo */ 275649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 276649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 2777d37aa17SJuan Castillo if (ret != 0) { 2787d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2797d37aa17SJuan Castillo } 2807d37aa17SJuan Castillo p += len; 2817d37aa17SJuan Castillo 2827d37aa17SJuan Castillo /* 2837d37aa17SJuan Castillo * Validity ::= SEQUENCE { 2847d37aa17SJuan Castillo * notBefore Time, 2857d37aa17SJuan Castillo * notAfter Time } 2867d37aa17SJuan Castillo * 2877d37aa17SJuan Castillo */ 288649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 289649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 2907d37aa17SJuan Castillo if (ret != 0) { 2917d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2927d37aa17SJuan Castillo } 2937d37aa17SJuan Castillo p += len; 2947d37aa17SJuan Castillo 2957d37aa17SJuan Castillo /* 2967d37aa17SJuan Castillo * subject Name 2977d37aa17SJuan Castillo */ 298649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 299649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 3007d37aa17SJuan Castillo if (ret != 0) { 3017d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3027d37aa17SJuan Castillo } 3037d37aa17SJuan Castillo p += len; 3047d37aa17SJuan Castillo 3057d37aa17SJuan Castillo /* 3067d37aa17SJuan Castillo * SubjectPublicKeyInfo 3077d37aa17SJuan Castillo */ 3087d37aa17SJuan Castillo pk.p = p; 309649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 310649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 3117d37aa17SJuan Castillo if (ret != 0) { 3127d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3137d37aa17SJuan Castillo } 31494c0cfbbSDemi Marie Obenour pk_end = p + len; 31594c0cfbbSDemi Marie Obenour pk.len = pk_end - pk.p; 31694c0cfbbSDemi Marie Obenour 317ce882b53SDemi Marie Obenour /* algorithm */ 31894c0cfbbSDemi Marie Obenour ret = mbedtls_asn1_get_tag(&p, pk_end, &len, MBEDTLS_ASN1_CONSTRUCTED | 31994c0cfbbSDemi Marie Obenour MBEDTLS_ASN1_SEQUENCE); 32094c0cfbbSDemi Marie Obenour if (ret != 0) { 32194c0cfbbSDemi Marie Obenour return IMG_PARSER_ERR_FORMAT; 32294c0cfbbSDemi Marie Obenour } 3237d37aa17SJuan Castillo p += len; 3247d37aa17SJuan Castillo 3258816dbb3SDemi Marie Obenour /* Key is a BIT STRING and must use all bytes in SubjectPublicKeyInfo */ 3268816dbb3SDemi Marie Obenour ret = mbedtls_asn1_get_bitstring_null(&p, pk_end, &len); 32794c0cfbbSDemi Marie Obenour if ((ret != 0) || (p + len != pk_end)) { 32894c0cfbbSDemi Marie Obenour return IMG_PARSER_ERR_FORMAT; 32994c0cfbbSDemi Marie Obenour } 33094c0cfbbSDemi Marie Obenour p = pk_end; 33194c0cfbbSDemi Marie Obenour 3327d37aa17SJuan Castillo /* 3337d37aa17SJuan Castillo * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 3347d37aa17SJuan Castillo * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 3356a7104a3SDemi Marie Obenour * -- technically these contain BIT STRINGs but that is not worth 3366a7104a3SDemi Marie Obenour * -- validating 3377d37aa17SJuan Castillo */ 3386a7104a3SDemi Marie Obenour for (int i = 1; i < 3; i++) { 339649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, 340649dbf6fSJuan Castillo MBEDTLS_ASN1_CONTEXT_SPECIFIC | 3416a7104a3SDemi Marie Obenour MBEDTLS_ASN1_CONSTRUCTED | i); 3426a7104a3SDemi Marie Obenour /* 3436a7104a3SDemi Marie Obenour * Unique IDs are obsolete, so MBEDTLS_ERR_ASN1_UNEXPECTED_TAG 3446a7104a3SDemi Marie Obenour * is the common case. 3456a7104a3SDemi Marie Obenour */ 346649dbf6fSJuan Castillo if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 3476a7104a3SDemi Marie Obenour if (ret != 0) { 3487d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3497d37aa17SJuan Castillo } 3507d37aa17SJuan Castillo p += len; 3517d37aa17SJuan Castillo } 3526a7104a3SDemi Marie Obenour } 3537d37aa17SJuan Castillo 3547d37aa17SJuan Castillo /* 3557d37aa17SJuan Castillo * extensions [3] EXPLICIT Extensions OPTIONAL 35672460f50SDemi Marie Obenour * } 35772460f50SDemi Marie Obenour * 35872460f50SDemi Marie Obenour * X.509 and RFC5280 allow omitting the extensions entirely. 35972460f50SDemi Marie Obenour * However, in TF-A, a certificate with no extensions would 36072460f50SDemi Marie Obenour * always fail later on, as the extensions contain the 36172460f50SDemi Marie Obenour * information needed to authenticate the next stage in the 36272460f50SDemi Marie Obenour * boot chain. Furthermore, get_ext() assumes that the 36372460f50SDemi Marie Obenour * extensions have been parsed into v3_ext, and allowing 36472460f50SDemi Marie Obenour * there to be no extensions would pointlessly complicate 36572460f50SDemi Marie Obenour * the code. Therefore, just reject certificates without 36672460f50SDemi Marie Obenour * extensions. This is also why version 1 and 2 certificates 36772460f50SDemi Marie Obenour * are rejected above. 3687d37aa17SJuan Castillo */ 369649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, 370649dbf6fSJuan Castillo MBEDTLS_ASN1_CONTEXT_SPECIFIC | 371649dbf6fSJuan Castillo MBEDTLS_ASN1_CONSTRUCTED | 3); 372fd37982aSDemi Marie Obenour if ((ret != 0) || (len != (size_t)(end - p))) { 3737d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3747d37aa17SJuan Castillo } 3757d37aa17SJuan Castillo 3767d37aa17SJuan Castillo /* 3777d37aa17SJuan Castillo * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension 378fd37982aSDemi Marie Obenour * -- must use all remaining bytes in TBSCertificate 3797d37aa17SJuan Castillo */ 380649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 381649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 382fd37982aSDemi Marie Obenour if ((ret != 0) || (len != (size_t)(end - p))) { 3837d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3847d37aa17SJuan Castillo } 385ce882b53SDemi Marie Obenour v3_ext.p = p; 386ce882b53SDemi Marie Obenour v3_ext.len = len; 3877d37aa17SJuan Castillo p += len; 3887d37aa17SJuan Castillo 389a987b89dSDemi Marie Obenour /* Check extensions integrity */ 390a987b89dSDemi Marie Obenour ret = get_ext(NULL, NULL, NULL); 391a987b89dSDemi Marie Obenour if (ret != IMG_PARSER_OK) { 392a987b89dSDemi Marie Obenour return ret; 3937d37aa17SJuan Castillo } 3947d37aa17SJuan Castillo 3957d37aa17SJuan Castillo end = crt_end; 3967d37aa17SJuan Castillo 3977d37aa17SJuan Castillo /* 3987d37aa17SJuan Castillo * } 3997d37aa17SJuan Castillo * -- end of TBSCertificate 4007d37aa17SJuan Castillo * 4017d37aa17SJuan Castillo * signatureAlgorithm AlgorithmIdentifier 40263cc49d0SDemi Marie Obenour * -- Does not need to be parsed. Ensuring it is bitwise 40363cc49d0SDemi Marie Obenour * -- identical (including the tag!) with the first signature 40463cc49d0SDemi Marie Obenour * -- algorithm is sufficient. 4057d37aa17SJuan Castillo */ 40663cc49d0SDemi Marie Obenour if ((sig_alg1.len >= (size_t)(end - p)) || 40763cc49d0SDemi Marie Obenour (0 != memcmp(sig_alg1.p, p, sig_alg1.len))) { 4087d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 4097d37aa17SJuan Castillo } 41063cc49d0SDemi Marie Obenour p += sig_alg1.len; 4117d37aa17SJuan Castillo memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg)); 4127d37aa17SJuan Castillo 4137d37aa17SJuan Castillo /* 4147d37aa17SJuan Castillo * signatureValue BIT STRING 415ddd9f675SDemi Marie Obenour * } -- must consume all bytes 4167d37aa17SJuan Castillo */ 4177d37aa17SJuan Castillo signature.p = p; 4188816dbb3SDemi Marie Obenour ret = mbedtls_asn1_get_bitstring_null(&p, end, &len); 419ddd9f675SDemi Marie Obenour if ((ret != 0) || ((p + len) != end)) { 4207d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 4217d37aa17SJuan Castillo } 422ddd9f675SDemi Marie Obenour signature.len = end - signature.p; 4237d37aa17SJuan Castillo 4247d37aa17SJuan Castillo return IMG_PARSER_OK; 4257d37aa17SJuan Castillo } 4267d37aa17SJuan Castillo 4277d37aa17SJuan Castillo 4287d37aa17SJuan Castillo /* Exported functions */ 4297d37aa17SJuan Castillo 4307d37aa17SJuan Castillo static void init(void) 4317d37aa17SJuan Castillo { 4327d37aa17SJuan Castillo mbedtls_init(); 4337d37aa17SJuan Castillo } 4347d37aa17SJuan Castillo 43551c5e1a2SAntonio Nino Diaz /* 43651c5e1a2SAntonio Nino Diaz * Wrapper for cert_parse() that clears the static variables used by it in case 43751c5e1a2SAntonio Nino Diaz * of an error. 43851c5e1a2SAntonio Nino Diaz */ 4397d37aa17SJuan Castillo static int check_integrity(void *img, unsigned int img_len) 4407d37aa17SJuan Castillo { 44151c5e1a2SAntonio Nino Diaz int rc = cert_parse(img, img_len); 44251c5e1a2SAntonio Nino Diaz 44351c5e1a2SAntonio Nino Diaz if (rc != IMG_PARSER_OK) 44451c5e1a2SAntonio Nino Diaz clear_temp_vars(); 44551c5e1a2SAntonio Nino Diaz 44651c5e1a2SAntonio Nino Diaz return rc; 4477d37aa17SJuan Castillo } 4487d37aa17SJuan Castillo 4497d37aa17SJuan Castillo /* 4507d37aa17SJuan Castillo * Extract an authentication parameter from an X509v3 certificate 45148279d52SJuan Castillo * 45248279d52SJuan Castillo * This function returns a pointer to the extracted data and its length. 45348279d52SJuan Castillo * Depending on the type of parameter, a pointer to the data stored in the 45448279d52SJuan Castillo * certificate may be returned (i.e. an octet string containing a hash). Other 45548279d52SJuan Castillo * data may need to be copied and formatted (i.e. integers). In the later case, 45648279d52SJuan Castillo * a buffer of the correct type needs to be statically allocated, filled and 45748279d52SJuan Castillo * returned. 4587d37aa17SJuan Castillo */ 4597d37aa17SJuan Castillo static int get_auth_param(const auth_param_type_desc_t *type_desc, 4607d37aa17SJuan Castillo void *img, unsigned int img_len, 4617d37aa17SJuan Castillo void **param, unsigned int *param_len) 4627d37aa17SJuan Castillo { 4637d37aa17SJuan Castillo int rc = IMG_PARSER_OK; 4647d37aa17SJuan Castillo 4657d37aa17SJuan Castillo /* We do not use img because the check_integrity function has already 4667d37aa17SJuan Castillo * extracted the relevant data (v3_ext, pk, sig_alg, etc) */ 4677d37aa17SJuan Castillo 4687d37aa17SJuan Castillo switch (type_desc->type) { 4697d37aa17SJuan Castillo case AUTH_PARAM_RAW_DATA: 4707d37aa17SJuan Castillo /* Data to be signed */ 4717d37aa17SJuan Castillo *param = (void *)tbs.p; 4727d37aa17SJuan Castillo *param_len = (unsigned int)tbs.len; 4737d37aa17SJuan Castillo break; 4747d37aa17SJuan Castillo case AUTH_PARAM_HASH: 47548279d52SJuan Castillo case AUTH_PARAM_NV_CTR: 4767d37aa17SJuan Castillo /* All these parameters are included as X509v3 extensions */ 4777d37aa17SJuan Castillo rc = get_ext(type_desc->cookie, param, param_len); 4787d37aa17SJuan Castillo break; 4797d37aa17SJuan Castillo case AUTH_PARAM_PUB_KEY: 480654b65b3SYann Gautier if (type_desc->cookie != NULL) { 4817d37aa17SJuan Castillo /* Get public key from extension */ 4827d37aa17SJuan Castillo rc = get_ext(type_desc->cookie, param, param_len); 4837d37aa17SJuan Castillo } else { 4847d37aa17SJuan Castillo /* Get the subject public key */ 4857d37aa17SJuan Castillo *param = (void *)pk.p; 4867d37aa17SJuan Castillo *param_len = (unsigned int)pk.len; 4877d37aa17SJuan Castillo } 4887d37aa17SJuan Castillo break; 4897d37aa17SJuan Castillo case AUTH_PARAM_SIG_ALG: 4907d37aa17SJuan Castillo /* Get the certificate signature algorithm */ 4917d37aa17SJuan Castillo *param = (void *)sig_alg.p; 4927d37aa17SJuan Castillo *param_len = (unsigned int)sig_alg.len; 4937d37aa17SJuan Castillo break; 4947d37aa17SJuan Castillo case AUTH_PARAM_SIG: 4957d37aa17SJuan Castillo /* Get the certificate signature */ 4967d37aa17SJuan Castillo *param = (void *)signature.p; 4977d37aa17SJuan Castillo *param_len = (unsigned int)signature.len; 4987d37aa17SJuan Castillo break; 4997d37aa17SJuan Castillo default: 5007d37aa17SJuan Castillo rc = IMG_PARSER_ERR_NOT_FOUND; 5017d37aa17SJuan Castillo break; 5027d37aa17SJuan Castillo } 5037d37aa17SJuan Castillo 5047d37aa17SJuan Castillo return rc; 5057d37aa17SJuan Castillo } 5067d37aa17SJuan Castillo 5079a90d720SElyes Haouas REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, 5087d37aa17SJuan Castillo check_integrity, get_auth_param); 509