17d37aa17SJuan Castillo /* 2ed38366fSNicolas Toromanoff * Copyright (c) 2015-2022, 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 697d37aa17SJuan Castillo * in the certificate. No need to check for errors since the image has passed 707d37aa17SJuan Castillo * the integrity check. 717d37aa17SJuan Castillo */ 727d37aa17SJuan Castillo static int get_ext(const char *oid, void **ext, unsigned int *ext_len) 737d37aa17SJuan Castillo { 747d37aa17SJuan Castillo int oid_len; 757d37aa17SJuan Castillo size_t len; 767d37aa17SJuan Castillo unsigned char *end_ext_data, *end_ext_octet; 777d37aa17SJuan Castillo unsigned char *p; 787d37aa17SJuan Castillo const unsigned char *end; 797d37aa17SJuan Castillo char oid_str[MAX_OID_STR_LEN]; 80649dbf6fSJuan Castillo mbedtls_asn1_buf extn_oid; 817d37aa17SJuan Castillo int is_critical; 827d37aa17SJuan Castillo 837d37aa17SJuan Castillo assert(oid != NULL); 847d37aa17SJuan Castillo 857d37aa17SJuan Castillo p = v3_ext.p; 867d37aa17SJuan Castillo end = v3_ext.p + v3_ext.len; 877d37aa17SJuan Castillo 88649dbf6fSJuan Castillo mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 89649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 907d37aa17SJuan Castillo 917d37aa17SJuan Castillo while (p < end) { 9232f0d3c6SDouglas Raillard zeromem(&extn_oid, sizeof(extn_oid)); 937d37aa17SJuan Castillo is_critical = 0; /* DEFAULT FALSE */ 947d37aa17SJuan Castillo 95649dbf6fSJuan Castillo mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 96649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 977d37aa17SJuan Castillo end_ext_data = p + len; 987d37aa17SJuan Castillo 997d37aa17SJuan Castillo /* Get extension ID */ 1007d37aa17SJuan Castillo extn_oid.tag = *p; 101649dbf6fSJuan Castillo mbedtls_asn1_get_tag(&p, end, &extn_oid.len, MBEDTLS_ASN1_OID); 1027d37aa17SJuan Castillo extn_oid.p = p; 1037d37aa17SJuan Castillo p += extn_oid.len; 1047d37aa17SJuan Castillo 1057d37aa17SJuan Castillo /* Get optional critical */ 106649dbf6fSJuan Castillo mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical); 1077d37aa17SJuan Castillo 1087d37aa17SJuan Castillo /* Extension data */ 109649dbf6fSJuan Castillo mbedtls_asn1_get_tag(&p, end_ext_data, &len, 110649dbf6fSJuan Castillo MBEDTLS_ASN1_OCTET_STRING); 1117d37aa17SJuan Castillo end_ext_octet = p + len; 1127d37aa17SJuan Castillo 1137d37aa17SJuan Castillo /* Detect requested extension */ 114649dbf6fSJuan Castillo oid_len = mbedtls_oid_get_numeric_string(oid_str, 115649dbf6fSJuan Castillo MAX_OID_STR_LEN, 116649dbf6fSJuan Castillo &extn_oid); 117ed38366fSNicolas Toromanoff if ((oid_len == MBEDTLS_ERR_OID_BUF_TOO_SMALL) || (oid_len < 0)) { 1187d37aa17SJuan Castillo return IMG_PARSER_ERR; 1197d37aa17SJuan Castillo } 120ed38366fSNicolas Toromanoff if (((size_t)oid_len == strlen(oid_str)) && !strcmp(oid, oid_str)) { 1217d37aa17SJuan Castillo *ext = (void *)p; 1227d37aa17SJuan Castillo *ext_len = (unsigned int)len; 1237d37aa17SJuan Castillo return IMG_PARSER_OK; 1247d37aa17SJuan Castillo } 1257d37aa17SJuan Castillo 1267d37aa17SJuan Castillo /* Next */ 1277d37aa17SJuan Castillo p = end_ext_octet; 1287d37aa17SJuan Castillo } 1297d37aa17SJuan Castillo 1307d37aa17SJuan Castillo return IMG_PARSER_ERR_NOT_FOUND; 1317d37aa17SJuan Castillo } 1327d37aa17SJuan Castillo 1337d37aa17SJuan Castillo 1347d37aa17SJuan Castillo /* 1357d37aa17SJuan Castillo * Check the integrity of the certificate ASN.1 structure. 13651c5e1a2SAntonio Nino Diaz * 1377d37aa17SJuan Castillo * Extract the relevant data that will be used later during authentication. 13851c5e1a2SAntonio Nino Diaz * 13951c5e1a2SAntonio Nino Diaz * This function doesn't clear the static variables located on the top of this 14051c5e1a2SAntonio Nino Diaz * file in case of an error. It is only called from check_integrity(), which 14151c5e1a2SAntonio Nino Diaz * performs the cleanup if necessary. 1427d37aa17SJuan Castillo */ 1437d37aa17SJuan Castillo static int cert_parse(void *img, unsigned int img_len) 1447d37aa17SJuan Castillo { 1457d37aa17SJuan Castillo int ret, is_critical; 1467d37aa17SJuan Castillo size_t len; 1477d37aa17SJuan Castillo unsigned char *p, *end, *crt_end; 148649dbf6fSJuan Castillo mbedtls_asn1_buf sig_alg1, sig_alg2; 149*e9e4a2a6SDemi Marie Obenour /* 150*e9e4a2a6SDemi Marie Obenour * The unique ASN.1 DER encoding of [0] EXPLICIT INTEGER { v3(2} }. 151*e9e4a2a6SDemi Marie Obenour */ 152*e9e4a2a6SDemi Marie Obenour static const char v3[] = { 153*e9e4a2a6SDemi Marie Obenour /* The outer CONTEXT SPECIFIC 0 tag */ 154*e9e4a2a6SDemi Marie Obenour MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0, 155*e9e4a2a6SDemi Marie Obenour /* The number bytes used to encode the inner INTEGER */ 156*e9e4a2a6SDemi Marie Obenour 3, 157*e9e4a2a6SDemi Marie Obenour /* The tag of the inner INTEGER */ 158*e9e4a2a6SDemi Marie Obenour MBEDTLS_ASN1_INTEGER, 159*e9e4a2a6SDemi Marie Obenour /* The number of bytes needed to represent 2 */ 160*e9e4a2a6SDemi Marie Obenour 1, 161*e9e4a2a6SDemi Marie Obenour /* The actual value 2 */ 162*e9e4a2a6SDemi Marie Obenour 2, 163*e9e4a2a6SDemi Marie Obenour }; 1647d37aa17SJuan Castillo 1657d37aa17SJuan Castillo p = (unsigned char *)img; 1667d37aa17SJuan Castillo len = img_len; 1677d37aa17SJuan Castillo end = p + len; 1687d37aa17SJuan Castillo 1697d37aa17SJuan Castillo /* 1707d37aa17SJuan Castillo * Certificate ::= SEQUENCE { 1717d37aa17SJuan Castillo * tbsCertificate TBSCertificate, 1727d37aa17SJuan Castillo * signatureAlgorithm AlgorithmIdentifier, 1737d37aa17SJuan Castillo * signatureValue BIT STRING } 1747d37aa17SJuan Castillo */ 175649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 176649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 1777d37aa17SJuan Castillo if (ret != 0) { 1787d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 1797d37aa17SJuan Castillo } 1807d37aa17SJuan Castillo 1817d37aa17SJuan Castillo if (len > (size_t)(end - p)) { 1827d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 1837d37aa17SJuan Castillo } 1847d37aa17SJuan Castillo crt_end = p + len; 1857d37aa17SJuan Castillo 1867d37aa17SJuan Castillo /* 1877d37aa17SJuan Castillo * TBSCertificate ::= SEQUENCE { 1887d37aa17SJuan Castillo */ 1897d37aa17SJuan Castillo tbs.p = p; 190649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 191649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 1927d37aa17SJuan Castillo if (ret != 0) { 1937d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 1947d37aa17SJuan Castillo } 1957d37aa17SJuan Castillo end = p + len; 1967d37aa17SJuan Castillo tbs.len = end - tbs.p; 1977d37aa17SJuan Castillo 1987d37aa17SJuan Castillo /* 199*e9e4a2a6SDemi Marie Obenour * Version ::= [0] EXPLICIT INTEGER { v1(0), v2(1), v3(2) } 200*e9e4a2a6SDemi Marie Obenour * -- only v3 accepted 2017d37aa17SJuan Castillo */ 202*e9e4a2a6SDemi Marie Obenour if (((end - p) <= (ptrdiff_t)sizeof(v3)) || 203*e9e4a2a6SDemi Marie Obenour (memcmp(p, v3, sizeof(v3)) != 0)) { 2047d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2057d37aa17SJuan Castillo } 206*e9e4a2a6SDemi Marie Obenour p += sizeof(v3); 2077d37aa17SJuan Castillo 2087d37aa17SJuan Castillo /* 2097d37aa17SJuan Castillo * CertificateSerialNumber ::= INTEGER 2107d37aa17SJuan Castillo */ 211649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER); 2127d37aa17SJuan Castillo if (ret != 0) { 2137d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2147d37aa17SJuan Castillo } 2157d37aa17SJuan Castillo p += len; 2167d37aa17SJuan Castillo 2177d37aa17SJuan Castillo /* 2187d37aa17SJuan Castillo * signature AlgorithmIdentifier 2197d37aa17SJuan Castillo */ 2207d37aa17SJuan Castillo sig_alg1.p = p; 221649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 222649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 2237d37aa17SJuan Castillo if (ret != 0) { 2247d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2257d37aa17SJuan Castillo } 2267d37aa17SJuan Castillo if ((end - p) < 1) { 2277d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2287d37aa17SJuan Castillo } 2297d37aa17SJuan Castillo sig_alg1.len = (p + len) - sig_alg1.p; 2307d37aa17SJuan Castillo p += len; 2317d37aa17SJuan Castillo 2327d37aa17SJuan Castillo /* 2337d37aa17SJuan Castillo * issuer Name 2347d37aa17SJuan Castillo */ 235649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 236649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 2377d37aa17SJuan Castillo if (ret != 0) { 2387d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2397d37aa17SJuan Castillo } 2407d37aa17SJuan Castillo p += len; 2417d37aa17SJuan Castillo 2427d37aa17SJuan Castillo /* 2437d37aa17SJuan Castillo * Validity ::= SEQUENCE { 2447d37aa17SJuan Castillo * notBefore Time, 2457d37aa17SJuan Castillo * notAfter Time } 2467d37aa17SJuan Castillo * 2477d37aa17SJuan Castillo */ 248649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 249649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 2507d37aa17SJuan Castillo if (ret != 0) { 2517d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2527d37aa17SJuan Castillo } 2537d37aa17SJuan Castillo p += len; 2547d37aa17SJuan Castillo 2557d37aa17SJuan Castillo /* 2567d37aa17SJuan Castillo * subject Name 2577d37aa17SJuan Castillo */ 258649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 259649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 2607d37aa17SJuan Castillo if (ret != 0) { 2617d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2627d37aa17SJuan Castillo } 2637d37aa17SJuan Castillo p += len; 2647d37aa17SJuan Castillo 2657d37aa17SJuan Castillo /* 2667d37aa17SJuan Castillo * SubjectPublicKeyInfo 2677d37aa17SJuan Castillo */ 2687d37aa17SJuan Castillo pk.p = p; 269649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 270649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 2717d37aa17SJuan Castillo if (ret != 0) { 2727d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2737d37aa17SJuan Castillo } 2747d37aa17SJuan Castillo pk.len = (p + len) - pk.p; 2757d37aa17SJuan Castillo p += len; 2767d37aa17SJuan Castillo 2777d37aa17SJuan Castillo /* 2787d37aa17SJuan Castillo * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 2797d37aa17SJuan Castillo */ 280649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, 281649dbf6fSJuan Castillo MBEDTLS_ASN1_CONTEXT_SPECIFIC | 282649dbf6fSJuan Castillo MBEDTLS_ASN1_CONSTRUCTED | 1); 2837d37aa17SJuan Castillo if (ret != 0) { 284649dbf6fSJuan Castillo if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 2857d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 2867d37aa17SJuan Castillo } 2877d37aa17SJuan Castillo } else { 2887d37aa17SJuan Castillo p += len; 2897d37aa17SJuan Castillo } 2907d37aa17SJuan Castillo 2917d37aa17SJuan Castillo /* 2927d37aa17SJuan Castillo * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 2937d37aa17SJuan Castillo */ 294649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, 295649dbf6fSJuan Castillo MBEDTLS_ASN1_CONTEXT_SPECIFIC | 296649dbf6fSJuan Castillo MBEDTLS_ASN1_CONSTRUCTED | 2); 2977d37aa17SJuan Castillo if (ret != 0) { 298649dbf6fSJuan Castillo if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 2997d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3007d37aa17SJuan Castillo } 3017d37aa17SJuan Castillo } else { 3027d37aa17SJuan Castillo p += len; 3037d37aa17SJuan Castillo } 3047d37aa17SJuan Castillo 3057d37aa17SJuan Castillo /* 3067d37aa17SJuan Castillo * extensions [3] EXPLICIT Extensions OPTIONAL 3077d37aa17SJuan Castillo */ 308649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, 309649dbf6fSJuan Castillo MBEDTLS_ASN1_CONTEXT_SPECIFIC | 310649dbf6fSJuan Castillo MBEDTLS_ASN1_CONSTRUCTED | 3); 3117d37aa17SJuan Castillo if (ret != 0) { 3127d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3137d37aa17SJuan Castillo } 3147d37aa17SJuan Castillo 3157d37aa17SJuan Castillo /* 3167d37aa17SJuan Castillo * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension 3177d37aa17SJuan Castillo */ 3187d37aa17SJuan Castillo v3_ext.p = p; 319649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 320649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 3217d37aa17SJuan Castillo if (ret != 0) { 3227d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3237d37aa17SJuan Castillo } 3247d37aa17SJuan Castillo v3_ext.len = (p + len) - v3_ext.p; 3257d37aa17SJuan Castillo 3267d37aa17SJuan Castillo /* 3277d37aa17SJuan Castillo * Check extensions integrity 3287d37aa17SJuan Castillo */ 3297d37aa17SJuan Castillo while (p < end) { 330649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, 331649dbf6fSJuan Castillo MBEDTLS_ASN1_CONSTRUCTED | 332649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 3337d37aa17SJuan Castillo if (ret != 0) { 3347d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3357d37aa17SJuan Castillo } 3367d37aa17SJuan Castillo 3377d37aa17SJuan Castillo /* Get extension ID */ 338649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID); 3397d37aa17SJuan Castillo if (ret != 0) { 3407d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3417d37aa17SJuan Castillo } 3427d37aa17SJuan Castillo p += len; 3437d37aa17SJuan Castillo 3447d37aa17SJuan Castillo /* Get optional critical */ 345649dbf6fSJuan Castillo ret = mbedtls_asn1_get_bool(&p, end, &is_critical); 346649dbf6fSJuan Castillo if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) { 3477d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3487d37aa17SJuan Castillo } 3497d37aa17SJuan Castillo 3507d37aa17SJuan Castillo /* Data should be octet string type */ 351649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, 352649dbf6fSJuan Castillo MBEDTLS_ASN1_OCTET_STRING); 3537d37aa17SJuan Castillo if (ret != 0) { 3547d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3557d37aa17SJuan Castillo } 3567d37aa17SJuan Castillo p += len; 3577d37aa17SJuan Castillo } 3587d37aa17SJuan Castillo 3597d37aa17SJuan Castillo if (p != end) { 3607d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3617d37aa17SJuan Castillo } 3627d37aa17SJuan Castillo 3637d37aa17SJuan Castillo end = crt_end; 3647d37aa17SJuan Castillo 3657d37aa17SJuan Castillo /* 3667d37aa17SJuan Castillo * } 3677d37aa17SJuan Castillo * -- end of TBSCertificate 3687d37aa17SJuan Castillo * 3697d37aa17SJuan Castillo * signatureAlgorithm AlgorithmIdentifier 3707d37aa17SJuan Castillo */ 3717d37aa17SJuan Castillo sig_alg2.p = p; 372649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | 373649dbf6fSJuan Castillo MBEDTLS_ASN1_SEQUENCE); 3747d37aa17SJuan Castillo if (ret != 0) { 3757d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3767d37aa17SJuan Castillo } 3777d37aa17SJuan Castillo if ((end - p) < 1) { 3787d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3797d37aa17SJuan Castillo } 3807d37aa17SJuan Castillo sig_alg2.len = (p + len) - sig_alg2.p; 3817d37aa17SJuan Castillo p += len; 3827d37aa17SJuan Castillo 3837d37aa17SJuan Castillo /* Compare both signature algorithms */ 3847d37aa17SJuan Castillo if (sig_alg1.len != sig_alg2.len) { 3857d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3867d37aa17SJuan Castillo } 387fabd21adSAntonio Nino Diaz if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) { 3887d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3897d37aa17SJuan Castillo } 3907d37aa17SJuan Castillo memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg)); 3917d37aa17SJuan Castillo 3927d37aa17SJuan Castillo /* 3937d37aa17SJuan Castillo * signatureValue BIT STRING 3947d37aa17SJuan Castillo */ 3957d37aa17SJuan Castillo signature.p = p; 396649dbf6fSJuan Castillo ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_BIT_STRING); 3977d37aa17SJuan Castillo if (ret != 0) { 3987d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 3997d37aa17SJuan Castillo } 4007d37aa17SJuan Castillo signature.len = (p + len) - signature.p; 4017d37aa17SJuan Castillo p += len; 4027d37aa17SJuan Castillo 4037d37aa17SJuan Castillo /* Check certificate length */ 4047d37aa17SJuan Castillo if (p != end) { 4057d37aa17SJuan Castillo return IMG_PARSER_ERR_FORMAT; 4067d37aa17SJuan Castillo } 4077d37aa17SJuan Castillo 4087d37aa17SJuan Castillo return IMG_PARSER_OK; 4097d37aa17SJuan Castillo } 4107d37aa17SJuan Castillo 4117d37aa17SJuan Castillo 4127d37aa17SJuan Castillo /* Exported functions */ 4137d37aa17SJuan Castillo 4147d37aa17SJuan Castillo static void init(void) 4157d37aa17SJuan Castillo { 4167d37aa17SJuan Castillo mbedtls_init(); 4177d37aa17SJuan Castillo } 4187d37aa17SJuan Castillo 41951c5e1a2SAntonio Nino Diaz /* 42051c5e1a2SAntonio Nino Diaz * Wrapper for cert_parse() that clears the static variables used by it in case 42151c5e1a2SAntonio Nino Diaz * of an error. 42251c5e1a2SAntonio Nino Diaz */ 4237d37aa17SJuan Castillo static int check_integrity(void *img, unsigned int img_len) 4247d37aa17SJuan Castillo { 42551c5e1a2SAntonio Nino Diaz int rc = cert_parse(img, img_len); 42651c5e1a2SAntonio Nino Diaz 42751c5e1a2SAntonio Nino Diaz if (rc != IMG_PARSER_OK) 42851c5e1a2SAntonio Nino Diaz clear_temp_vars(); 42951c5e1a2SAntonio Nino Diaz 43051c5e1a2SAntonio Nino Diaz return rc; 4317d37aa17SJuan Castillo } 4327d37aa17SJuan Castillo 4337d37aa17SJuan Castillo /* 4347d37aa17SJuan Castillo * Extract an authentication parameter from an X509v3 certificate 43548279d52SJuan Castillo * 43648279d52SJuan Castillo * This function returns a pointer to the extracted data and its length. 43748279d52SJuan Castillo * Depending on the type of parameter, a pointer to the data stored in the 43848279d52SJuan Castillo * certificate may be returned (i.e. an octet string containing a hash). Other 43948279d52SJuan Castillo * data may need to be copied and formatted (i.e. integers). In the later case, 44048279d52SJuan Castillo * a buffer of the correct type needs to be statically allocated, filled and 44148279d52SJuan Castillo * returned. 4427d37aa17SJuan Castillo */ 4437d37aa17SJuan Castillo static int get_auth_param(const auth_param_type_desc_t *type_desc, 4447d37aa17SJuan Castillo void *img, unsigned int img_len, 4457d37aa17SJuan Castillo void **param, unsigned int *param_len) 4467d37aa17SJuan Castillo { 4477d37aa17SJuan Castillo int rc = IMG_PARSER_OK; 4487d37aa17SJuan Castillo 4497d37aa17SJuan Castillo /* We do not use img because the check_integrity function has already 4507d37aa17SJuan Castillo * extracted the relevant data (v3_ext, pk, sig_alg, etc) */ 4517d37aa17SJuan Castillo 4527d37aa17SJuan Castillo switch (type_desc->type) { 4537d37aa17SJuan Castillo case AUTH_PARAM_RAW_DATA: 4547d37aa17SJuan Castillo /* Data to be signed */ 4557d37aa17SJuan Castillo *param = (void *)tbs.p; 4567d37aa17SJuan Castillo *param_len = (unsigned int)tbs.len; 4577d37aa17SJuan Castillo break; 4587d37aa17SJuan Castillo case AUTH_PARAM_HASH: 45948279d52SJuan Castillo case AUTH_PARAM_NV_CTR: 4607d37aa17SJuan Castillo /* All these parameters are included as X509v3 extensions */ 4617d37aa17SJuan Castillo rc = get_ext(type_desc->cookie, param, param_len); 4627d37aa17SJuan Castillo break; 4637d37aa17SJuan Castillo case AUTH_PARAM_PUB_KEY: 4647d37aa17SJuan Castillo if (type_desc->cookie != 0) { 4657d37aa17SJuan Castillo /* Get public key from extension */ 4667d37aa17SJuan Castillo rc = get_ext(type_desc->cookie, param, param_len); 4677d37aa17SJuan Castillo } else { 4687d37aa17SJuan Castillo /* Get the subject public key */ 4697d37aa17SJuan Castillo *param = (void *)pk.p; 4707d37aa17SJuan Castillo *param_len = (unsigned int)pk.len; 4717d37aa17SJuan Castillo } 4727d37aa17SJuan Castillo break; 4737d37aa17SJuan Castillo case AUTH_PARAM_SIG_ALG: 4747d37aa17SJuan Castillo /* Get the certificate signature algorithm */ 4757d37aa17SJuan Castillo *param = (void *)sig_alg.p; 4767d37aa17SJuan Castillo *param_len = (unsigned int)sig_alg.len; 4777d37aa17SJuan Castillo break; 4787d37aa17SJuan Castillo case AUTH_PARAM_SIG: 4797d37aa17SJuan Castillo /* Get the certificate signature */ 4807d37aa17SJuan Castillo *param = (void *)signature.p; 4817d37aa17SJuan Castillo *param_len = (unsigned int)signature.len; 4827d37aa17SJuan Castillo break; 4837d37aa17SJuan Castillo default: 4847d37aa17SJuan Castillo rc = IMG_PARSER_ERR_NOT_FOUND; 4857d37aa17SJuan Castillo break; 4867d37aa17SJuan Castillo } 4877d37aa17SJuan Castillo 4887d37aa17SJuan Castillo return rc; 4897d37aa17SJuan Castillo } 4907d37aa17SJuan Castillo 4917d37aa17SJuan Castillo REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \ 4927d37aa17SJuan Castillo check_integrity, get_auth_param); 493