1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * X.509 certificate parsing and verification 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 57901324dSJerome Forissier * SPDX-License-Identifier: Apache-2.0 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander */ 19817466cbSJens Wiklander /* 20817466cbSJens Wiklander * The ITU-T X.509 standard defines a certificate format for PKI. 21817466cbSJens Wiklander * 22817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) 23817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) 24817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) 25817466cbSJens Wiklander * 26817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf 27817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf 283d3b0591SJens Wiklander * 293d3b0591SJens Wiklander * [SIRO] https://cabforum.org/wp-content/uploads/Chunghwatelecom201503cabforumV4.pdf 30817466cbSJens Wiklander */ 31817466cbSJens Wiklander 327901324dSJerome Forissier #include "common.h" 33817466cbSJens Wiklander 34817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRT_PARSE_C) 35817466cbSJens Wiklander 36817466cbSJens Wiklander #include "mbedtls/x509_crt.h" 3711fa71b9SJerome Forissier #include "mbedtls/error.h" 38817466cbSJens Wiklander #include "mbedtls/oid.h" 393d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 40817466cbSJens Wiklander 41817466cbSJens Wiklander #include <string.h> 42817466cbSJens Wiklander 43817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 44817466cbSJens Wiklander #include "mbedtls/pem.h" 45817466cbSJens Wiklander #endif 46817466cbSJens Wiklander 4711fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 4811fa71b9SJerome Forissier #include "psa/crypto.h" 4911fa71b9SJerome Forissier #include "mbedtls/psa_util.h" 50*32b31808SJens Wiklander #endif /* MBEDTLS_USE_PSA_CRYPTO */ 51*32b31808SJens Wiklander #include "hash_info.h" 5211fa71b9SJerome Forissier 53817466cbSJens Wiklander #include "mbedtls/platform.h" 54817466cbSJens Wiklander 55817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 56817466cbSJens Wiklander #include "mbedtls/threading.h" 57817466cbSJens Wiklander #endif 58817466cbSJens Wiklander 59039e02dfSJerome Forissier #if defined(MBEDTLS_HAVE_TIME) 60817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 61817466cbSJens Wiklander #include <windows.h> 62817466cbSJens Wiklander #else 63817466cbSJens Wiklander #include <time.h> 64817466cbSJens Wiklander #endif 65039e02dfSJerome Forissier #endif 66817466cbSJens Wiklander 67817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 68817466cbSJens Wiklander #include <stdio.h> 69817466cbSJens Wiklander #if !defined(_WIN32) || defined(EFIX64) || defined(EFI32) 70817466cbSJens Wiklander #include <sys/types.h> 71817466cbSJens Wiklander #include <sys/stat.h> 72*32b31808SJens Wiklander #if defined(__MBED__) 73*32b31808SJens Wiklander #include <platform/mbed_retarget.h> 74*32b31808SJens Wiklander #else 75817466cbSJens Wiklander #include <dirent.h> 76*32b31808SJens Wiklander #endif /* __MBED__ */ 77*32b31808SJens Wiklander #include <errno.h> 78817466cbSJens Wiklander #endif /* !_WIN32 || EFIX64 || EFI32 */ 79817466cbSJens Wiklander #endif 80817466cbSJens Wiklander 813d3b0591SJens Wiklander /* 823d3b0591SJens Wiklander * Item in a verification chain: cert and flags for it 833d3b0591SJens Wiklander */ 843d3b0591SJens Wiklander typedef struct { 853d3b0591SJens Wiklander mbedtls_x509_crt *crt; 863d3b0591SJens Wiklander uint32_t flags; 873d3b0591SJens Wiklander } x509_crt_verify_chain_item; 883d3b0591SJens Wiklander 893d3b0591SJens Wiklander /* 903d3b0591SJens Wiklander * Max size of verification chain: end-entity + intermediates + trusted root 913d3b0591SJens Wiklander */ 923d3b0591SJens Wiklander #define X509_MAX_VERIFY_CHAIN_SIZE (MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2) 93817466cbSJens Wiklander 947901324dSJerome Forissier /* Default profile. Do not remove items unless there are serious security 957901324dSJerome Forissier * concerns. */ 96817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default = 97817466cbSJens Wiklander { 98*32b31808SJens Wiklander /* Hashes from SHA-256 and above. Note that this selection 99*32b31808SJens Wiklander * should be aligned with ssl_preset_default_hashes in ssl_tls.c. */ 100817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | 101817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | 102817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), 103817466cbSJens Wiklander 0xFFFFFFF, /* Any PK alg */ 104817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 105*32b31808SJens Wiklander /* Curves at or above 128-bit security level. Note that this selection 106*32b31808SJens Wiklander * should be aligned with ssl_preset_default_curves in ssl_tls.c. */ 107*32b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) | 108*32b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1) | 109*32b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP521R1) | 110*32b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP256R1) | 111*32b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP384R1) | 112*32b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP512R1) | 113*32b31808SJens Wiklander 0, 114*32b31808SJens Wiklander #else 115*32b31808SJens Wiklander 0, 116*32b31808SJens Wiklander #endif 117*32b31808SJens Wiklander 2048, 118*32b31808SJens Wiklander }; 119*32b31808SJens Wiklander 120*32b31808SJens Wiklander /* Next-generation profile. Currently identical to the default, but may 121*32b31808SJens Wiklander * be tightened at any time. */ 122*32b31808SJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next = 123*32b31808SJens Wiklander { 124*32b31808SJens Wiklander /* Hashes from SHA-256 and above. */ 125*32b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | 126*32b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | 127*32b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), 128*32b31808SJens Wiklander 0xFFFFFFF, /* Any PK alg */ 129*32b31808SJens Wiklander #if defined(MBEDTLS_ECP_C) 130*32b31808SJens Wiklander /* Curves at or above 128-bit security level. */ 131817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) | 132817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1) | 133817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP521R1) | 134817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP256R1) | 135817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP384R1) | 136817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP512R1) | 137817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256K1), 138817466cbSJens Wiklander #else 139817466cbSJens Wiklander 0, 140817466cbSJens Wiklander #endif 141817466cbSJens Wiklander 2048, 142817466cbSJens Wiklander }; 143817466cbSJens Wiklander 144817466cbSJens Wiklander /* 145817466cbSJens Wiklander * NSA Suite B Profile 146817466cbSJens Wiklander */ 147817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb = 148817466cbSJens Wiklander { 149817466cbSJens Wiklander /* Only SHA-256 and 384 */ 150817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | 151817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384), 152817466cbSJens Wiklander /* Only ECDSA */ 1533d3b0591SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECDSA) | 1543d3b0591SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECKEY), 155817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 156817466cbSJens Wiklander /* Only NIST P-256 and P-384 */ 157817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) | 158817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1), 159817466cbSJens Wiklander #else 160817466cbSJens Wiklander 0, 161817466cbSJens Wiklander #endif 162817466cbSJens Wiklander 0, 163817466cbSJens Wiklander }; 164817466cbSJens Wiklander 165817466cbSJens Wiklander /* 166*32b31808SJens Wiklander * Empty / all-forbidden profile 167*32b31808SJens Wiklander */ 168*32b31808SJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_none = 169*32b31808SJens Wiklander { 170*32b31808SJens Wiklander 0, 171*32b31808SJens Wiklander 0, 172*32b31808SJens Wiklander 0, 173*32b31808SJens Wiklander (uint32_t) -1, 174*32b31808SJens Wiklander }; 175*32b31808SJens Wiklander 176*32b31808SJens Wiklander /* 177817466cbSJens Wiklander * Check md_alg against profile 1783d3b0591SJens Wiklander * Return 0 if md_alg is acceptable for this profile, -1 otherwise 179817466cbSJens Wiklander */ 180817466cbSJens Wiklander static int x509_profile_check_md_alg(const mbedtls_x509_crt_profile *profile, 181817466cbSJens Wiklander mbedtls_md_type_t md_alg) 182817466cbSJens Wiklander { 183*32b31808SJens Wiklander if (md_alg == MBEDTLS_MD_NONE) { 184*32b31808SJens Wiklander return -1; 185*32b31808SJens Wiklander } 1863d3b0591SJens Wiklander 187*32b31808SJens Wiklander if ((profile->allowed_mds & MBEDTLS_X509_ID_FLAG(md_alg)) != 0) { 188*32b31808SJens Wiklander return 0; 189*32b31808SJens Wiklander } 190817466cbSJens Wiklander 191*32b31808SJens Wiklander return -1; 192817466cbSJens Wiklander } 193817466cbSJens Wiklander 194817466cbSJens Wiklander /* 195817466cbSJens Wiklander * Check pk_alg against profile 1963d3b0591SJens Wiklander * Return 0 if pk_alg is acceptable for this profile, -1 otherwise 197817466cbSJens Wiklander */ 198817466cbSJens Wiklander static int x509_profile_check_pk_alg(const mbedtls_x509_crt_profile *profile, 199817466cbSJens Wiklander mbedtls_pk_type_t pk_alg) 200817466cbSJens Wiklander { 201*32b31808SJens Wiklander if (pk_alg == MBEDTLS_PK_NONE) { 202*32b31808SJens Wiklander return -1; 203*32b31808SJens Wiklander } 2043d3b0591SJens Wiklander 205*32b31808SJens Wiklander if ((profile->allowed_pks & MBEDTLS_X509_ID_FLAG(pk_alg)) != 0) { 206*32b31808SJens Wiklander return 0; 207*32b31808SJens Wiklander } 208817466cbSJens Wiklander 209*32b31808SJens Wiklander return -1; 210817466cbSJens Wiklander } 211817466cbSJens Wiklander 212817466cbSJens Wiklander /* 213817466cbSJens Wiklander * Check key against profile 2143d3b0591SJens Wiklander * Return 0 if pk is acceptable for this profile, -1 otherwise 215817466cbSJens Wiklander */ 216817466cbSJens Wiklander static int x509_profile_check_key(const mbedtls_x509_crt_profile *profile, 217817466cbSJens Wiklander const mbedtls_pk_context *pk) 218817466cbSJens Wiklander { 2193d3b0591SJens Wiklander const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type(pk); 2203d3b0591SJens Wiklander 221817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 222*32b31808SJens Wiklander if (pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS) { 223*32b31808SJens Wiklander if (mbedtls_pk_get_bitlen(pk) >= profile->rsa_min_bitlen) { 224*32b31808SJens Wiklander return 0; 225*32b31808SJens Wiklander } 226817466cbSJens Wiklander 227*32b31808SJens Wiklander return -1; 228817466cbSJens Wiklander } 229817466cbSJens Wiklander #endif 230817466cbSJens Wiklander 231817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 232817466cbSJens Wiklander if (pk_alg == MBEDTLS_PK_ECDSA || 233817466cbSJens Wiklander pk_alg == MBEDTLS_PK_ECKEY || 234*32b31808SJens Wiklander pk_alg == MBEDTLS_PK_ECKEY_DH) { 2353d3b0591SJens Wiklander const mbedtls_ecp_group_id gid = mbedtls_pk_ec(*pk)->grp.id; 2363d3b0591SJens Wiklander 237*32b31808SJens Wiklander if (gid == MBEDTLS_ECP_DP_NONE) { 238*32b31808SJens Wiklander return -1; 239*32b31808SJens Wiklander } 240817466cbSJens Wiklander 241*32b31808SJens Wiklander if ((profile->allowed_curves & MBEDTLS_X509_ID_FLAG(gid)) != 0) { 242*32b31808SJens Wiklander return 0; 243*32b31808SJens Wiklander } 244817466cbSJens Wiklander 245*32b31808SJens Wiklander return -1; 246817466cbSJens Wiklander } 247817466cbSJens Wiklander #endif 248817466cbSJens Wiklander 249*32b31808SJens Wiklander return -1; 250817466cbSJens Wiklander } 251817466cbSJens Wiklander 252817466cbSJens Wiklander /* 2533d3b0591SJens Wiklander * Like memcmp, but case-insensitive and always returns -1 if different 2543d3b0591SJens Wiklander */ 2553d3b0591SJens Wiklander static int x509_memcasecmp(const void *s1, const void *s2, size_t len) 2563d3b0591SJens Wiklander { 2573d3b0591SJens Wiklander size_t i; 2583d3b0591SJens Wiklander unsigned char diff; 2593d3b0591SJens Wiklander const unsigned char *n1 = s1, *n2 = s2; 2603d3b0591SJens Wiklander 261*32b31808SJens Wiklander for (i = 0; i < len; i++) { 2623d3b0591SJens Wiklander diff = n1[i] ^ n2[i]; 2633d3b0591SJens Wiklander 264*32b31808SJens Wiklander if (diff == 0) { 2653d3b0591SJens Wiklander continue; 266*32b31808SJens Wiklander } 2673d3b0591SJens Wiklander 2683d3b0591SJens Wiklander if (diff == 32 && 2693d3b0591SJens Wiklander ((n1[i] >= 'a' && n1[i] <= 'z') || 270*32b31808SJens Wiklander (n1[i] >= 'A' && n1[i] <= 'Z'))) { 2713d3b0591SJens Wiklander continue; 2723d3b0591SJens Wiklander } 2733d3b0591SJens Wiklander 274*32b31808SJens Wiklander return -1; 2753d3b0591SJens Wiklander } 2763d3b0591SJens Wiklander 277*32b31808SJens Wiklander return 0; 2783d3b0591SJens Wiklander } 2793d3b0591SJens Wiklander 2803d3b0591SJens Wiklander /* 2813d3b0591SJens Wiklander * Return 0 if name matches wildcard, -1 otherwise 2823d3b0591SJens Wiklander */ 2833d3b0591SJens Wiklander static int x509_check_wildcard(const char *cn, const mbedtls_x509_buf *name) 2843d3b0591SJens Wiklander { 2853d3b0591SJens Wiklander size_t i; 2863d3b0591SJens Wiklander size_t cn_idx = 0, cn_len = strlen(cn); 2873d3b0591SJens Wiklander 2883d3b0591SJens Wiklander /* We can't have a match if there is no wildcard to match */ 289*32b31808SJens Wiklander if (name->len < 3 || name->p[0] != '*' || name->p[1] != '.') { 290*32b31808SJens Wiklander return -1; 291*32b31808SJens Wiklander } 2923d3b0591SJens Wiklander 293*32b31808SJens Wiklander for (i = 0; i < cn_len; ++i) { 294*32b31808SJens Wiklander if (cn[i] == '.') { 2953d3b0591SJens Wiklander cn_idx = i; 2963d3b0591SJens Wiklander break; 2973d3b0591SJens Wiklander } 2983d3b0591SJens Wiklander } 2993d3b0591SJens Wiklander 300*32b31808SJens Wiklander if (cn_idx == 0) { 301*32b31808SJens Wiklander return -1; 3023d3b0591SJens Wiklander } 3033d3b0591SJens Wiklander 304*32b31808SJens Wiklander if (cn_len - cn_idx == name->len - 1 && 305*32b31808SJens Wiklander x509_memcasecmp(name->p + 1, cn + cn_idx, name->len - 1) == 0) { 306*32b31808SJens Wiklander return 0; 307*32b31808SJens Wiklander } 308*32b31808SJens Wiklander 309*32b31808SJens Wiklander return -1; 3103d3b0591SJens Wiklander } 3113d3b0591SJens Wiklander 3123d3b0591SJens Wiklander /* 3133d3b0591SJens Wiklander * Compare two X.509 strings, case-insensitive, and allowing for some encoding 3143d3b0591SJens Wiklander * variations (but not all). 3153d3b0591SJens Wiklander * 3163d3b0591SJens Wiklander * Return 0 if equal, -1 otherwise. 3173d3b0591SJens Wiklander */ 3183d3b0591SJens Wiklander static int x509_string_cmp(const mbedtls_x509_buf *a, const mbedtls_x509_buf *b) 3193d3b0591SJens Wiklander { 3203d3b0591SJens Wiklander if (a->tag == b->tag && 3213d3b0591SJens Wiklander a->len == b->len && 322*32b31808SJens Wiklander memcmp(a->p, b->p, b->len) == 0) { 323*32b31808SJens Wiklander return 0; 3243d3b0591SJens Wiklander } 3253d3b0591SJens Wiklander 3263d3b0591SJens Wiklander if ((a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING) && 3273d3b0591SJens Wiklander (b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING) && 3283d3b0591SJens Wiklander a->len == b->len && 329*32b31808SJens Wiklander x509_memcasecmp(a->p, b->p, b->len) == 0) { 330*32b31808SJens Wiklander return 0; 3313d3b0591SJens Wiklander } 3323d3b0591SJens Wiklander 333*32b31808SJens Wiklander return -1; 3343d3b0591SJens Wiklander } 3353d3b0591SJens Wiklander 3363d3b0591SJens Wiklander /* 3373d3b0591SJens Wiklander * Compare two X.509 Names (aka rdnSequence). 3383d3b0591SJens Wiklander * 3393d3b0591SJens Wiklander * See RFC 5280 section 7.1, though we don't implement the whole algorithm: 3403d3b0591SJens Wiklander * we sometimes return unequal when the full algorithm would return equal, 3413d3b0591SJens Wiklander * but never the other way. (In particular, we don't do Unicode normalisation 3423d3b0591SJens Wiklander * or space folding.) 3433d3b0591SJens Wiklander * 3443d3b0591SJens Wiklander * Return 0 if equal, -1 otherwise. 3453d3b0591SJens Wiklander */ 3463d3b0591SJens Wiklander static int x509_name_cmp(const mbedtls_x509_name *a, const mbedtls_x509_name *b) 3473d3b0591SJens Wiklander { 3483d3b0591SJens Wiklander /* Avoid recursion, it might not be optimised by the compiler */ 349*32b31808SJens Wiklander while (a != NULL || b != NULL) { 350*32b31808SJens Wiklander if (a == NULL || b == NULL) { 351*32b31808SJens Wiklander return -1; 352*32b31808SJens Wiklander } 3533d3b0591SJens Wiklander 3543d3b0591SJens Wiklander /* type */ 3553d3b0591SJens Wiklander if (a->oid.tag != b->oid.tag || 3563d3b0591SJens Wiklander a->oid.len != b->oid.len || 357*32b31808SJens Wiklander memcmp(a->oid.p, b->oid.p, b->oid.len) != 0) { 358*32b31808SJens Wiklander return -1; 3593d3b0591SJens Wiklander } 3603d3b0591SJens Wiklander 3613d3b0591SJens Wiklander /* value */ 362*32b31808SJens Wiklander if (x509_string_cmp(&a->val, &b->val) != 0) { 363*32b31808SJens Wiklander return -1; 364*32b31808SJens Wiklander } 3653d3b0591SJens Wiklander 3663d3b0591SJens Wiklander /* structure of the list of sets */ 367*32b31808SJens Wiklander if (a->next_merged != b->next_merged) { 368*32b31808SJens Wiklander return -1; 369*32b31808SJens Wiklander } 3703d3b0591SJens Wiklander 3713d3b0591SJens Wiklander a = a->next; 3723d3b0591SJens Wiklander b = b->next; 3733d3b0591SJens Wiklander } 3743d3b0591SJens Wiklander 3753d3b0591SJens Wiklander /* a == NULL == b */ 376*32b31808SJens Wiklander return 0; 3773d3b0591SJens Wiklander } 3783d3b0591SJens Wiklander 3793d3b0591SJens Wiklander /* 3803d3b0591SJens Wiklander * Reset (init or clear) a verify_chain 3813d3b0591SJens Wiklander */ 3823d3b0591SJens Wiklander static void x509_crt_verify_chain_reset( 3833d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain *ver_chain) 3843d3b0591SJens Wiklander { 3853d3b0591SJens Wiklander size_t i; 3863d3b0591SJens Wiklander 387*32b31808SJens Wiklander for (i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++) { 3883d3b0591SJens Wiklander ver_chain->items[i].crt = NULL; 3895b25c76aSJerome Forissier ver_chain->items[i].flags = (uint32_t) -1; 3903d3b0591SJens Wiklander } 3913d3b0591SJens Wiklander 3923d3b0591SJens Wiklander ver_chain->len = 0; 39311fa71b9SJerome Forissier 39411fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 39511fa71b9SJerome Forissier ver_chain->trust_ca_cb_result = NULL; 39611fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 3973d3b0591SJens Wiklander } 3983d3b0591SJens Wiklander 3993d3b0591SJens Wiklander /* 400817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 401817466cbSJens Wiklander */ 402817466cbSJens Wiklander static int x509_get_version(unsigned char **p, 403817466cbSJens Wiklander const unsigned char *end, 404817466cbSJens Wiklander int *ver) 405817466cbSJens Wiklander { 40611fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 407817466cbSJens Wiklander size_t len; 408817466cbSJens Wiklander 409817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 410*32b31808SJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 411*32b31808SJens Wiklander 0)) != 0) { 412*32b31808SJens Wiklander if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 413817466cbSJens Wiklander *ver = 0; 414*32b31808SJens Wiklander return 0; 415817466cbSJens Wiklander } 416817466cbSJens Wiklander 417*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 418817466cbSJens Wiklander } 419817466cbSJens Wiklander 420817466cbSJens Wiklander end = *p + len; 421817466cbSJens Wiklander 422*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_int(p, end, ver)) != 0) { 423*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_VERSION, ret); 424*32b31808SJens Wiklander } 425817466cbSJens Wiklander 426*32b31808SJens Wiklander if (*p != end) { 427*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_VERSION, 428*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 429*32b31808SJens Wiklander } 430817466cbSJens Wiklander 431*32b31808SJens Wiklander return 0; 432817466cbSJens Wiklander } 433817466cbSJens Wiklander 434817466cbSJens Wiklander /* 435817466cbSJens Wiklander * Validity ::= SEQUENCE { 436817466cbSJens Wiklander * notBefore Time, 437817466cbSJens Wiklander * notAfter Time } 438817466cbSJens Wiklander */ 439817466cbSJens Wiklander static int x509_get_dates(unsigned char **p, 440817466cbSJens Wiklander const unsigned char *end, 441817466cbSJens Wiklander mbedtls_x509_time *from, 442817466cbSJens Wiklander mbedtls_x509_time *to) 443817466cbSJens Wiklander { 44411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 445817466cbSJens Wiklander size_t len; 446817466cbSJens Wiklander 447817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 448*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 449*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_DATE, ret); 450*32b31808SJens Wiklander } 451817466cbSJens Wiklander 452817466cbSJens Wiklander end = *p + len; 453817466cbSJens Wiklander 454*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_time(p, end, from)) != 0) { 455*32b31808SJens Wiklander return ret; 456*32b31808SJens Wiklander } 457817466cbSJens Wiklander 458*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_time(p, end, to)) != 0) { 459*32b31808SJens Wiklander return ret; 460*32b31808SJens Wiklander } 461817466cbSJens Wiklander 462*32b31808SJens Wiklander if (*p != end) { 463*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_DATE, 464*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 465*32b31808SJens Wiklander } 466817466cbSJens Wiklander 467*32b31808SJens Wiklander return 0; 468817466cbSJens Wiklander } 469817466cbSJens Wiklander 470817466cbSJens Wiklander /* 471817466cbSJens Wiklander * X.509 v2/v3 unique identifier (not parsed) 472817466cbSJens Wiklander */ 473817466cbSJens Wiklander static int x509_get_uid(unsigned char **p, 474817466cbSJens Wiklander const unsigned char *end, 475817466cbSJens Wiklander mbedtls_x509_buf *uid, int n) 476817466cbSJens Wiklander { 47711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 478817466cbSJens Wiklander 479*32b31808SJens Wiklander if (*p == end) { 480*32b31808SJens Wiklander return 0; 481*32b31808SJens Wiklander } 482817466cbSJens Wiklander 483817466cbSJens Wiklander uid->tag = **p; 484817466cbSJens Wiklander 485817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &uid->len, 486*32b31808SJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 487*32b31808SJens Wiklander n)) != 0) { 488*32b31808SJens Wiklander if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 489*32b31808SJens Wiklander return 0; 490*32b31808SJens Wiklander } 491817466cbSJens Wiklander 492*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 493817466cbSJens Wiklander } 494817466cbSJens Wiklander 495817466cbSJens Wiklander uid->p = *p; 496817466cbSJens Wiklander *p += uid->len; 497817466cbSJens Wiklander 498*32b31808SJens Wiklander return 0; 499817466cbSJens Wiklander } 500817466cbSJens Wiklander 501817466cbSJens Wiklander static int x509_get_basic_constraints(unsigned char **p, 502817466cbSJens Wiklander const unsigned char *end, 503817466cbSJens Wiklander int *ca_istrue, 504817466cbSJens Wiklander int *max_pathlen) 505817466cbSJens Wiklander { 50611fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 507817466cbSJens Wiklander size_t len; 508817466cbSJens Wiklander 509817466cbSJens Wiklander /* 510817466cbSJens Wiklander * BasicConstraints ::= SEQUENCE { 511817466cbSJens Wiklander * cA BOOLEAN DEFAULT FALSE, 512817466cbSJens Wiklander * pathLenConstraint INTEGER (0..MAX) OPTIONAL } 513817466cbSJens Wiklander */ 514817466cbSJens Wiklander *ca_istrue = 0; /* DEFAULT FALSE */ 515817466cbSJens Wiklander *max_pathlen = 0; /* endless */ 516817466cbSJens Wiklander 517817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 518*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 519*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 520817466cbSJens Wiklander } 521817466cbSJens Wiklander 522*32b31808SJens Wiklander if (*p == end) { 523*32b31808SJens Wiklander return 0; 524*32b31808SJens Wiklander } 525817466cbSJens Wiklander 526*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_bool(p, end, ca_istrue)) != 0) { 527*32b31808SJens Wiklander if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 528*32b31808SJens Wiklander ret = mbedtls_asn1_get_int(p, end, ca_istrue); 529*32b31808SJens Wiklander } 530817466cbSJens Wiklander 531*32b31808SJens Wiklander if (ret != 0) { 532*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 533*32b31808SJens Wiklander } 534*32b31808SJens Wiklander 535*32b31808SJens Wiklander if (*ca_istrue != 0) { 536*32b31808SJens Wiklander *ca_istrue = 1; 537*32b31808SJens Wiklander } 538*32b31808SJens Wiklander } 539*32b31808SJens Wiklander 540*32b31808SJens Wiklander if (*p == end) { 541*32b31808SJens Wiklander return 0; 542*32b31808SJens Wiklander } 543*32b31808SJens Wiklander 544*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_int(p, end, max_pathlen)) != 0) { 545*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 546*32b31808SJens Wiklander } 547*32b31808SJens Wiklander 548*32b31808SJens Wiklander if (*p != end) { 549*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 550*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 551*32b31808SJens Wiklander } 5527901324dSJerome Forissier 5537901324dSJerome Forissier /* Do not accept max_pathlen equal to INT_MAX to avoid a signed integer 5547901324dSJerome Forissier * overflow, which is an undefined behavior. */ 555*32b31808SJens Wiklander if (*max_pathlen == INT_MAX) { 556*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 557*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH); 558*32b31808SJens Wiklander } 559817466cbSJens Wiklander 560817466cbSJens Wiklander (*max_pathlen)++; 561817466cbSJens Wiklander 562*32b31808SJens Wiklander return 0; 563817466cbSJens Wiklander } 564817466cbSJens Wiklander 565817466cbSJens Wiklander /* 566817466cbSJens Wiklander * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId 567817466cbSJens Wiklander * 568817466cbSJens Wiklander * KeyPurposeId ::= OBJECT IDENTIFIER 569817466cbSJens Wiklander */ 570817466cbSJens Wiklander static int x509_get_ext_key_usage(unsigned char **p, 571817466cbSJens Wiklander const unsigned char *end, 572817466cbSJens Wiklander mbedtls_x509_sequence *ext_key_usage) 573817466cbSJens Wiklander { 57411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 575817466cbSJens Wiklander 576*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_sequence_of(p, end, ext_key_usage, MBEDTLS_ASN1_OID)) != 0) { 577*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 578*32b31808SJens Wiklander } 579817466cbSJens Wiklander 580817466cbSJens Wiklander /* Sequence length must be >= 1 */ 581*32b31808SJens Wiklander if (ext_key_usage->buf.p == NULL) { 582*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 583*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH); 584817466cbSJens Wiklander } 585817466cbSJens Wiklander 586*32b31808SJens Wiklander return 0; 587817466cbSJens Wiklander } 588817466cbSJens Wiklander 589817466cbSJens Wiklander /* 59011fa71b9SJerome Forissier * id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } 59111fa71b9SJerome Forissier * 59211fa71b9SJerome Forissier * anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 } 59311fa71b9SJerome Forissier * 59411fa71b9SJerome Forissier * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation 59511fa71b9SJerome Forissier * 59611fa71b9SJerome Forissier * PolicyInformation ::= SEQUENCE { 59711fa71b9SJerome Forissier * policyIdentifier CertPolicyId, 59811fa71b9SJerome Forissier * policyQualifiers SEQUENCE SIZE (1..MAX) OF 59911fa71b9SJerome Forissier * PolicyQualifierInfo OPTIONAL } 60011fa71b9SJerome Forissier * 60111fa71b9SJerome Forissier * CertPolicyId ::= OBJECT IDENTIFIER 60211fa71b9SJerome Forissier * 60311fa71b9SJerome Forissier * PolicyQualifierInfo ::= SEQUENCE { 60411fa71b9SJerome Forissier * policyQualifierId PolicyQualifierId, 60511fa71b9SJerome Forissier * qualifier ANY DEFINED BY policyQualifierId } 60611fa71b9SJerome Forissier * 60711fa71b9SJerome Forissier * -- policyQualifierIds for Internet policy qualifiers 60811fa71b9SJerome Forissier * 60911fa71b9SJerome Forissier * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 } 61011fa71b9SJerome Forissier * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 } 61111fa71b9SJerome Forissier * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 } 61211fa71b9SJerome Forissier * 61311fa71b9SJerome Forissier * PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ) 61411fa71b9SJerome Forissier * 61511fa71b9SJerome Forissier * Qualifier ::= CHOICE { 61611fa71b9SJerome Forissier * cPSuri CPSuri, 61711fa71b9SJerome Forissier * userNotice UserNotice } 61811fa71b9SJerome Forissier * 61911fa71b9SJerome Forissier * CPSuri ::= IA5String 62011fa71b9SJerome Forissier * 62111fa71b9SJerome Forissier * UserNotice ::= SEQUENCE { 62211fa71b9SJerome Forissier * noticeRef NoticeReference OPTIONAL, 62311fa71b9SJerome Forissier * explicitText DisplayText OPTIONAL } 62411fa71b9SJerome Forissier * 62511fa71b9SJerome Forissier * NoticeReference ::= SEQUENCE { 62611fa71b9SJerome Forissier * organization DisplayText, 62711fa71b9SJerome Forissier * noticeNumbers SEQUENCE OF INTEGER } 62811fa71b9SJerome Forissier * 62911fa71b9SJerome Forissier * DisplayText ::= CHOICE { 63011fa71b9SJerome Forissier * ia5String IA5String (SIZE (1..200)), 63111fa71b9SJerome Forissier * visibleString VisibleString (SIZE (1..200)), 63211fa71b9SJerome Forissier * bmpString BMPString (SIZE (1..200)), 63311fa71b9SJerome Forissier * utf8String UTF8String (SIZE (1..200)) } 63411fa71b9SJerome Forissier * 63511fa71b9SJerome Forissier * NOTE: we only parse and use anyPolicy without qualifiers at this point 63611fa71b9SJerome Forissier * as defined in RFC 5280. 63711fa71b9SJerome Forissier */ 63811fa71b9SJerome Forissier static int x509_get_certificate_policies(unsigned char **p, 63911fa71b9SJerome Forissier const unsigned char *end, 64011fa71b9SJerome Forissier mbedtls_x509_sequence *certificate_policies) 64111fa71b9SJerome Forissier { 64211fa71b9SJerome Forissier int ret, parse_ret = 0; 64311fa71b9SJerome Forissier size_t len; 64411fa71b9SJerome Forissier mbedtls_asn1_buf *buf; 64511fa71b9SJerome Forissier mbedtls_asn1_sequence *cur = certificate_policies; 64611fa71b9SJerome Forissier 64711fa71b9SJerome Forissier /* Get main sequence tag */ 64811fa71b9SJerome Forissier ret = mbedtls_asn1_get_tag(p, end, &len, 64911fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); 650*32b31808SJens Wiklander if (ret != 0) { 651*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 652*32b31808SJens Wiklander } 65311fa71b9SJerome Forissier 654*32b31808SJens Wiklander if (*p + len != end) { 655*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 656*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 657*32b31808SJens Wiklander } 65811fa71b9SJerome Forissier 65911fa71b9SJerome Forissier /* 66011fa71b9SJerome Forissier * Cannot be an empty sequence. 66111fa71b9SJerome Forissier */ 662*32b31808SJens Wiklander if (len == 0) { 663*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 664*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 665*32b31808SJens Wiklander } 66611fa71b9SJerome Forissier 667*32b31808SJens Wiklander while (*p < end) { 66811fa71b9SJerome Forissier mbedtls_x509_buf policy_oid; 66911fa71b9SJerome Forissier const unsigned char *policy_end; 67011fa71b9SJerome Forissier 67111fa71b9SJerome Forissier /* 67211fa71b9SJerome Forissier * Get the policy sequence 67311fa71b9SJerome Forissier */ 67411fa71b9SJerome Forissier if ((ret = mbedtls_asn1_get_tag(p, end, &len, 675*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 676*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 677*32b31808SJens Wiklander } 67811fa71b9SJerome Forissier 67911fa71b9SJerome Forissier policy_end = *p + len; 68011fa71b9SJerome Forissier 68111fa71b9SJerome Forissier if ((ret = mbedtls_asn1_get_tag(p, policy_end, &len, 682*32b31808SJens Wiklander MBEDTLS_ASN1_OID)) != 0) { 683*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 684*32b31808SJens Wiklander } 68511fa71b9SJerome Forissier 68611fa71b9SJerome Forissier policy_oid.tag = MBEDTLS_ASN1_OID; 68711fa71b9SJerome Forissier policy_oid.len = len; 68811fa71b9SJerome Forissier policy_oid.p = *p; 68911fa71b9SJerome Forissier 69011fa71b9SJerome Forissier /* 69111fa71b9SJerome Forissier * Only AnyPolicy is currently supported when enforcing policy. 69211fa71b9SJerome Forissier */ 693*32b31808SJens Wiklander if (MBEDTLS_OID_CMP(MBEDTLS_OID_ANY_POLICY, &policy_oid) != 0) { 69411fa71b9SJerome Forissier /* 69511fa71b9SJerome Forissier * Set the parsing return code but continue parsing, in case this 696*32b31808SJens Wiklander * extension is critical. 69711fa71b9SJerome Forissier */ 69811fa71b9SJerome Forissier parse_ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; 69911fa71b9SJerome Forissier } 70011fa71b9SJerome Forissier 70111fa71b9SJerome Forissier /* Allocate and assign next pointer */ 702*32b31808SJens Wiklander if (cur->buf.p != NULL) { 703*32b31808SJens Wiklander if (cur->next != NULL) { 704*32b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_EXTENSIONS; 705*32b31808SJens Wiklander } 70611fa71b9SJerome Forissier 70711fa71b9SJerome Forissier cur->next = mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence)); 70811fa71b9SJerome Forissier 709*32b31808SJens Wiklander if (cur->next == NULL) { 710*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 711*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_ALLOC_FAILED); 712*32b31808SJens Wiklander } 71311fa71b9SJerome Forissier 71411fa71b9SJerome Forissier cur = cur->next; 71511fa71b9SJerome Forissier } 71611fa71b9SJerome Forissier 71711fa71b9SJerome Forissier buf = &(cur->buf); 71811fa71b9SJerome Forissier buf->tag = policy_oid.tag; 71911fa71b9SJerome Forissier buf->p = policy_oid.p; 72011fa71b9SJerome Forissier buf->len = policy_oid.len; 72111fa71b9SJerome Forissier 72211fa71b9SJerome Forissier *p += len; 72311fa71b9SJerome Forissier 72411fa71b9SJerome Forissier /* 72511fa71b9SJerome Forissier * If there is an optional qualifier, then *p < policy_end 72611fa71b9SJerome Forissier * Check the Qualifier len to verify it doesn't exceed policy_end. 72711fa71b9SJerome Forissier */ 728*32b31808SJens Wiklander if (*p < policy_end) { 72911fa71b9SJerome Forissier if ((ret = mbedtls_asn1_get_tag(p, policy_end, &len, 730*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 731*32b31808SJens Wiklander 0) { 732*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 733*32b31808SJens Wiklander } 73411fa71b9SJerome Forissier /* 73511fa71b9SJerome Forissier * Skip the optional policy qualifiers. 73611fa71b9SJerome Forissier */ 73711fa71b9SJerome Forissier *p += len; 73811fa71b9SJerome Forissier } 73911fa71b9SJerome Forissier 740*32b31808SJens Wiklander if (*p != policy_end) { 741*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 742*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 743*32b31808SJens Wiklander } 74411fa71b9SJerome Forissier } 74511fa71b9SJerome Forissier 74611fa71b9SJerome Forissier /* Set final sequence entry's next pointer to NULL */ 74711fa71b9SJerome Forissier cur->next = NULL; 74811fa71b9SJerome Forissier 749*32b31808SJens Wiklander if (*p != end) { 750*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 751*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 752*32b31808SJens Wiklander } 75311fa71b9SJerome Forissier 754*32b31808SJens Wiklander return parse_ret; 75511fa71b9SJerome Forissier } 75611fa71b9SJerome Forissier 75711fa71b9SJerome Forissier /* 758817466cbSJens Wiklander * X.509 v3 extensions 759817466cbSJens Wiklander * 760817466cbSJens Wiklander */ 761817466cbSJens Wiklander static int x509_get_crt_ext(unsigned char **p, 762817466cbSJens Wiklander const unsigned char *end, 7637901324dSJerome Forissier mbedtls_x509_crt *crt, 7647901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 7657901324dSJerome Forissier void *p_ctx) 766817466cbSJens Wiklander { 76711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 768817466cbSJens Wiklander size_t len; 7697901324dSJerome Forissier unsigned char *end_ext_data, *start_ext_octet, *end_ext_octet; 770817466cbSJens Wiklander 771*32b31808SJens Wiklander if (*p == end) { 772*32b31808SJens Wiklander return 0; 773*32b31808SJens Wiklander } 774817466cbSJens Wiklander 775*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_ext(p, end, &crt->v3_ext, 3)) != 0) { 776*32b31808SJens Wiklander return ret; 777*32b31808SJens Wiklander } 778817466cbSJens Wiklander 7795b25c76aSJerome Forissier end = crt->v3_ext.p + crt->v3_ext.len; 780*32b31808SJens Wiklander while (*p < end) { 781817466cbSJens Wiklander /* 782817466cbSJens Wiklander * Extension ::= SEQUENCE { 783817466cbSJens Wiklander * extnID OBJECT IDENTIFIER, 784817466cbSJens Wiklander * critical BOOLEAN DEFAULT FALSE, 785817466cbSJens Wiklander * extnValue OCTET STRING } 786817466cbSJens Wiklander */ 787817466cbSJens Wiklander mbedtls_x509_buf extn_oid = { 0, 0, NULL }; 788817466cbSJens Wiklander int is_critical = 0; /* DEFAULT FALSE */ 789817466cbSJens Wiklander int ext_type = 0; 790817466cbSJens Wiklander 791817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 792*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 793*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 794*32b31808SJens Wiklander } 795817466cbSJens Wiklander 796817466cbSJens Wiklander end_ext_data = *p + len; 797817466cbSJens Wiklander 798817466cbSJens Wiklander /* Get extension ID */ 7993d3b0591SJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &extn_oid.len, 800*32b31808SJens Wiklander MBEDTLS_ASN1_OID)) != 0) { 801*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 802*32b31808SJens Wiklander } 803817466cbSJens Wiklander 8043d3b0591SJens Wiklander extn_oid.tag = MBEDTLS_ASN1_OID; 805817466cbSJens Wiklander extn_oid.p = *p; 806817466cbSJens Wiklander *p += extn_oid.len; 807817466cbSJens Wiklander 808817466cbSJens Wiklander /* Get optional critical */ 809817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_bool(p, end_ext_data, &is_critical)) != 0 && 810*32b31808SJens Wiklander (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) { 811*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 812*32b31808SJens Wiklander } 813817466cbSJens Wiklander 814817466cbSJens Wiklander /* Data should be octet string type */ 815817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &len, 816*32b31808SJens Wiklander MBEDTLS_ASN1_OCTET_STRING)) != 0) { 817*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 818*32b31808SJens Wiklander } 819817466cbSJens Wiklander 8207901324dSJerome Forissier start_ext_octet = *p; 821817466cbSJens Wiklander end_ext_octet = *p + len; 822817466cbSJens Wiklander 823*32b31808SJens Wiklander if (end_ext_octet != end_ext_data) { 824*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 825*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 826*32b31808SJens Wiklander } 827817466cbSJens Wiklander 828817466cbSJens Wiklander /* 829817466cbSJens Wiklander * Detect supported extensions 830817466cbSJens Wiklander */ 831817466cbSJens Wiklander ret = mbedtls_oid_get_x509_ext_type(&extn_oid, &ext_type); 832817466cbSJens Wiklander 833*32b31808SJens Wiklander if (ret != 0) { 8347901324dSJerome Forissier /* Give the callback (if any) a chance to handle the extension */ 835*32b31808SJens Wiklander if (cb != NULL) { 8367901324dSJerome Forissier ret = cb(p_ctx, crt, &extn_oid, is_critical, *p, end_ext_octet); 837*32b31808SJens Wiklander if (ret != 0 && is_critical) { 838*32b31808SJens Wiklander return ret; 839*32b31808SJens Wiklander } 8407901324dSJerome Forissier *p = end_ext_octet; 8417901324dSJerome Forissier continue; 8427901324dSJerome Forissier } 8437901324dSJerome Forissier 844817466cbSJens Wiklander /* No parser found, skip extension */ 845817466cbSJens Wiklander *p = end_ext_octet; 846817466cbSJens Wiklander 847*32b31808SJens Wiklander if (is_critical) { 848817466cbSJens Wiklander /* Data is marked as critical: fail */ 849*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 850*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG); 851817466cbSJens Wiklander } 852817466cbSJens Wiklander continue; 853817466cbSJens Wiklander } 854817466cbSJens Wiklander 855817466cbSJens Wiklander /* Forbid repeated extensions */ 856*32b31808SJens Wiklander if ((crt->ext_types & ext_type) != 0) { 857*32b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_EXTENSIONS; 858*32b31808SJens Wiklander } 859817466cbSJens Wiklander 860817466cbSJens Wiklander crt->ext_types |= ext_type; 861817466cbSJens Wiklander 862*32b31808SJens Wiklander switch (ext_type) { 863817466cbSJens Wiklander case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS: 864817466cbSJens Wiklander /* Parse basic constraints */ 865817466cbSJens Wiklander if ((ret = x509_get_basic_constraints(p, end_ext_octet, 866*32b31808SJens Wiklander &crt->ca_istrue, &crt->max_pathlen)) != 0) { 867*32b31808SJens Wiklander return ret; 868*32b31808SJens Wiklander } 869817466cbSJens Wiklander break; 870817466cbSJens Wiklander 871817466cbSJens Wiklander case MBEDTLS_X509_EXT_KEY_USAGE: 872817466cbSJens Wiklander /* Parse key usage */ 873*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_key_usage(p, end_ext_octet, 874*32b31808SJens Wiklander &crt->key_usage)) != 0) { 875*32b31808SJens Wiklander return ret; 876*32b31808SJens Wiklander } 877817466cbSJens Wiklander break; 878817466cbSJens Wiklander 879817466cbSJens Wiklander case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: 880817466cbSJens Wiklander /* Parse extended key usage */ 881817466cbSJens Wiklander if ((ret = x509_get_ext_key_usage(p, end_ext_octet, 882*32b31808SJens Wiklander &crt->ext_key_usage)) != 0) { 883*32b31808SJens Wiklander return ret; 884*32b31808SJens Wiklander } 885817466cbSJens Wiklander break; 886817466cbSJens Wiklander 887817466cbSJens Wiklander case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME: 888817466cbSJens Wiklander /* Parse subject alt name */ 889*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_subject_alt_name(p, end_ext_octet, 890*32b31808SJens Wiklander &crt->subject_alt_names)) != 0) { 891*32b31808SJens Wiklander return ret; 892*32b31808SJens Wiklander } 893817466cbSJens Wiklander break; 894817466cbSJens Wiklander 895817466cbSJens Wiklander case MBEDTLS_X509_EXT_NS_CERT_TYPE: 896817466cbSJens Wiklander /* Parse netscape certificate type */ 897*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_ns_cert_type(p, end_ext_octet, 898*32b31808SJens Wiklander &crt->ns_cert_type)) != 0) { 899*32b31808SJens Wiklander return ret; 900*32b31808SJens Wiklander } 901817466cbSJens Wiklander break; 902817466cbSJens Wiklander 90311fa71b9SJerome Forissier case MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES: 90411fa71b9SJerome Forissier /* Parse certificate policies type */ 90511fa71b9SJerome Forissier if ((ret = x509_get_certificate_policies(p, end_ext_octet, 906*32b31808SJens Wiklander &crt->certificate_policies)) != 0) { 9077901324dSJerome Forissier /* Give the callback (if any) a chance to handle the extension 9087901324dSJerome Forissier * if it contains unsupported policies */ 9097901324dSJerome Forissier if (ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE && cb != NULL && 9107901324dSJerome Forissier cb(p_ctx, crt, &extn_oid, is_critical, 911*32b31808SJens Wiklander start_ext_octet, end_ext_octet) == 0) { 9127901324dSJerome Forissier break; 913*32b31808SJens Wiklander } 9147901324dSJerome Forissier 915*32b31808SJens Wiklander if (is_critical) { 916*32b31808SJens Wiklander return ret; 917*32b31808SJens Wiklander } else 91811fa71b9SJerome Forissier /* 91911fa71b9SJerome Forissier * If MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, then we 92011fa71b9SJerome Forissier * cannot interpret or enforce the policy. However, it is up to 92111fa71b9SJerome Forissier * the user to choose how to enforce the policies, 92211fa71b9SJerome Forissier * unless the extension is critical. 92311fa71b9SJerome Forissier */ 924*32b31808SJens Wiklander if (ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) { 925*32b31808SJens Wiklander return ret; 926*32b31808SJens Wiklander } 92711fa71b9SJerome Forissier } 92811fa71b9SJerome Forissier break; 92911fa71b9SJerome Forissier 930817466cbSJens Wiklander default: 93111fa71b9SJerome Forissier /* 93211fa71b9SJerome Forissier * If this is a non-critical extension, which the oid layer 93311fa71b9SJerome Forissier * supports, but there isn't an x509 parser for it, 93411fa71b9SJerome Forissier * skip the extension. 93511fa71b9SJerome Forissier */ 936*32b31808SJens Wiklander if (is_critical) { 937*32b31808SJens Wiklander return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; 938*32b31808SJens Wiklander } else { 93911fa71b9SJerome Forissier *p = end_ext_octet; 940817466cbSJens Wiklander } 941817466cbSJens Wiklander } 942*32b31808SJens Wiklander } 943817466cbSJens Wiklander 944*32b31808SJens Wiklander if (*p != end) { 945*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 946*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 947*32b31808SJens Wiklander } 948817466cbSJens Wiklander 949*32b31808SJens Wiklander return 0; 950817466cbSJens Wiklander } 951817466cbSJens Wiklander 952817466cbSJens Wiklander /* 953817466cbSJens Wiklander * Parse and fill a single X.509 certificate in DER format 954817466cbSJens Wiklander */ 95511fa71b9SJerome Forissier static int x509_crt_parse_der_core(mbedtls_x509_crt *crt, 95611fa71b9SJerome Forissier const unsigned char *buf, 95711fa71b9SJerome Forissier size_t buflen, 9587901324dSJerome Forissier int make_copy, 9597901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 9607901324dSJerome Forissier void *p_ctx) 961817466cbSJens Wiklander { 96211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 963817466cbSJens Wiklander size_t len; 964817466cbSJens Wiklander unsigned char *p, *end, *crt_end; 965817466cbSJens Wiklander mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; 966817466cbSJens Wiklander 967817466cbSJens Wiklander memset(&sig_params1, 0, sizeof(mbedtls_x509_buf)); 968817466cbSJens Wiklander memset(&sig_params2, 0, sizeof(mbedtls_x509_buf)); 969817466cbSJens Wiklander memset(&sig_oid2, 0, sizeof(mbedtls_x509_buf)); 970817466cbSJens Wiklander 971817466cbSJens Wiklander /* 972817466cbSJens Wiklander * Check for valid input 973817466cbSJens Wiklander */ 974*32b31808SJens Wiklander if (crt == NULL || buf == NULL) { 975*32b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 976*32b31808SJens Wiklander } 977817466cbSJens Wiklander 97811fa71b9SJerome Forissier /* Use the original buffer until we figure out actual length. */ 979817466cbSJens Wiklander p = (unsigned char *) buf; 980817466cbSJens Wiklander len = buflen; 981817466cbSJens Wiklander end = p + len; 982817466cbSJens Wiklander 983817466cbSJens Wiklander /* 984817466cbSJens Wiklander * Certificate ::= SEQUENCE { 985817466cbSJens Wiklander * tbsCertificate TBSCertificate, 986817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 987817466cbSJens Wiklander * signatureValue BIT STRING } 988817466cbSJens Wiklander */ 989817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 990*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 991817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 992*32b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_FORMAT; 993817466cbSJens Wiklander } 994817466cbSJens Wiklander 99511fa71b9SJerome Forissier end = crt_end = p + len; 996817466cbSJens Wiklander crt->raw.len = crt_end - buf; 997*32b31808SJens Wiklander if (make_copy != 0) { 99811fa71b9SJerome Forissier /* Create and populate a new buffer for the raw field. */ 999817466cbSJens Wiklander crt->raw.p = p = mbedtls_calloc(1, crt->raw.len); 1000*32b31808SJens Wiklander if (crt->raw.p == NULL) { 1001*32b31808SJens Wiklander return MBEDTLS_ERR_X509_ALLOC_FAILED; 1002*32b31808SJens Wiklander } 1003817466cbSJens Wiklander 100411fa71b9SJerome Forissier memcpy(crt->raw.p, buf, crt->raw.len); 100511fa71b9SJerome Forissier crt->own_buffer = 1; 1006817466cbSJens Wiklander 1007817466cbSJens Wiklander p += crt->raw.len - len; 1008817466cbSJens Wiklander end = crt_end = p + len; 1009*32b31808SJens Wiklander } else { 101011fa71b9SJerome Forissier crt->raw.p = (unsigned char *) buf; 101111fa71b9SJerome Forissier crt->own_buffer = 0; 101211fa71b9SJerome Forissier } 1013817466cbSJens Wiklander 1014817466cbSJens Wiklander /* 1015817466cbSJens Wiklander * TBSCertificate ::= SEQUENCE { 1016817466cbSJens Wiklander */ 1017817466cbSJens Wiklander crt->tbs.p = p; 1018817466cbSJens Wiklander 1019817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 1020*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 1021817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1022*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 1023817466cbSJens Wiklander } 1024817466cbSJens Wiklander 1025817466cbSJens Wiklander end = p + len; 1026817466cbSJens Wiklander crt->tbs.len = end - crt->tbs.p; 1027817466cbSJens Wiklander 1028817466cbSJens Wiklander /* 1029817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 1030817466cbSJens Wiklander * 1031817466cbSJens Wiklander * CertificateSerialNumber ::= INTEGER 1032817466cbSJens Wiklander * 1033817466cbSJens Wiklander * signature AlgorithmIdentifier 1034817466cbSJens Wiklander */ 1035817466cbSJens Wiklander if ((ret = x509_get_version(&p, end, &crt->version)) != 0 || 1036817466cbSJens Wiklander (ret = mbedtls_x509_get_serial(&p, end, &crt->serial)) != 0 || 1037817466cbSJens Wiklander (ret = mbedtls_x509_get_alg(&p, end, &crt->sig_oid, 1038*32b31808SJens Wiklander &sig_params1)) != 0) { 1039817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1040*32b31808SJens Wiklander return ret; 1041817466cbSJens Wiklander } 1042817466cbSJens Wiklander 1043*32b31808SJens Wiklander if (crt->version < 0 || crt->version > 2) { 1044817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1045*32b31808SJens Wiklander return MBEDTLS_ERR_X509_UNKNOWN_VERSION; 1046817466cbSJens Wiklander } 1047817466cbSJens Wiklander 1048817466cbSJens Wiklander crt->version++; 1049817466cbSJens Wiklander 1050817466cbSJens Wiklander if ((ret = mbedtls_x509_get_sig_alg(&crt->sig_oid, &sig_params1, 1051817466cbSJens Wiklander &crt->sig_md, &crt->sig_pk, 1052*32b31808SJens Wiklander &crt->sig_opts)) != 0) { 1053817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1054*32b31808SJens Wiklander return ret; 1055817466cbSJens Wiklander } 1056817466cbSJens Wiklander 1057817466cbSJens Wiklander /* 1058817466cbSJens Wiklander * issuer Name 1059817466cbSJens Wiklander */ 1060817466cbSJens Wiklander crt->issuer_raw.p = p; 1061817466cbSJens Wiklander 1062817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 1063*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 1064817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1065*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 1066817466cbSJens Wiklander } 1067817466cbSJens Wiklander 1068*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_name(&p, p + len, &crt->issuer)) != 0) { 1069817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1070*32b31808SJens Wiklander return ret; 1071817466cbSJens Wiklander } 1072817466cbSJens Wiklander 1073817466cbSJens Wiklander crt->issuer_raw.len = p - crt->issuer_raw.p; 1074817466cbSJens Wiklander 1075817466cbSJens Wiklander /* 1076817466cbSJens Wiklander * Validity ::= SEQUENCE { 1077817466cbSJens Wiklander * notBefore Time, 1078817466cbSJens Wiklander * notAfter Time } 1079817466cbSJens Wiklander * 1080817466cbSJens Wiklander */ 1081817466cbSJens Wiklander if ((ret = x509_get_dates(&p, end, &crt->valid_from, 1082*32b31808SJens Wiklander &crt->valid_to)) != 0) { 1083817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1084*32b31808SJens Wiklander return ret; 1085817466cbSJens Wiklander } 1086817466cbSJens Wiklander 1087817466cbSJens Wiklander /* 1088817466cbSJens Wiklander * subject Name 1089817466cbSJens Wiklander */ 1090817466cbSJens Wiklander crt->subject_raw.p = p; 1091817466cbSJens Wiklander 1092817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 1093*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 1094817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1095*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 1096817466cbSJens Wiklander } 1097817466cbSJens Wiklander 1098*32b31808SJens Wiklander if (len && (ret = mbedtls_x509_get_name(&p, p + len, &crt->subject)) != 0) { 1099817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1100*32b31808SJens Wiklander return ret; 1101817466cbSJens Wiklander } 1102817466cbSJens Wiklander 1103817466cbSJens Wiklander crt->subject_raw.len = p - crt->subject_raw.p; 1104817466cbSJens Wiklander 1105817466cbSJens Wiklander /* 1106817466cbSJens Wiklander * SubjectPublicKeyInfo 1107817466cbSJens Wiklander */ 110811fa71b9SJerome Forissier crt->pk_raw.p = p; 1109*32b31808SJens Wiklander if ((ret = mbedtls_pk_parse_subpubkey(&p, end, &crt->pk)) != 0) { 1110817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1111*32b31808SJens Wiklander return ret; 1112817466cbSJens Wiklander } 111311fa71b9SJerome Forissier crt->pk_raw.len = p - crt->pk_raw.p; 1114817466cbSJens Wiklander 1115817466cbSJens Wiklander /* 1116817466cbSJens Wiklander * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 1117817466cbSJens Wiklander * -- If present, version shall be v2 or v3 1118817466cbSJens Wiklander * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 1119817466cbSJens Wiklander * -- If present, version shall be v2 or v3 1120817466cbSJens Wiklander * extensions [3] EXPLICIT Extensions OPTIONAL 1121817466cbSJens Wiklander * -- If present, version shall be v3 1122817466cbSJens Wiklander */ 1123*32b31808SJens Wiklander if (crt->version == 2 || crt->version == 3) { 1124817466cbSJens Wiklander ret = x509_get_uid(&p, end, &crt->issuer_id, 1); 1125*32b31808SJens Wiklander if (ret != 0) { 1126817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1127*32b31808SJens Wiklander return ret; 1128817466cbSJens Wiklander } 1129817466cbSJens Wiklander } 1130817466cbSJens Wiklander 1131*32b31808SJens Wiklander if (crt->version == 2 || crt->version == 3) { 1132817466cbSJens Wiklander ret = x509_get_uid(&p, end, &crt->subject_id, 2); 1133*32b31808SJens Wiklander if (ret != 0) { 1134817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1135*32b31808SJens Wiklander return ret; 1136817466cbSJens Wiklander } 1137817466cbSJens Wiklander } 1138817466cbSJens Wiklander 1139*32b31808SJens Wiklander if (crt->version == 3) { 11407901324dSJerome Forissier ret = x509_get_crt_ext(&p, end, crt, cb, p_ctx); 1141*32b31808SJens Wiklander if (ret != 0) { 1142817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1143*32b31808SJens Wiklander return ret; 1144817466cbSJens Wiklander } 1145817466cbSJens Wiklander } 1146817466cbSJens Wiklander 1147*32b31808SJens Wiklander if (p != end) { 1148817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1149*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, 1150*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 1151817466cbSJens Wiklander } 1152817466cbSJens Wiklander 1153817466cbSJens Wiklander end = crt_end; 1154817466cbSJens Wiklander 1155817466cbSJens Wiklander /* 1156817466cbSJens Wiklander * } 1157817466cbSJens Wiklander * -- end of TBSCertificate 1158817466cbSJens Wiklander * 1159817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 1160817466cbSJens Wiklander * signatureValue BIT STRING 1161817466cbSJens Wiklander */ 1162*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_alg(&p, end, &sig_oid2, &sig_params2)) != 0) { 1163817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1164*32b31808SJens Wiklander return ret; 1165817466cbSJens Wiklander } 1166817466cbSJens Wiklander 1167817466cbSJens Wiklander if (crt->sig_oid.len != sig_oid2.len || 1168817466cbSJens Wiklander memcmp(crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len) != 0 || 11697901324dSJerome Forissier sig_params1.tag != sig_params2.tag || 1170817466cbSJens Wiklander sig_params1.len != sig_params2.len || 1171817466cbSJens Wiklander (sig_params1.len != 0 && 1172*32b31808SJens Wiklander memcmp(sig_params1.p, sig_params2.p, sig_params1.len) != 0)) { 1173817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1174*32b31808SJens Wiklander return MBEDTLS_ERR_X509_SIG_MISMATCH; 1175817466cbSJens Wiklander } 1176817466cbSJens Wiklander 1177*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_sig(&p, end, &crt->sig)) != 0) { 1178817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1179*32b31808SJens Wiklander return ret; 1180817466cbSJens Wiklander } 1181817466cbSJens Wiklander 1182*32b31808SJens Wiklander if (p != end) { 1183817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 1184*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, 1185*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 1186817466cbSJens Wiklander } 1187817466cbSJens Wiklander 1188*32b31808SJens Wiklander return 0; 1189817466cbSJens Wiklander } 1190817466cbSJens Wiklander 1191817466cbSJens Wiklander /* 1192817466cbSJens Wiklander * Parse one X.509 certificate in DER format from a buffer and add them to a 1193817466cbSJens Wiklander * chained list 1194817466cbSJens Wiklander */ 119511fa71b9SJerome Forissier static int mbedtls_x509_crt_parse_der_internal(mbedtls_x509_crt *chain, 119611fa71b9SJerome Forissier const unsigned char *buf, 119711fa71b9SJerome Forissier size_t buflen, 11987901324dSJerome Forissier int make_copy, 11997901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 12007901324dSJerome Forissier void *p_ctx) 1201817466cbSJens Wiklander { 120211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1203817466cbSJens Wiklander mbedtls_x509_crt *crt = chain, *prev = NULL; 1204817466cbSJens Wiklander 1205817466cbSJens Wiklander /* 1206817466cbSJens Wiklander * Check for valid input 1207817466cbSJens Wiklander */ 1208*32b31808SJens Wiklander if (crt == NULL || buf == NULL) { 1209*32b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 1210*32b31808SJens Wiklander } 1211817466cbSJens Wiklander 1212*32b31808SJens Wiklander while (crt->version != 0 && crt->next != NULL) { 1213817466cbSJens Wiklander prev = crt; 1214817466cbSJens Wiklander crt = crt->next; 1215817466cbSJens Wiklander } 1216817466cbSJens Wiklander 1217817466cbSJens Wiklander /* 1218817466cbSJens Wiklander * Add new certificate on the end of the chain if needed. 1219817466cbSJens Wiklander */ 1220*32b31808SJens Wiklander if (crt->version != 0 && crt->next == NULL) { 1221817466cbSJens Wiklander crt->next = mbedtls_calloc(1, sizeof(mbedtls_x509_crt)); 1222817466cbSJens Wiklander 1223*32b31808SJens Wiklander if (crt->next == NULL) { 1224*32b31808SJens Wiklander return MBEDTLS_ERR_X509_ALLOC_FAILED; 1225*32b31808SJens Wiklander } 1226817466cbSJens Wiklander 1227817466cbSJens Wiklander prev = crt; 1228817466cbSJens Wiklander mbedtls_x509_crt_init(crt->next); 1229817466cbSJens Wiklander crt = crt->next; 1230817466cbSJens Wiklander } 1231817466cbSJens Wiklander 12327901324dSJerome Forissier ret = x509_crt_parse_der_core(crt, buf, buflen, make_copy, cb, p_ctx); 1233*32b31808SJens Wiklander if (ret != 0) { 1234*32b31808SJens Wiklander if (prev) { 1235817466cbSJens Wiklander prev->next = NULL; 1236817466cbSJens Wiklander } 1237817466cbSJens Wiklander 1238*32b31808SJens Wiklander if (crt != chain) { 1239*32b31808SJens Wiklander mbedtls_free(crt); 1240*32b31808SJens Wiklander } 1241*32b31808SJens Wiklander 1242*32b31808SJens Wiklander return ret; 1243*32b31808SJens Wiklander } 1244*32b31808SJens Wiklander 1245*32b31808SJens Wiklander return 0; 1246817466cbSJens Wiklander } 1247817466cbSJens Wiklander 124811fa71b9SJerome Forissier int mbedtls_x509_crt_parse_der_nocopy(mbedtls_x509_crt *chain, 124911fa71b9SJerome Forissier const unsigned char *buf, 125011fa71b9SJerome Forissier size_t buflen) 125111fa71b9SJerome Forissier { 1252*32b31808SJens Wiklander return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, 0, NULL, NULL); 12537901324dSJerome Forissier } 12547901324dSJerome Forissier 12557901324dSJerome Forissier int mbedtls_x509_crt_parse_der_with_ext_cb(mbedtls_x509_crt *chain, 12567901324dSJerome Forissier const unsigned char *buf, 12577901324dSJerome Forissier size_t buflen, 12587901324dSJerome Forissier int make_copy, 12597901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 12607901324dSJerome Forissier void *p_ctx) 12617901324dSJerome Forissier { 1262*32b31808SJens Wiklander return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, make_copy, cb, p_ctx); 126311fa71b9SJerome Forissier } 126411fa71b9SJerome Forissier 126511fa71b9SJerome Forissier int mbedtls_x509_crt_parse_der(mbedtls_x509_crt *chain, 126611fa71b9SJerome Forissier const unsigned char *buf, 126711fa71b9SJerome Forissier size_t buflen) 126811fa71b9SJerome Forissier { 1269*32b31808SJens Wiklander return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, 1, NULL, NULL); 127011fa71b9SJerome Forissier } 127111fa71b9SJerome Forissier 1272817466cbSJens Wiklander /* 1273817466cbSJens Wiklander * Parse one or more PEM certificates from a buffer and add them to the chained 1274817466cbSJens Wiklander * list 1275817466cbSJens Wiklander */ 127611fa71b9SJerome Forissier int mbedtls_x509_crt_parse(mbedtls_x509_crt *chain, 127711fa71b9SJerome Forissier const unsigned char *buf, 127811fa71b9SJerome Forissier size_t buflen) 1279817466cbSJens Wiklander { 1280817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1281817466cbSJens Wiklander int success = 0, first_error = 0, total_failed = 0; 1282817466cbSJens Wiklander int buf_format = MBEDTLS_X509_FORMAT_DER; 1283817466cbSJens Wiklander #endif 1284817466cbSJens Wiklander 1285817466cbSJens Wiklander /* 1286817466cbSJens Wiklander * Check for valid input 1287817466cbSJens Wiklander */ 1288*32b31808SJens Wiklander if (chain == NULL || buf == NULL) { 1289*32b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 1290*32b31808SJens Wiklander } 1291817466cbSJens Wiklander 1292817466cbSJens Wiklander /* 1293817466cbSJens Wiklander * Determine buffer content. Buffer contains either one DER certificate or 1294817466cbSJens Wiklander * one or more PEM certificates. 1295817466cbSJens Wiklander */ 1296817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1297817466cbSJens Wiklander if (buflen != 0 && buf[buflen - 1] == '\0' && 1298*32b31808SJens Wiklander strstr((const char *) buf, "-----BEGIN CERTIFICATE-----") != NULL) { 1299817466cbSJens Wiklander buf_format = MBEDTLS_X509_FORMAT_PEM; 1300817466cbSJens Wiklander } 1301817466cbSJens Wiklander 1302*32b31808SJens Wiklander if (buf_format == MBEDTLS_X509_FORMAT_DER) { 1303817466cbSJens Wiklander return mbedtls_x509_crt_parse_der(chain, buf, buflen); 1304*32b31808SJens Wiklander } 1305817466cbSJens Wiklander #else 1306817466cbSJens Wiklander return mbedtls_x509_crt_parse_der(chain, buf, buflen); 1307817466cbSJens Wiklander #endif 1308817466cbSJens Wiklander 1309817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1310*32b31808SJens Wiklander if (buf_format == MBEDTLS_X509_FORMAT_PEM) { 131111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1312817466cbSJens Wiklander mbedtls_pem_context pem; 1313817466cbSJens Wiklander 1314817466cbSJens Wiklander /* 1 rather than 0 since the terminating NULL byte is counted in */ 1315*32b31808SJens Wiklander while (buflen > 1) { 1316817466cbSJens Wiklander size_t use_len; 1317817466cbSJens Wiklander mbedtls_pem_init(&pem); 1318817466cbSJens Wiklander 1319817466cbSJens Wiklander /* If we get there, we know the string is null-terminated */ 1320817466cbSJens Wiklander ret = mbedtls_pem_read_buffer(&pem, 1321817466cbSJens Wiklander "-----BEGIN CERTIFICATE-----", 1322817466cbSJens Wiklander "-----END CERTIFICATE-----", 1323817466cbSJens Wiklander buf, NULL, 0, &use_len); 1324817466cbSJens Wiklander 1325*32b31808SJens Wiklander if (ret == 0) { 1326817466cbSJens Wiklander /* 1327817466cbSJens Wiklander * Was PEM encoded 1328817466cbSJens Wiklander */ 1329817466cbSJens Wiklander buflen -= use_len; 1330817466cbSJens Wiklander buf += use_len; 1331*32b31808SJens Wiklander } else if (ret == MBEDTLS_ERR_PEM_BAD_INPUT_DATA) { 1332*32b31808SJens Wiklander return ret; 1333*32b31808SJens Wiklander } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) { 1334817466cbSJens Wiklander mbedtls_pem_free(&pem); 1335817466cbSJens Wiklander 1336817466cbSJens Wiklander /* 1337817466cbSJens Wiklander * PEM header and footer were found 1338817466cbSJens Wiklander */ 1339817466cbSJens Wiklander buflen -= use_len; 1340817466cbSJens Wiklander buf += use_len; 1341817466cbSJens Wiklander 1342*32b31808SJens Wiklander if (first_error == 0) { 1343817466cbSJens Wiklander first_error = ret; 1344*32b31808SJens Wiklander } 1345817466cbSJens Wiklander 1346817466cbSJens Wiklander total_failed++; 1347817466cbSJens Wiklander continue; 1348*32b31808SJens Wiklander } else { 1349817466cbSJens Wiklander break; 1350*32b31808SJens Wiklander } 1351817466cbSJens Wiklander 1352817466cbSJens Wiklander ret = mbedtls_x509_crt_parse_der(chain, pem.buf, pem.buflen); 1353817466cbSJens Wiklander 1354817466cbSJens Wiklander mbedtls_pem_free(&pem); 1355817466cbSJens Wiklander 1356*32b31808SJens Wiklander if (ret != 0) { 1357817466cbSJens Wiklander /* 1358817466cbSJens Wiklander * Quit parsing on a memory error 1359817466cbSJens Wiklander */ 1360*32b31808SJens Wiklander if (ret == MBEDTLS_ERR_X509_ALLOC_FAILED) { 1361*32b31808SJens Wiklander return ret; 1362*32b31808SJens Wiklander } 1363817466cbSJens Wiklander 1364*32b31808SJens Wiklander if (first_error == 0) { 1365817466cbSJens Wiklander first_error = ret; 1366*32b31808SJens Wiklander } 1367817466cbSJens Wiklander 1368817466cbSJens Wiklander total_failed++; 1369817466cbSJens Wiklander continue; 1370817466cbSJens Wiklander } 1371817466cbSJens Wiklander 1372817466cbSJens Wiklander success = 1; 1373817466cbSJens Wiklander } 1374817466cbSJens Wiklander } 1375817466cbSJens Wiklander 1376*32b31808SJens Wiklander if (success) { 1377*32b31808SJens Wiklander return total_failed; 1378*32b31808SJens Wiklander } else if (first_error) { 1379*32b31808SJens Wiklander return first_error; 1380*32b31808SJens Wiklander } else { 1381*32b31808SJens Wiklander return MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT; 1382*32b31808SJens Wiklander } 1383817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 1384817466cbSJens Wiklander } 1385817466cbSJens Wiklander 1386817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 1387817466cbSJens Wiklander /* 1388817466cbSJens Wiklander * Load one or more certificates and add them to the chained list 1389817466cbSJens Wiklander */ 1390817466cbSJens Wiklander int mbedtls_x509_crt_parse_file(mbedtls_x509_crt *chain, const char *path) 1391817466cbSJens Wiklander { 139211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1393817466cbSJens Wiklander size_t n; 1394817466cbSJens Wiklander unsigned char *buf; 1395817466cbSJens Wiklander 1396*32b31808SJens Wiklander if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) { 1397*32b31808SJens Wiklander return ret; 1398*32b31808SJens Wiklander } 1399817466cbSJens Wiklander 1400817466cbSJens Wiklander ret = mbedtls_x509_crt_parse(chain, buf, n); 1401817466cbSJens Wiklander 14023d3b0591SJens Wiklander mbedtls_platform_zeroize(buf, n); 1403817466cbSJens Wiklander mbedtls_free(buf); 1404817466cbSJens Wiklander 1405*32b31808SJens Wiklander return ret; 1406817466cbSJens Wiklander } 1407817466cbSJens Wiklander 1408817466cbSJens Wiklander int mbedtls_x509_crt_parse_path(mbedtls_x509_crt *chain, const char *path) 1409817466cbSJens Wiklander { 1410817466cbSJens Wiklander int ret = 0; 1411817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 1412817466cbSJens Wiklander int w_ret; 1413817466cbSJens Wiklander WCHAR szDir[MAX_PATH]; 1414817466cbSJens Wiklander char filename[MAX_PATH]; 1415817466cbSJens Wiklander char *p; 1416817466cbSJens Wiklander size_t len = strlen(path); 1417817466cbSJens Wiklander 1418817466cbSJens Wiklander WIN32_FIND_DATAW file_data; 1419817466cbSJens Wiklander HANDLE hFind; 1420817466cbSJens Wiklander 1421*32b31808SJens Wiklander if (len > MAX_PATH - 3) { 1422*32b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 1423*32b31808SJens Wiklander } 1424817466cbSJens Wiklander 1425817466cbSJens Wiklander memset(szDir, 0, sizeof(szDir)); 1426817466cbSJens Wiklander memset(filename, 0, MAX_PATH); 1427817466cbSJens Wiklander memcpy(filename, path, len); 1428817466cbSJens Wiklander filename[len++] = '\\'; 1429817466cbSJens Wiklander p = filename + len; 1430817466cbSJens Wiklander filename[len++] = '*'; 1431817466cbSJens Wiklander 1432817466cbSJens Wiklander w_ret = MultiByteToWideChar(CP_ACP, 0, filename, (int) len, szDir, 1433817466cbSJens Wiklander MAX_PATH - 3); 1434*32b31808SJens Wiklander if (w_ret == 0) { 1435*32b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 1436*32b31808SJens Wiklander } 1437817466cbSJens Wiklander 1438817466cbSJens Wiklander hFind = FindFirstFileW(szDir, &file_data); 1439*32b31808SJens Wiklander if (hFind == INVALID_HANDLE_VALUE) { 1440*32b31808SJens Wiklander return MBEDTLS_ERR_X509_FILE_IO_ERROR; 1441*32b31808SJens Wiklander } 1442817466cbSJens Wiklander 1443817466cbSJens Wiklander len = MAX_PATH - len; 1444*32b31808SJens Wiklander do { 1445817466cbSJens Wiklander memset(p, 0, len); 1446817466cbSJens Wiklander 1447*32b31808SJens Wiklander if (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 1448817466cbSJens Wiklander continue; 1449*32b31808SJens Wiklander } 1450817466cbSJens Wiklander 1451817466cbSJens Wiklander w_ret = WideCharToMultiByte(CP_ACP, 0, file_data.cFileName, 1452*32b31808SJens Wiklander -1, 1453*32b31808SJens Wiklander p, (int) len, 1454817466cbSJens Wiklander NULL, NULL); 1455*32b31808SJens Wiklander if (w_ret == 0) { 1456817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1457817466cbSJens Wiklander goto cleanup; 1458817466cbSJens Wiklander } 1459817466cbSJens Wiklander 1460817466cbSJens Wiklander w_ret = mbedtls_x509_crt_parse_file(chain, filename); 1461*32b31808SJens Wiklander if (w_ret < 0) { 1462817466cbSJens Wiklander ret++; 1463*32b31808SJens Wiklander } else { 1464817466cbSJens Wiklander ret += w_ret; 1465817466cbSJens Wiklander } 1466*32b31808SJens Wiklander } while (FindNextFileW(hFind, &file_data) != 0); 1467817466cbSJens Wiklander 1468*32b31808SJens Wiklander if (GetLastError() != ERROR_NO_MORE_FILES) { 1469817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1470*32b31808SJens Wiklander } 1471817466cbSJens Wiklander 1472817466cbSJens Wiklander cleanup: 1473817466cbSJens Wiklander FindClose(hFind); 1474817466cbSJens Wiklander #else /* _WIN32 */ 1475817466cbSJens Wiklander int t_ret; 1476817466cbSJens Wiklander int snp_ret; 1477817466cbSJens Wiklander struct stat sb; 1478817466cbSJens Wiklander struct dirent *entry; 1479817466cbSJens Wiklander char entry_name[MBEDTLS_X509_MAX_FILE_PATH_LEN]; 1480817466cbSJens Wiklander DIR *dir = opendir(path); 1481817466cbSJens Wiklander 1482*32b31808SJens Wiklander if (dir == NULL) { 1483*32b31808SJens Wiklander return MBEDTLS_ERR_X509_FILE_IO_ERROR; 1484*32b31808SJens Wiklander } 1485817466cbSJens Wiklander 1486817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 1487*32b31808SJens Wiklander if ((ret = mbedtls_mutex_lock(&mbedtls_threading_readdir_mutex)) != 0) { 1488817466cbSJens Wiklander closedir(dir); 1489*32b31808SJens Wiklander return ret; 1490817466cbSJens Wiklander } 1491817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */ 1492817466cbSJens Wiklander 14937901324dSJerome Forissier memset(&sb, 0, sizeof(sb)); 14947901324dSJerome Forissier 1495*32b31808SJens Wiklander while ((entry = readdir(dir)) != NULL) { 1496*32b31808SJens Wiklander snp_ret = mbedtls_snprintf(entry_name, sizeof(entry_name), 1497817466cbSJens Wiklander "%s/%s", path, entry->d_name); 1498817466cbSJens Wiklander 1499*32b31808SJens Wiklander if (snp_ret < 0 || (size_t) snp_ret >= sizeof(entry_name)) { 1500817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; 1501817466cbSJens Wiklander goto cleanup; 1502*32b31808SJens Wiklander } else if (stat(entry_name, &sb) == -1) { 1503*32b31808SJens Wiklander if (errno == ENOENT) { 1504*32b31808SJens Wiklander /* Broken symbolic link - ignore this entry. 1505*32b31808SJens Wiklander stat(2) will return this error for either (a) a dangling 1506*32b31808SJens Wiklander symlink or (b) a missing file. 1507*32b31808SJens Wiklander Given that we have just obtained the filename from readdir, 1508*32b31808SJens Wiklander assume that it does exist and therefore treat this as a 1509*32b31808SJens Wiklander dangling symlink. */ 1510*32b31808SJens Wiklander continue; 1511*32b31808SJens Wiklander } else { 1512*32b31808SJens Wiklander /* Some other file error; report the error. */ 1513817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1514817466cbSJens Wiklander goto cleanup; 1515817466cbSJens Wiklander } 1516*32b31808SJens Wiklander } 1517817466cbSJens Wiklander 1518*32b31808SJens Wiklander if (!S_ISREG(sb.st_mode)) { 1519817466cbSJens Wiklander continue; 1520*32b31808SJens Wiklander } 1521817466cbSJens Wiklander 1522817466cbSJens Wiklander // Ignore parse errors 1523817466cbSJens Wiklander // 1524817466cbSJens Wiklander t_ret = mbedtls_x509_crt_parse_file(chain, entry_name); 1525*32b31808SJens Wiklander if (t_ret < 0) { 1526817466cbSJens Wiklander ret++; 1527*32b31808SJens Wiklander } else { 1528817466cbSJens Wiklander ret += t_ret; 1529817466cbSJens Wiklander } 1530*32b31808SJens Wiklander } 1531817466cbSJens Wiklander 1532817466cbSJens Wiklander cleanup: 1533817466cbSJens Wiklander closedir(dir); 1534817466cbSJens Wiklander 1535817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 1536*32b31808SJens Wiklander if (mbedtls_mutex_unlock(&mbedtls_threading_readdir_mutex) != 0) { 1537817466cbSJens Wiklander ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR; 1538*32b31808SJens Wiklander } 1539817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */ 1540817466cbSJens Wiklander 1541817466cbSJens Wiklander #endif /* _WIN32 */ 1542817466cbSJens Wiklander 1543*32b31808SJens Wiklander return ret; 1544817466cbSJens Wiklander } 1545817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 1546817466cbSJens Wiklander 1547*32b31808SJens Wiklander #if !defined(MBEDTLS_X509_REMOVE_INFO) 1548817466cbSJens Wiklander static int x509_info_ext_key_usage(char **buf, size_t *size, 1549817466cbSJens Wiklander const mbedtls_x509_sequence *extended_key_usage) 1550817466cbSJens Wiklander { 155111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1552817466cbSJens Wiklander const char *desc; 1553817466cbSJens Wiklander size_t n = *size; 1554817466cbSJens Wiklander char *p = *buf; 1555817466cbSJens Wiklander const mbedtls_x509_sequence *cur = extended_key_usage; 1556817466cbSJens Wiklander const char *sep = ""; 1557817466cbSJens Wiklander 1558*32b31808SJens Wiklander while (cur != NULL) { 1559*32b31808SJens Wiklander if (mbedtls_oid_get_extended_key_usage(&cur->buf, &desc) != 0) { 1560817466cbSJens Wiklander desc = "???"; 1561*32b31808SJens Wiklander } 1562817466cbSJens Wiklander 1563817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%s%s", sep, desc); 1564817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1565817466cbSJens Wiklander 1566817466cbSJens Wiklander sep = ", "; 1567817466cbSJens Wiklander 1568817466cbSJens Wiklander cur = cur->next; 1569817466cbSJens Wiklander } 1570817466cbSJens Wiklander 1571817466cbSJens Wiklander *size = n; 1572817466cbSJens Wiklander *buf = p; 1573817466cbSJens Wiklander 1574*32b31808SJens Wiklander return 0; 1575817466cbSJens Wiklander } 1576817466cbSJens Wiklander 157711fa71b9SJerome Forissier static int x509_info_cert_policies(char **buf, size_t *size, 157811fa71b9SJerome Forissier const mbedtls_x509_sequence *certificate_policies) 157911fa71b9SJerome Forissier { 158011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 158111fa71b9SJerome Forissier const char *desc; 158211fa71b9SJerome Forissier size_t n = *size; 158311fa71b9SJerome Forissier char *p = *buf; 158411fa71b9SJerome Forissier const mbedtls_x509_sequence *cur = certificate_policies; 158511fa71b9SJerome Forissier const char *sep = ""; 158611fa71b9SJerome Forissier 1587*32b31808SJens Wiklander while (cur != NULL) { 1588*32b31808SJens Wiklander if (mbedtls_oid_get_certificate_policies(&cur->buf, &desc) != 0) { 158911fa71b9SJerome Forissier desc = "???"; 1590*32b31808SJens Wiklander } 159111fa71b9SJerome Forissier 159211fa71b9SJerome Forissier ret = mbedtls_snprintf(p, n, "%s%s", sep, desc); 159311fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 159411fa71b9SJerome Forissier 159511fa71b9SJerome Forissier sep = ", "; 159611fa71b9SJerome Forissier 159711fa71b9SJerome Forissier cur = cur->next; 159811fa71b9SJerome Forissier } 159911fa71b9SJerome Forissier 160011fa71b9SJerome Forissier *size = n; 160111fa71b9SJerome Forissier *buf = p; 160211fa71b9SJerome Forissier 1603*32b31808SJens Wiklander return 0; 160411fa71b9SJerome Forissier } 160511fa71b9SJerome Forissier 1606817466cbSJens Wiklander /* 1607817466cbSJens Wiklander * Return an informational string about the certificate. 1608817466cbSJens Wiklander */ 1609817466cbSJens Wiklander #define BEFORE_COLON 18 1610817466cbSJens Wiklander #define BC "18" 1611817466cbSJens Wiklander int mbedtls_x509_crt_info(char *buf, size_t size, const char *prefix, 1612817466cbSJens Wiklander const mbedtls_x509_crt *crt) 1613817466cbSJens Wiklander { 161411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1615817466cbSJens Wiklander size_t n; 1616817466cbSJens Wiklander char *p; 1617817466cbSJens Wiklander char key_size_str[BEFORE_COLON]; 1618817466cbSJens Wiklander 1619817466cbSJens Wiklander p = buf; 1620817466cbSJens Wiklander n = size; 1621817466cbSJens Wiklander 1622*32b31808SJens Wiklander if (NULL == crt) { 1623817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\nCertificate is uninitialised!\n"); 1624817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1625817466cbSJens Wiklander 1626*32b31808SJens Wiklander return (int) (size - n); 1627817466cbSJens Wiklander } 1628817466cbSJens Wiklander 1629817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%scert. version : %d\n", 1630817466cbSJens Wiklander prefix, crt->version); 1631817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1632817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%sserial number : ", 1633817466cbSJens Wiklander prefix); 1634817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1635817466cbSJens Wiklander 1636817466cbSJens Wiklander ret = mbedtls_x509_serial_gets(p, n, &crt->serial); 1637817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1638817466cbSJens Wiklander 1639817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sissuer name : ", prefix); 1640817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1641817466cbSJens Wiklander ret = mbedtls_x509_dn_gets(p, n, &crt->issuer); 1642817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1643817466cbSJens Wiklander 1644817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssubject name : ", prefix); 1645817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1646817466cbSJens Wiklander ret = mbedtls_x509_dn_gets(p, n, &crt->subject); 1647817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1648817466cbSJens Wiklander 1649817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sissued on : " \ 1650817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix, 1651817466cbSJens Wiklander crt->valid_from.year, crt->valid_from.mon, 1652817466cbSJens Wiklander crt->valid_from.day, crt->valid_from.hour, 1653817466cbSJens Wiklander crt->valid_from.min, crt->valid_from.sec); 1654817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1655817466cbSJens Wiklander 1656817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sexpires on : " \ 1657817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix, 1658817466cbSJens Wiklander crt->valid_to.year, crt->valid_to.mon, 1659817466cbSJens Wiklander crt->valid_to.day, crt->valid_to.hour, 1660817466cbSJens Wiklander crt->valid_to.min, crt->valid_to.sec); 1661817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1662817466cbSJens Wiklander 1663817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssigned using : ", prefix); 1664817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1665817466cbSJens Wiklander 1666817466cbSJens Wiklander ret = mbedtls_x509_sig_alg_gets(p, n, &crt->sig_oid, crt->sig_pk, 1667817466cbSJens Wiklander crt->sig_md, crt->sig_opts); 1668817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1669817466cbSJens Wiklander 1670817466cbSJens Wiklander /* Key size */ 1671817466cbSJens Wiklander if ((ret = mbedtls_x509_key_size_helper(key_size_str, BEFORE_COLON, 1672*32b31808SJens Wiklander mbedtls_pk_get_name(&crt->pk))) != 0) { 1673*32b31808SJens Wiklander return ret; 1674817466cbSJens Wiklander } 1675817466cbSJens Wiklander 1676817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, 1677817466cbSJens Wiklander (int) mbedtls_pk_get_bitlen(&crt->pk)); 1678817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1679817466cbSJens Wiklander 1680817466cbSJens Wiklander /* 1681817466cbSJens Wiklander * Optional extensions 1682817466cbSJens Wiklander */ 1683817466cbSJens Wiklander 1684*32b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS) { 1685817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sbasic constraints : CA=%s", prefix, 1686817466cbSJens Wiklander crt->ca_istrue ? "true" : "false"); 1687817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1688817466cbSJens Wiklander 1689*32b31808SJens Wiklander if (crt->max_pathlen > 0) { 1690817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, ", max_pathlen=%d", crt->max_pathlen - 1); 1691817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1692817466cbSJens Wiklander } 1693817466cbSJens Wiklander } 1694817466cbSJens Wiklander 1695*32b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) { 1696817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssubject alt name :", prefix); 1697817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1698817466cbSJens Wiklander 1699*32b31808SJens Wiklander if ((ret = mbedtls_x509_info_subject_alt_name(&p, &n, 170011fa71b9SJerome Forissier &crt->subject_alt_names, 1701*32b31808SJens Wiklander prefix)) != 0) { 1702*32b31808SJens Wiklander return ret; 1703*32b31808SJens Wiklander } 1704817466cbSJens Wiklander } 1705817466cbSJens Wiklander 1706*32b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) { 1707817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%scert. type : ", prefix); 1708817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1709817466cbSJens Wiklander 1710*32b31808SJens Wiklander if ((ret = mbedtls_x509_info_cert_type(&p, &n, crt->ns_cert_type)) != 0) { 1711*32b31808SJens Wiklander return ret; 1712*32b31808SJens Wiklander } 1713817466cbSJens Wiklander } 1714817466cbSJens Wiklander 1715*32b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE) { 1716817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%skey usage : ", prefix); 1717817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1718817466cbSJens Wiklander 1719*32b31808SJens Wiklander if ((ret = mbedtls_x509_info_key_usage(&p, &n, crt->key_usage)) != 0) { 1720*32b31808SJens Wiklander return ret; 1721*32b31808SJens Wiklander } 1722817466cbSJens Wiklander } 1723817466cbSJens Wiklander 1724*32b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE) { 1725817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sext key usage : ", prefix); 1726817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1727817466cbSJens Wiklander 1728817466cbSJens Wiklander if ((ret = x509_info_ext_key_usage(&p, &n, 1729*32b31808SJens Wiklander &crt->ext_key_usage)) != 0) { 1730*32b31808SJens Wiklander return ret; 1731*32b31808SJens Wiklander } 1732817466cbSJens Wiklander } 1733817466cbSJens Wiklander 1734*32b31808SJens Wiklander if (crt->ext_types & MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES) { 173511fa71b9SJerome Forissier ret = mbedtls_snprintf(p, n, "\n%scertificate policies : ", prefix); 173611fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 173711fa71b9SJerome Forissier 173811fa71b9SJerome Forissier if ((ret = x509_info_cert_policies(&p, &n, 1739*32b31808SJens Wiklander &crt->certificate_policies)) != 0) { 1740*32b31808SJens Wiklander return ret; 1741*32b31808SJens Wiklander } 174211fa71b9SJerome Forissier } 174311fa71b9SJerome Forissier 1744817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n"); 1745817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1746817466cbSJens Wiklander 1747*32b31808SJens Wiklander return (int) (size - n); 1748817466cbSJens Wiklander } 1749817466cbSJens Wiklander 1750817466cbSJens Wiklander struct x509_crt_verify_string { 1751817466cbSJens Wiklander int code; 1752817466cbSJens Wiklander const char *string; 1753817466cbSJens Wiklander }; 1754817466cbSJens Wiklander 1755*32b31808SJens Wiklander #define X509_CRT_ERROR_INFO(err, err_str, info) { err, info }, 1756817466cbSJens Wiklander static const struct x509_crt_verify_string x509_crt_verify_strings[] = { 1757*32b31808SJens Wiklander MBEDTLS_X509_CRT_ERROR_INFO_LIST 1758817466cbSJens Wiklander { 0, NULL } 1759817466cbSJens Wiklander }; 1760*32b31808SJens Wiklander #undef X509_CRT_ERROR_INFO 1761817466cbSJens Wiklander 1762817466cbSJens Wiklander int mbedtls_x509_crt_verify_info(char *buf, size_t size, const char *prefix, 1763817466cbSJens Wiklander uint32_t flags) 1764817466cbSJens Wiklander { 176511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1766817466cbSJens Wiklander const struct x509_crt_verify_string *cur; 1767817466cbSJens Wiklander char *p = buf; 1768817466cbSJens Wiklander size_t n = size; 1769817466cbSJens Wiklander 1770*32b31808SJens Wiklander for (cur = x509_crt_verify_strings; cur->string != NULL; cur++) { 1771*32b31808SJens Wiklander if ((flags & cur->code) == 0) { 1772817466cbSJens Wiklander continue; 1773*32b31808SJens Wiklander } 1774817466cbSJens Wiklander 1775817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%s%s\n", prefix, cur->string); 1776817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1777817466cbSJens Wiklander flags ^= cur->code; 1778817466cbSJens Wiklander } 1779817466cbSJens Wiklander 1780*32b31808SJens Wiklander if (flags != 0) { 1781817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%sUnknown reason " 1782817466cbSJens Wiklander "(this should not happen)\n", prefix); 1783817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1784817466cbSJens Wiklander } 1785817466cbSJens Wiklander 1786*32b31808SJens Wiklander return (int) (size - n); 1787817466cbSJens Wiklander } 1788*32b31808SJens Wiklander #endif /* MBEDTLS_X509_REMOVE_INFO */ 1789817466cbSJens Wiklander 1790817466cbSJens Wiklander int mbedtls_x509_crt_check_key_usage(const mbedtls_x509_crt *crt, 1791817466cbSJens Wiklander unsigned int usage) 1792817466cbSJens Wiklander { 1793817466cbSJens Wiklander unsigned int usage_must, usage_may; 1794817466cbSJens Wiklander unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY 1795817466cbSJens Wiklander | MBEDTLS_X509_KU_DECIPHER_ONLY; 1796817466cbSJens Wiklander 1797*32b31808SJens Wiklander if ((crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE) == 0) { 1798*32b31808SJens Wiklander return 0; 1799*32b31808SJens Wiklander } 1800817466cbSJens Wiklander 1801817466cbSJens Wiklander usage_must = usage & ~may_mask; 1802817466cbSJens Wiklander 1803*32b31808SJens Wiklander if (((crt->key_usage & ~may_mask) & usage_must) != usage_must) { 1804*32b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 1805*32b31808SJens Wiklander } 1806817466cbSJens Wiklander 1807817466cbSJens Wiklander usage_may = usage & may_mask; 1808817466cbSJens Wiklander 1809*32b31808SJens Wiklander if (((crt->key_usage & may_mask) | usage_may) != usage_may) { 1810*32b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 1811817466cbSJens Wiklander } 1812817466cbSJens Wiklander 1813*32b31808SJens Wiklander return 0; 1814*32b31808SJens Wiklander } 1815*32b31808SJens Wiklander 1816817466cbSJens Wiklander int mbedtls_x509_crt_check_extended_key_usage(const mbedtls_x509_crt *crt, 1817817466cbSJens Wiklander const char *usage_oid, 1818817466cbSJens Wiklander size_t usage_len) 1819817466cbSJens Wiklander { 1820817466cbSJens Wiklander const mbedtls_x509_sequence *cur; 1821817466cbSJens Wiklander 1822817466cbSJens Wiklander /* Extension is not mandatory, absent means no restriction */ 1823*32b31808SJens Wiklander if ((crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE) == 0) { 1824*32b31808SJens Wiklander return 0; 1825*32b31808SJens Wiklander } 1826817466cbSJens Wiklander 1827817466cbSJens Wiklander /* 1828817466cbSJens Wiklander * Look for the requested usage (or wildcard ANY) in our list 1829817466cbSJens Wiklander */ 1830*32b31808SJens Wiklander for (cur = &crt->ext_key_usage; cur != NULL; cur = cur->next) { 1831817466cbSJens Wiklander const mbedtls_x509_buf *cur_oid = &cur->buf; 1832817466cbSJens Wiklander 1833817466cbSJens Wiklander if (cur_oid->len == usage_len && 1834*32b31808SJens Wiklander memcmp(cur_oid->p, usage_oid, usage_len) == 0) { 1835*32b31808SJens Wiklander return 0; 1836817466cbSJens Wiklander } 1837817466cbSJens Wiklander 1838*32b31808SJens Wiklander if (MBEDTLS_OID_CMP(MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid) == 0) { 1839*32b31808SJens Wiklander return 0; 1840*32b31808SJens Wiklander } 1841817466cbSJens Wiklander } 1842817466cbSJens Wiklander 1843*32b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 1844817466cbSJens Wiklander } 1845817466cbSJens Wiklander 1846817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C) 1847817466cbSJens Wiklander /* 1848817466cbSJens Wiklander * Return 1 if the certificate is revoked, or 0 otherwise. 1849817466cbSJens Wiklander */ 1850817466cbSJens Wiklander int mbedtls_x509_crt_is_revoked(const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl) 1851817466cbSJens Wiklander { 1852817466cbSJens Wiklander const mbedtls_x509_crl_entry *cur = &crl->entry; 1853817466cbSJens Wiklander 1854*32b31808SJens Wiklander while (cur != NULL && cur->serial.len != 0) { 1855817466cbSJens Wiklander if (crt->serial.len == cur->serial.len && 1856*32b31808SJens Wiklander memcmp(crt->serial.p, cur->serial.p, crt->serial.len) == 0) { 1857*32b31808SJens Wiklander return 1; 1858817466cbSJens Wiklander } 1859817466cbSJens Wiklander 1860817466cbSJens Wiklander cur = cur->next; 1861817466cbSJens Wiklander } 1862817466cbSJens Wiklander 1863*32b31808SJens Wiklander return 0; 1864817466cbSJens Wiklander } 1865817466cbSJens Wiklander 1866817466cbSJens Wiklander /* 1867817466cbSJens Wiklander * Check that the given certificate is not revoked according to the CRL. 18683d3b0591SJens Wiklander * Skip validation if no CRL for the given CA is present. 1869817466cbSJens Wiklander */ 1870817466cbSJens Wiklander static int x509_crt_verifycrl(mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, 1871817466cbSJens Wiklander mbedtls_x509_crl *crl_list, 1872817466cbSJens Wiklander const mbedtls_x509_crt_profile *profile) 1873817466cbSJens Wiklander { 1874817466cbSJens Wiklander int flags = 0; 1875*32b31808SJens Wiklander unsigned char hash[MBEDTLS_HASH_MAX_SIZE]; 1876*32b31808SJens Wiklander #if defined(MBEDTLS_USE_PSA_CRYPTO) 1877*32b31808SJens Wiklander psa_algorithm_t psa_algorithm; 1878*32b31808SJens Wiklander #else 1879817466cbSJens Wiklander const mbedtls_md_info_t *md_info; 1880*32b31808SJens Wiklander #endif /* MBEDTLS_USE_PSA_CRYPTO */ 1881*32b31808SJens Wiklander size_t hash_length; 1882817466cbSJens Wiklander 1883*32b31808SJens Wiklander if (ca == NULL) { 1884*32b31808SJens Wiklander return flags; 1885*32b31808SJens Wiklander } 1886817466cbSJens Wiklander 1887*32b31808SJens Wiklander while (crl_list != NULL) { 1888817466cbSJens Wiklander if (crl_list->version == 0 || 1889*32b31808SJens Wiklander x509_name_cmp(&crl_list->issuer, &ca->subject) != 0) { 1890817466cbSJens Wiklander crl_list = crl_list->next; 1891817466cbSJens Wiklander continue; 1892817466cbSJens Wiklander } 1893817466cbSJens Wiklander 1894817466cbSJens Wiklander /* 1895817466cbSJens Wiklander * Check if the CA is configured to sign CRLs 1896817466cbSJens Wiklander */ 18973d3b0591SJens Wiklander if (mbedtls_x509_crt_check_key_usage(ca, 1898*32b31808SJens Wiklander MBEDTLS_X509_KU_CRL_SIGN) != 0) { 1899817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 1900817466cbSJens Wiklander break; 1901817466cbSJens Wiklander } 1902817466cbSJens Wiklander 1903817466cbSJens Wiklander /* 1904817466cbSJens Wiklander * Check if CRL is correctly signed by the trusted CA 1905817466cbSJens Wiklander */ 1906*32b31808SJens Wiklander if (x509_profile_check_md_alg(profile, crl_list->sig_md) != 0) { 1907817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_MD; 1908*32b31808SJens Wiklander } 1909817466cbSJens Wiklander 1910*32b31808SJens Wiklander if (x509_profile_check_pk_alg(profile, crl_list->sig_pk) != 0) { 1911817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_PK; 1912*32b31808SJens Wiklander } 1913817466cbSJens Wiklander 1914*32b31808SJens Wiklander #if defined(MBEDTLS_USE_PSA_CRYPTO) 1915*32b31808SJens Wiklander psa_algorithm = mbedtls_hash_info_psa_from_md(crl_list->sig_md); 1916*32b31808SJens Wiklander if (psa_hash_compute(psa_algorithm, 1917*32b31808SJens Wiklander crl_list->tbs.p, 1918*32b31808SJens Wiklander crl_list->tbs.len, 1919*32b31808SJens Wiklander hash, 1920*32b31808SJens Wiklander sizeof(hash), 1921*32b31808SJens Wiklander &hash_length) != PSA_SUCCESS) { 19223d3b0591SJens Wiklander /* Note: this can't happen except after an internal error */ 1923817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 1924817466cbSJens Wiklander break; 1925817466cbSJens Wiklander } 1926*32b31808SJens Wiklander #else 1927*32b31808SJens Wiklander md_info = mbedtls_md_info_from_type(crl_list->sig_md); 1928*32b31808SJens Wiklander hash_length = mbedtls_md_get_size(md_info); 1929*32b31808SJens Wiklander if (mbedtls_md(md_info, 1930*32b31808SJens Wiklander crl_list->tbs.p, 1931*32b31808SJens Wiklander crl_list->tbs.len, 1932*32b31808SJens Wiklander hash) != 0) { 1933*32b31808SJens Wiklander /* Note: this can't happen except after an internal error */ 1934*32b31808SJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 1935*32b31808SJens Wiklander break; 1936*32b31808SJens Wiklander } 1937*32b31808SJens Wiklander #endif /* MBEDTLS_USE_PSA_CRYPTO */ 1938817466cbSJens Wiklander 1939*32b31808SJens Wiklander if (x509_profile_check_key(profile, &ca->pk) != 0) { 1940817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 1941*32b31808SJens Wiklander } 1942817466cbSJens Wiklander 1943817466cbSJens Wiklander if (mbedtls_pk_verify_ext(crl_list->sig_pk, crl_list->sig_opts, &ca->pk, 1944*32b31808SJens Wiklander crl_list->sig_md, hash, hash_length, 1945*32b31808SJens Wiklander crl_list->sig.p, crl_list->sig.len) != 0) { 1946817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 1947817466cbSJens Wiklander break; 1948817466cbSJens Wiklander } 1949817466cbSJens Wiklander 1950817466cbSJens Wiklander /* 1951817466cbSJens Wiklander * Check for validity of CRL (Do not drop out) 1952817466cbSJens Wiklander */ 1953*32b31808SJens Wiklander if (mbedtls_x509_time_is_past(&crl_list->next_update)) { 1954817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_EXPIRED; 1955*32b31808SJens Wiklander } 1956817466cbSJens Wiklander 1957*32b31808SJens Wiklander if (mbedtls_x509_time_is_future(&crl_list->this_update)) { 1958817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_FUTURE; 1959*32b31808SJens Wiklander } 1960817466cbSJens Wiklander 1961817466cbSJens Wiklander /* 1962817466cbSJens Wiklander * Check if certificate is revoked 1963817466cbSJens Wiklander */ 1964*32b31808SJens Wiklander if (mbedtls_x509_crt_is_revoked(crt, crl_list)) { 1965817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_REVOKED; 1966817466cbSJens Wiklander break; 1967817466cbSJens Wiklander } 1968817466cbSJens Wiklander 1969817466cbSJens Wiklander crl_list = crl_list->next; 1970817466cbSJens Wiklander } 1971817466cbSJens Wiklander 1972*32b31808SJens Wiklander return flags; 1973817466cbSJens Wiklander } 1974817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRL_PARSE_C */ 1975817466cbSJens Wiklander 1976817466cbSJens Wiklander /* 19773d3b0591SJens Wiklander * Check the signature of a certificate by its parent 1978817466cbSJens Wiklander */ 19793d3b0591SJens Wiklander static int x509_crt_check_signature(const mbedtls_x509_crt *child, 19803d3b0591SJens Wiklander mbedtls_x509_crt *parent, 19813d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx) 1982817466cbSJens Wiklander { 198311fa71b9SJerome Forissier size_t hash_len; 1984*32b31808SJens Wiklander unsigned char hash[MBEDTLS_HASH_MAX_SIZE]; 198511fa71b9SJerome Forissier #if !defined(MBEDTLS_USE_PSA_CRYPTO) 198611fa71b9SJerome Forissier const mbedtls_md_info_t *md_info; 19873d3b0591SJens Wiklander md_info = mbedtls_md_info_from_type(child->sig_md); 198811fa71b9SJerome Forissier hash_len = mbedtls_md_get_size(md_info); 198911fa71b9SJerome Forissier 199011fa71b9SJerome Forissier /* Note: hash errors can happen only after an internal error */ 1991*32b31808SJens Wiklander if (mbedtls_md(md_info, child->tbs.p, child->tbs.len, hash) != 0) { 1992*32b31808SJens Wiklander return -1; 1993*32b31808SJens Wiklander } 199411fa71b9SJerome Forissier #else 1995*32b31808SJens Wiklander psa_algorithm_t hash_alg = mbedtls_hash_info_psa_from_md(child->sig_md); 1996*32b31808SJens Wiklander psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 199711fa71b9SJerome Forissier 1998*32b31808SJens Wiklander status = psa_hash_compute(hash_alg, 1999*32b31808SJens Wiklander child->tbs.p, 2000*32b31808SJens Wiklander child->tbs.len, 2001*32b31808SJens Wiklander hash, 2002*32b31808SJens Wiklander sizeof(hash), 2003*32b31808SJens Wiklander &hash_len); 2004*32b31808SJens Wiklander if (status != PSA_SUCCESS) { 2005*32b31808SJens Wiklander return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED; 2006817466cbSJens Wiklander } 2007817466cbSJens Wiklander 200811fa71b9SJerome Forissier #endif /* MBEDTLS_USE_PSA_CRYPTO */ 20093d3b0591SJens Wiklander /* Skip expensive computation on obvious mismatch */ 2010*32b31808SJens Wiklander if (!mbedtls_pk_can_do(&parent->pk, child->sig_pk)) { 2011*32b31808SJens Wiklander return -1; 2012*32b31808SJens Wiklander } 2013817466cbSJens Wiklander 20143d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 2015*32b31808SJens Wiklander if (rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA) { 2016*32b31808SJens Wiklander return mbedtls_pk_verify_restartable(&parent->pk, 201711fa71b9SJerome Forissier child->sig_md, hash, hash_len, 2018*32b31808SJens Wiklander child->sig.p, child->sig.len, &rs_ctx->pk); 2019817466cbSJens Wiklander } 20203d3b0591SJens Wiklander #else 20213d3b0591SJens Wiklander (void) rs_ctx; 20223d3b0591SJens Wiklander #endif 2023817466cbSJens Wiklander 2024*32b31808SJens Wiklander return mbedtls_pk_verify_ext(child->sig_pk, child->sig_opts, &parent->pk, 202511fa71b9SJerome Forissier child->sig_md, hash, hash_len, 2026*32b31808SJens Wiklander child->sig.p, child->sig.len); 2027817466cbSJens Wiklander } 2028817466cbSJens Wiklander 2029817466cbSJens Wiklander /* 2030817466cbSJens Wiklander * Check if 'parent' is a suitable parent (signing CA) for 'child'. 2031817466cbSJens Wiklander * Return 0 if yes, -1 if not. 2032817466cbSJens Wiklander * 2033817466cbSJens Wiklander * top means parent is a locally-trusted certificate 2034817466cbSJens Wiklander */ 2035817466cbSJens Wiklander static int x509_crt_check_parent(const mbedtls_x509_crt *child, 2036817466cbSJens Wiklander const mbedtls_x509_crt *parent, 20373d3b0591SJens Wiklander int top) 2038817466cbSJens Wiklander { 2039817466cbSJens Wiklander int need_ca_bit; 2040817466cbSJens Wiklander 2041817466cbSJens Wiklander /* Parent must be the issuer */ 2042*32b31808SJens Wiklander if (x509_name_cmp(&child->issuer, &parent->subject) != 0) { 2043*32b31808SJens Wiklander return -1; 2044*32b31808SJens Wiklander } 2045817466cbSJens Wiklander 2046817466cbSJens Wiklander /* Parent must have the basicConstraints CA bit set as a general rule */ 2047817466cbSJens Wiklander need_ca_bit = 1; 2048817466cbSJens Wiklander 2049817466cbSJens Wiklander /* Exception: v1/v2 certificates that are locally trusted. */ 2050*32b31808SJens Wiklander if (top && parent->version < 3) { 2051817466cbSJens Wiklander need_ca_bit = 0; 2052817466cbSJens Wiklander } 2053817466cbSJens Wiklander 2054*32b31808SJens Wiklander if (need_ca_bit && !parent->ca_istrue) { 2055*32b31808SJens Wiklander return -1; 2056*32b31808SJens Wiklander } 2057*32b31808SJens Wiklander 2058*32b31808SJens Wiklander if (need_ca_bit && 2059*32b31808SJens Wiklander mbedtls_x509_crt_check_key_usage(parent, MBEDTLS_X509_KU_KEY_CERT_SIGN) != 0) { 2060*32b31808SJens Wiklander return -1; 2061*32b31808SJens Wiklander } 2062*32b31808SJens Wiklander 2063*32b31808SJens Wiklander return 0; 2064817466cbSJens Wiklander } 2065817466cbSJens Wiklander 20663d3b0591SJens Wiklander /* 20673d3b0591SJens Wiklander * Find a suitable parent for child in candidates, or return NULL. 20683d3b0591SJens Wiklander * 20693d3b0591SJens Wiklander * Here suitable is defined as: 20703d3b0591SJens Wiklander * 1. subject name matches child's issuer 20713d3b0591SJens Wiklander * 2. if necessary, the CA bit is set and key usage allows signing certs 20723d3b0591SJens Wiklander * 3. for trusted roots, the signature is correct 20733d3b0591SJens Wiklander * (for intermediates, the signature is checked and the result reported) 20743d3b0591SJens Wiklander * 4. pathlen constraints are satisfied 20753d3b0591SJens Wiklander * 20763d3b0591SJens Wiklander * If there's a suitable candidate which is also time-valid, return the first 20773d3b0591SJens Wiklander * such. Otherwise, return the first suitable candidate (or NULL if there is 20783d3b0591SJens Wiklander * none). 20793d3b0591SJens Wiklander * 20803d3b0591SJens Wiklander * The rationale for this rule is that someone could have a list of trusted 20813d3b0591SJens Wiklander * roots with two versions on the same root with different validity periods. 20823d3b0591SJens Wiklander * (At least one user reported having such a list and wanted it to just work.) 20833d3b0591SJens Wiklander * The reason we don't just require time-validity is that generally there is 20843d3b0591SJens Wiklander * only one version, and if it's expired we want the flags to state that 20853d3b0591SJens Wiklander * rather than NOT_TRUSTED, as would be the case if we required it here. 20863d3b0591SJens Wiklander * 20873d3b0591SJens Wiklander * The rationale for rule 3 (signature for trusted roots) is that users might 20883d3b0591SJens Wiklander * have two versions of the same CA with different keys in their list, and the 20893d3b0591SJens Wiklander * way we select the correct one is by checking the signature (as we don't 20903d3b0591SJens Wiklander * rely on key identifier extensions). (This is one way users might choose to 20913d3b0591SJens Wiklander * handle key rollover, another relies on self-issued certs, see [SIRO].) 20923d3b0591SJens Wiklander * 20933d3b0591SJens Wiklander * Arguments: 20943d3b0591SJens Wiklander * - [in] child: certificate for which we're looking for a parent 20953d3b0591SJens Wiklander * - [in] candidates: chained list of potential parents 20963d3b0591SJens Wiklander * - [out] r_parent: parent found (or NULL) 20973d3b0591SJens Wiklander * - [out] r_signature_is_good: 1 if child signature by parent is valid, or 0 20983d3b0591SJens Wiklander * - [in] top: 1 if candidates consists of trusted roots, ie we're at the top 20993d3b0591SJens Wiklander * of the chain, 0 otherwise 21003d3b0591SJens Wiklander * - [in] path_cnt: number of intermediates seen so far 21013d3b0591SJens Wiklander * - [in] self_cnt: number of self-signed intermediates seen so far 21023d3b0591SJens Wiklander * (will never be greater than path_cnt) 21033d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 21043d3b0591SJens Wiklander * 21053d3b0591SJens Wiklander * Return value: 21063d3b0591SJens Wiklander * - 0 on success 21073d3b0591SJens Wiklander * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise 21083d3b0591SJens Wiklander */ 21093d3b0591SJens Wiklander static int x509_crt_find_parent_in( 21103d3b0591SJens Wiklander mbedtls_x509_crt *child, 21113d3b0591SJens Wiklander mbedtls_x509_crt *candidates, 21123d3b0591SJens Wiklander mbedtls_x509_crt **r_parent, 21133d3b0591SJens Wiklander int *r_signature_is_good, 21143d3b0591SJens Wiklander int top, 21153d3b0591SJens Wiklander unsigned path_cnt, 21163d3b0591SJens Wiklander unsigned self_cnt, 21173d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx) 2118817466cbSJens Wiklander { 211911fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 21203d3b0591SJens Wiklander mbedtls_x509_crt *parent, *fallback_parent; 212111fa71b9SJerome Forissier int signature_is_good = 0, fallback_signature_is_good; 2122817466cbSJens Wiklander 21233d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 21243d3b0591SJens Wiklander /* did we have something in progress? */ 2125*32b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->parent != NULL) { 21263d3b0591SJens Wiklander /* restore saved state */ 21273d3b0591SJens Wiklander parent = rs_ctx->parent; 21283d3b0591SJens Wiklander fallback_parent = rs_ctx->fallback_parent; 21293d3b0591SJens Wiklander fallback_signature_is_good = rs_ctx->fallback_signature_is_good; 21303d3b0591SJens Wiklander 21313d3b0591SJens Wiklander /* clear saved state */ 21323d3b0591SJens Wiklander rs_ctx->parent = NULL; 21333d3b0591SJens Wiklander rs_ctx->fallback_parent = NULL; 21343d3b0591SJens Wiklander rs_ctx->fallback_signature_is_good = 0; 21353d3b0591SJens Wiklander 21363d3b0591SJens Wiklander /* resume where we left */ 21373d3b0591SJens Wiklander goto check_signature; 2138817466cbSJens Wiklander } 21393d3b0591SJens Wiklander #endif 2140817466cbSJens Wiklander 21413d3b0591SJens Wiklander fallback_parent = NULL; 21423d3b0591SJens Wiklander fallback_signature_is_good = 0; 21433d3b0591SJens Wiklander 2144*32b31808SJens Wiklander for (parent = candidates; parent != NULL; parent = parent->next) { 21453d3b0591SJens Wiklander /* basic parenting skills (name, CA bit, key usage) */ 2146*32b31808SJens Wiklander if (x509_crt_check_parent(child, parent, top) != 0) { 2147817466cbSJens Wiklander continue; 2148*32b31808SJens Wiklander } 2149817466cbSJens Wiklander 21503d3b0591SJens Wiklander /* +1 because stored max_pathlen is 1 higher that the actual value */ 21513d3b0591SJens Wiklander if (parent->max_pathlen > 0 && 2152*32b31808SJens Wiklander (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt) { 2153817466cbSJens Wiklander continue; 2154817466cbSJens Wiklander } 2155817466cbSJens Wiklander 21563d3b0591SJens Wiklander /* Signature */ 21573d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 21583d3b0591SJens Wiklander check_signature: 21593d3b0591SJens Wiklander #endif 21603d3b0591SJens Wiklander ret = x509_crt_check_signature(child, parent, rs_ctx); 2161817466cbSJens Wiklander 21623d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 2163*32b31808SJens Wiklander if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 21643d3b0591SJens Wiklander /* save state */ 21653d3b0591SJens Wiklander rs_ctx->parent = parent; 21663d3b0591SJens Wiklander rs_ctx->fallback_parent = fallback_parent; 21673d3b0591SJens Wiklander rs_ctx->fallback_signature_is_good = fallback_signature_is_good; 21683d3b0591SJens Wiklander 2169*32b31808SJens Wiklander return ret; 21703d3b0591SJens Wiklander } 21713d3b0591SJens Wiklander #else 21723d3b0591SJens Wiklander (void) ret; 21733d3b0591SJens Wiklander #endif 21743d3b0591SJens Wiklander 21753d3b0591SJens Wiklander signature_is_good = ret == 0; 2176*32b31808SJens Wiklander if (top && !signature_is_good) { 21773d3b0591SJens Wiklander continue; 2178*32b31808SJens Wiklander } 21793d3b0591SJens Wiklander 21803d3b0591SJens Wiklander /* optional time check */ 21813d3b0591SJens Wiklander if (mbedtls_x509_time_is_past(&parent->valid_to) || 2182*32b31808SJens Wiklander mbedtls_x509_time_is_future(&parent->valid_from)) { 2183*32b31808SJens Wiklander if (fallback_parent == NULL) { 21843d3b0591SJens Wiklander fallback_parent = parent; 21853d3b0591SJens Wiklander fallback_signature_is_good = signature_is_good; 21863d3b0591SJens Wiklander } 2187817466cbSJens Wiklander 2188817466cbSJens Wiklander continue; 2189817466cbSJens Wiklander } 2190817466cbSJens Wiklander 21915b25c76aSJerome Forissier *r_parent = parent; 21925b25c76aSJerome Forissier *r_signature_is_good = signature_is_good; 21935b25c76aSJerome Forissier 2194817466cbSJens Wiklander break; 2195817466cbSJens Wiklander } 2196817466cbSJens Wiklander 2197*32b31808SJens Wiklander if (parent == NULL) { 21983d3b0591SJens Wiklander *r_parent = fallback_parent; 21993d3b0591SJens Wiklander *r_signature_is_good = fallback_signature_is_good; 2200817466cbSJens Wiklander } 2201817466cbSJens Wiklander 2202*32b31808SJens Wiklander return 0; 2203817466cbSJens Wiklander } 2204817466cbSJens Wiklander 22053d3b0591SJens Wiklander /* 22063d3b0591SJens Wiklander * Find a parent in trusted CAs or the provided chain, or return NULL. 22073d3b0591SJens Wiklander * 22083d3b0591SJens Wiklander * Searches in trusted CAs first, and return the first suitable parent found 22093d3b0591SJens Wiklander * (see find_parent_in() for definition of suitable). 22103d3b0591SJens Wiklander * 22113d3b0591SJens Wiklander * Arguments: 22123d3b0591SJens Wiklander * - [in] child: certificate for which we're looking for a parent, followed 22133d3b0591SJens Wiklander * by a chain of possible intermediates 22143d3b0591SJens Wiklander * - [in] trust_ca: list of locally trusted certificates 22153d3b0591SJens Wiklander * - [out] parent: parent found (or NULL) 22163d3b0591SJens Wiklander * - [out] parent_is_trusted: 1 if returned `parent` is trusted, or 0 22173d3b0591SJens Wiklander * - [out] signature_is_good: 1 if child signature by parent is valid, or 0 22183d3b0591SJens Wiklander * - [in] path_cnt: number of links in the chain so far (EE -> ... -> child) 22193d3b0591SJens Wiklander * - [in] self_cnt: number of self-signed certs in the chain so far 22203d3b0591SJens Wiklander * (will always be no greater than path_cnt) 22213d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 22223d3b0591SJens Wiklander * 22233d3b0591SJens Wiklander * Return value: 22243d3b0591SJens Wiklander * - 0 on success 22253d3b0591SJens Wiklander * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise 22263d3b0591SJens Wiklander */ 22273d3b0591SJens Wiklander static int x509_crt_find_parent( 22283d3b0591SJens Wiklander mbedtls_x509_crt *child, 22293d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 22303d3b0591SJens Wiklander mbedtls_x509_crt **parent, 22313d3b0591SJens Wiklander int *parent_is_trusted, 22323d3b0591SJens Wiklander int *signature_is_good, 22333d3b0591SJens Wiklander unsigned path_cnt, 22343d3b0591SJens Wiklander unsigned self_cnt, 22353d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx) 2236817466cbSJens Wiklander { 223711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 22383d3b0591SJens Wiklander mbedtls_x509_crt *search_list; 2239817466cbSJens Wiklander 22403d3b0591SJens Wiklander *parent_is_trusted = 1; 2241817466cbSJens Wiklander 22423d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 22433d3b0591SJens Wiklander /* restore then clear saved state if we have some stored */ 2244*32b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->parent_is_trusted != -1) { 22453d3b0591SJens Wiklander *parent_is_trusted = rs_ctx->parent_is_trusted; 22463d3b0591SJens Wiklander rs_ctx->parent_is_trusted = -1; 22473d3b0591SJens Wiklander } 22483d3b0591SJens Wiklander #endif 22493d3b0591SJens Wiklander 22503d3b0591SJens Wiklander while (1) { 22513d3b0591SJens Wiklander search_list = *parent_is_trusted ? trust_ca : child->next; 22523d3b0591SJens Wiklander 22533d3b0591SJens Wiklander ret = x509_crt_find_parent_in(child, search_list, 22543d3b0591SJens Wiklander parent, signature_is_good, 22553d3b0591SJens Wiklander *parent_is_trusted, 22563d3b0591SJens Wiklander path_cnt, self_cnt, rs_ctx); 22573d3b0591SJens Wiklander 22583d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 2259*32b31808SJens Wiklander if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 22603d3b0591SJens Wiklander /* save state */ 22613d3b0591SJens Wiklander rs_ctx->parent_is_trusted = *parent_is_trusted; 2262*32b31808SJens Wiklander return ret; 22633d3b0591SJens Wiklander } 22643d3b0591SJens Wiklander #else 22653d3b0591SJens Wiklander (void) ret; 22663d3b0591SJens Wiklander #endif 22673d3b0591SJens Wiklander 22683d3b0591SJens Wiklander /* stop here if found or already in second iteration */ 2269*32b31808SJens Wiklander if (*parent != NULL || *parent_is_trusted == 0) { 22703d3b0591SJens Wiklander break; 2271*32b31808SJens Wiklander } 22723d3b0591SJens Wiklander 22733d3b0591SJens Wiklander /* prepare second iteration */ 22743d3b0591SJens Wiklander *parent_is_trusted = 0; 2275817466cbSJens Wiklander } 2276817466cbSJens Wiklander 22773d3b0591SJens Wiklander /* extra precaution against mistakes in the caller */ 2278*32b31808SJens Wiklander if (*parent == NULL) { 22793d3b0591SJens Wiklander *parent_is_trusted = 0; 22803d3b0591SJens Wiklander *signature_is_good = 0; 22813d3b0591SJens Wiklander } 22823d3b0591SJens Wiklander 2283*32b31808SJens Wiklander return 0; 22843d3b0591SJens Wiklander } 22853d3b0591SJens Wiklander 22863d3b0591SJens Wiklander /* 22873d3b0591SJens Wiklander * Check if an end-entity certificate is locally trusted 22883d3b0591SJens Wiklander * 22893d3b0591SJens Wiklander * Currently we require such certificates to be self-signed (actually only 22903d3b0591SJens Wiklander * check for self-issued as self-signatures are not checked) 22913d3b0591SJens Wiklander */ 22923d3b0591SJens Wiklander static int x509_crt_check_ee_locally_trusted( 22933d3b0591SJens Wiklander mbedtls_x509_crt *crt, 22943d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca) 22953d3b0591SJens Wiklander { 22963d3b0591SJens Wiklander mbedtls_x509_crt *cur; 22973d3b0591SJens Wiklander 22983d3b0591SJens Wiklander /* must be self-issued */ 2299*32b31808SJens Wiklander if (x509_name_cmp(&crt->issuer, &crt->subject) != 0) { 2300*32b31808SJens Wiklander return -1; 2301*32b31808SJens Wiklander } 23023d3b0591SJens Wiklander 23033d3b0591SJens Wiklander /* look for an exact match with trusted cert */ 2304*32b31808SJens Wiklander for (cur = trust_ca; cur != NULL; cur = cur->next) { 23053d3b0591SJens Wiklander if (crt->raw.len == cur->raw.len && 2306*32b31808SJens Wiklander memcmp(crt->raw.p, cur->raw.p, crt->raw.len) == 0) { 2307*32b31808SJens Wiklander return 0; 23083d3b0591SJens Wiklander } 23093d3b0591SJens Wiklander } 23103d3b0591SJens Wiklander 23113d3b0591SJens Wiklander /* too bad */ 2312*32b31808SJens Wiklander return -1; 23133d3b0591SJens Wiklander } 23143d3b0591SJens Wiklander 23153d3b0591SJens Wiklander /* 23163d3b0591SJens Wiklander * Build and verify a certificate chain 23173d3b0591SJens Wiklander * 23183d3b0591SJens Wiklander * Given a peer-provided list of certificates EE, C1, ..., Cn and 23193d3b0591SJens Wiklander * a list of trusted certs R1, ... Rp, try to build and verify a chain 23203d3b0591SJens Wiklander * EE, Ci1, ... Ciq [, Rj] 23213d3b0591SJens Wiklander * such that every cert in the chain is a child of the next one, 23223d3b0591SJens Wiklander * jumping to a trusted root as early as possible. 23233d3b0591SJens Wiklander * 23243d3b0591SJens Wiklander * Verify that chain and return it with flags for all issues found. 23253d3b0591SJens Wiklander * 23263d3b0591SJens Wiklander * Special cases: 23273d3b0591SJens Wiklander * - EE == Rj -> return a one-element list containing it 23283d3b0591SJens Wiklander * - EE, Ci1, ..., Ciq cannot be continued with a trusted root 23293d3b0591SJens Wiklander * -> return that chain with NOT_TRUSTED set on Ciq 23303d3b0591SJens Wiklander * 23313d3b0591SJens Wiklander * Tests for (aspects of) this function should include at least: 23323d3b0591SJens Wiklander * - trusted EE 23333d3b0591SJens Wiklander * - EE -> trusted root 23345b25c76aSJerome Forissier * - EE -> intermediate CA -> trusted root 23353d3b0591SJens Wiklander * - if relevant: EE untrusted 23363d3b0591SJens Wiklander * - if relevant: EE -> intermediate, untrusted 23373d3b0591SJens Wiklander * with the aspect under test checked at each relevant level (EE, int, root). 23383d3b0591SJens Wiklander * For some aspects longer chains are required, but usually length 2 is 23393d3b0591SJens Wiklander * enough (but length 1 is not in general). 23403d3b0591SJens Wiklander * 23413d3b0591SJens Wiklander * Arguments: 23423d3b0591SJens Wiklander * - [in] crt: the cert list EE, C1, ..., Cn 23433d3b0591SJens Wiklander * - [in] trust_ca: the trusted list R1, ..., Rp 23443d3b0591SJens Wiklander * - [in] ca_crl, profile: as in verify_with_profile() 23453d3b0591SJens Wiklander * - [out] ver_chain: the built and verified chain 23463d3b0591SJens Wiklander * Only valid when return value is 0, may contain garbage otherwise! 23473d3b0591SJens Wiklander * Restart note: need not be the same when calling again to resume. 23483d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 23493d3b0591SJens Wiklander * 23503d3b0591SJens Wiklander * Return value: 23513d3b0591SJens Wiklander * - non-zero if the chain could not be fully built and examined 23523d3b0591SJens Wiklander * - 0 is the chain was successfully built and examined, 23533d3b0591SJens Wiklander * even if it was found to be invalid 23543d3b0591SJens Wiklander */ 23553d3b0591SJens Wiklander static int x509_crt_verify_chain( 23563d3b0591SJens Wiklander mbedtls_x509_crt *crt, 23573d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 23583d3b0591SJens Wiklander mbedtls_x509_crl *ca_crl, 235911fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 236011fa71b9SJerome Forissier void *p_ca_cb, 23613d3b0591SJens Wiklander const mbedtls_x509_crt_profile *profile, 23623d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain *ver_chain, 23633d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx) 23643d3b0591SJens Wiklander { 23653d3b0591SJens Wiklander /* Don't initialize any of those variables here, so that the compiler can 23663d3b0591SJens Wiklander * catch potential issues with jumping ahead when restarting */ 236711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 23683d3b0591SJens Wiklander uint32_t *flags; 23693d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain_item *cur; 23703d3b0591SJens Wiklander mbedtls_x509_crt *child; 23713d3b0591SJens Wiklander mbedtls_x509_crt *parent; 23723d3b0591SJens Wiklander int parent_is_trusted; 23733d3b0591SJens Wiklander int child_is_trusted; 23743d3b0591SJens Wiklander int signature_is_good; 23753d3b0591SJens Wiklander unsigned self_cnt; 237611fa71b9SJerome Forissier mbedtls_x509_crt *cur_trust_ca = NULL; 23773d3b0591SJens Wiklander 23783d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 23793d3b0591SJens Wiklander /* resume if we had an operation in progress */ 2380*32b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->in_progress == x509_crt_rs_find_parent) { 23813d3b0591SJens Wiklander /* restore saved state */ 23823d3b0591SJens Wiklander *ver_chain = rs_ctx->ver_chain; /* struct copy */ 23833d3b0591SJens Wiklander self_cnt = rs_ctx->self_cnt; 23843d3b0591SJens Wiklander 23853d3b0591SJens Wiklander /* restore derived state */ 23863d3b0591SJens Wiklander cur = &ver_chain->items[ver_chain->len - 1]; 23873d3b0591SJens Wiklander child = cur->crt; 23883d3b0591SJens Wiklander flags = &cur->flags; 23893d3b0591SJens Wiklander 23903d3b0591SJens Wiklander goto find_parent; 23913d3b0591SJens Wiklander } 23923d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ 23933d3b0591SJens Wiklander 23943d3b0591SJens Wiklander child = crt; 23953d3b0591SJens Wiklander self_cnt = 0; 23963d3b0591SJens Wiklander parent_is_trusted = 0; 23973d3b0591SJens Wiklander child_is_trusted = 0; 23983d3b0591SJens Wiklander 23993d3b0591SJens Wiklander while (1) { 24003d3b0591SJens Wiklander /* Add certificate to the verification chain */ 24013d3b0591SJens Wiklander cur = &ver_chain->items[ver_chain->len]; 24023d3b0591SJens Wiklander cur->crt = child; 24033d3b0591SJens Wiklander cur->flags = 0; 24043d3b0591SJens Wiklander ver_chain->len++; 24053d3b0591SJens Wiklander flags = &cur->flags; 24063d3b0591SJens Wiklander 24073d3b0591SJens Wiklander /* Check time-validity (all certificates) */ 2408*32b31808SJens Wiklander if (mbedtls_x509_time_is_past(&child->valid_to)) { 2409817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_EXPIRED; 2410*32b31808SJens Wiklander } 2411817466cbSJens Wiklander 2412*32b31808SJens Wiklander if (mbedtls_x509_time_is_future(&child->valid_from)) { 2413817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_FUTURE; 2414*32b31808SJens Wiklander } 2415817466cbSJens Wiklander 24163d3b0591SJens Wiklander /* Stop here for trusted roots (but not for trusted EE certs) */ 2417*32b31808SJens Wiklander if (child_is_trusted) { 2418*32b31808SJens Wiklander return 0; 2419*32b31808SJens Wiklander } 24203d3b0591SJens Wiklander 24213d3b0591SJens Wiklander /* Check signature algorithm: MD & PK algs */ 2422*32b31808SJens Wiklander if (x509_profile_check_md_alg(profile, child->sig_md) != 0) { 2423817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_MD; 2424*32b31808SJens Wiklander } 2425817466cbSJens Wiklander 2426*32b31808SJens Wiklander if (x509_profile_check_pk_alg(profile, child->sig_pk) != 0) { 2427817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_PK; 2428*32b31808SJens Wiklander } 2429817466cbSJens Wiklander 24303d3b0591SJens Wiklander /* Special case: EE certs that are locally trusted */ 24313d3b0591SJens Wiklander if (ver_chain->len == 1 && 2432*32b31808SJens Wiklander x509_crt_check_ee_locally_trusted(child, trust_ca) == 0) { 2433*32b31808SJens Wiklander return 0; 2434817466cbSJens Wiklander } 2435817466cbSJens Wiklander 24363d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 24373d3b0591SJens Wiklander find_parent: 24383d3b0591SJens Wiklander #endif 243911fa71b9SJerome Forissier 244011fa71b9SJerome Forissier /* Obtain list of potential trusted signers from CA callback, 244111fa71b9SJerome Forissier * or use statically provided list. */ 244211fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 2443*32b31808SJens Wiklander if (f_ca_cb != NULL) { 244411fa71b9SJerome Forissier mbedtls_x509_crt_free(ver_chain->trust_ca_cb_result); 244511fa71b9SJerome Forissier mbedtls_free(ver_chain->trust_ca_cb_result); 244611fa71b9SJerome Forissier ver_chain->trust_ca_cb_result = NULL; 244711fa71b9SJerome Forissier 244811fa71b9SJerome Forissier ret = f_ca_cb(p_ca_cb, child, &ver_chain->trust_ca_cb_result); 2449*32b31808SJens Wiklander if (ret != 0) { 2450*32b31808SJens Wiklander return MBEDTLS_ERR_X509_FATAL_ERROR; 2451*32b31808SJens Wiklander } 245211fa71b9SJerome Forissier 245311fa71b9SJerome Forissier cur_trust_ca = ver_chain->trust_ca_cb_result; 2454*32b31808SJens Wiklander } else 245511fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 245611fa71b9SJerome Forissier { 245711fa71b9SJerome Forissier ((void) f_ca_cb); 245811fa71b9SJerome Forissier ((void) p_ca_cb); 245911fa71b9SJerome Forissier cur_trust_ca = trust_ca; 246011fa71b9SJerome Forissier } 246111fa71b9SJerome Forissier 24623d3b0591SJens Wiklander /* Look for a parent in trusted CAs or up the chain */ 246311fa71b9SJerome Forissier ret = x509_crt_find_parent(child, cur_trust_ca, &parent, 24643d3b0591SJens Wiklander &parent_is_trusted, &signature_is_good, 24653d3b0591SJens Wiklander ver_chain->len - 1, self_cnt, rs_ctx); 24663d3b0591SJens Wiklander 24673d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 2468*32b31808SJens Wiklander if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 24693d3b0591SJens Wiklander /* save state */ 24703d3b0591SJens Wiklander rs_ctx->in_progress = x509_crt_rs_find_parent; 24713d3b0591SJens Wiklander rs_ctx->self_cnt = self_cnt; 24723d3b0591SJens Wiklander rs_ctx->ver_chain = *ver_chain; /* struct copy */ 24733d3b0591SJens Wiklander 2474*32b31808SJens Wiklander return ret; 24753d3b0591SJens Wiklander } 24763d3b0591SJens Wiklander #else 24773d3b0591SJens Wiklander (void) ret; 24783d3b0591SJens Wiklander #endif 24793d3b0591SJens Wiklander 24803d3b0591SJens Wiklander /* No parent? We're done here */ 2481*32b31808SJens Wiklander if (parent == NULL) { 24823d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; 2483*32b31808SJens Wiklander return 0; 24843d3b0591SJens Wiklander } 24853d3b0591SJens Wiklander 24863d3b0591SJens Wiklander /* Count intermediate self-issued (not necessarily self-signed) certs. 24873d3b0591SJens Wiklander * These can occur with some strategies for key rollover, see [SIRO], 24883d3b0591SJens Wiklander * and should be excluded from max_pathlen checks. */ 24893d3b0591SJens Wiklander if (ver_chain->len != 1 && 2490*32b31808SJens Wiklander x509_name_cmp(&child->issuer, &child->subject) == 0) { 24913d3b0591SJens Wiklander self_cnt++; 24923d3b0591SJens Wiklander } 24933d3b0591SJens Wiklander 24943d3b0591SJens Wiklander /* path_cnt is 0 for the first intermediate CA, 24953d3b0591SJens Wiklander * and if parent is trusted it's not an intermediate CA */ 24963d3b0591SJens Wiklander if (!parent_is_trusted && 2497*32b31808SJens Wiklander ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA) { 24983d3b0591SJens Wiklander /* return immediately to avoid overflow the chain array */ 2499*32b31808SJens Wiklander return MBEDTLS_ERR_X509_FATAL_ERROR; 25003d3b0591SJens Wiklander } 25013d3b0591SJens Wiklander 25023d3b0591SJens Wiklander /* signature was checked while searching parent */ 2503*32b31808SJens Wiklander if (!signature_is_good) { 25043d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; 2505*32b31808SJens Wiklander } 25063d3b0591SJens Wiklander 25073d3b0591SJens Wiklander /* check size of signing key */ 2508*32b31808SJens Wiklander if (x509_profile_check_key(profile, &parent->pk) != 0) { 2509817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 2510*32b31808SJens Wiklander } 2511817466cbSJens Wiklander 2512817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C) 2513817466cbSJens Wiklander /* Check trusted CA's CRL for the given crt */ 2514817466cbSJens Wiklander *flags |= x509_crt_verifycrl(child, parent, ca_crl, profile); 25153d3b0591SJens Wiklander #else 25163d3b0591SJens Wiklander (void) ca_crl; 2517817466cbSJens Wiklander #endif 2518817466cbSJens Wiklander 25193d3b0591SJens Wiklander /* prepare for next iteration */ 25203d3b0591SJens Wiklander child = parent; 25213d3b0591SJens Wiklander parent = NULL; 25223d3b0591SJens Wiklander child_is_trusted = parent_is_trusted; 25233d3b0591SJens Wiklander signature_is_good = 0; 25243d3b0591SJens Wiklander } 25253d3b0591SJens Wiklander } 25263d3b0591SJens Wiklander 25273d3b0591SJens Wiklander /* 25283d3b0591SJens Wiklander * Check for CN match 25293d3b0591SJens Wiklander */ 25303d3b0591SJens Wiklander static int x509_crt_check_cn(const mbedtls_x509_buf *name, 25313d3b0591SJens Wiklander const char *cn, size_t cn_len) 2532817466cbSJens Wiklander { 25333d3b0591SJens Wiklander /* try exact match */ 25343d3b0591SJens Wiklander if (name->len == cn_len && 2535*32b31808SJens Wiklander x509_memcasecmp(cn, name->p, cn_len) == 0) { 2536*32b31808SJens Wiklander return 0; 25373d3b0591SJens Wiklander } 25383d3b0591SJens Wiklander 25393d3b0591SJens Wiklander /* try wildcard match */ 2540*32b31808SJens Wiklander if (x509_check_wildcard(cn, name) == 0) { 2541*32b31808SJens Wiklander return 0; 25423d3b0591SJens Wiklander } 25433d3b0591SJens Wiklander 2544*32b31808SJens Wiklander return -1; 25453d3b0591SJens Wiklander } 25463d3b0591SJens Wiklander 25473d3b0591SJens Wiklander /* 25487901324dSJerome Forissier * Check for SAN match, see RFC 5280 Section 4.2.1.6 25497901324dSJerome Forissier */ 25507901324dSJerome Forissier static int x509_crt_check_san(const mbedtls_x509_buf *name, 25517901324dSJerome Forissier const char *cn, size_t cn_len) 25527901324dSJerome Forissier { 25537901324dSJerome Forissier const unsigned char san_type = (unsigned char) name->tag & 25547901324dSJerome Forissier MBEDTLS_ASN1_TAG_VALUE_MASK; 25557901324dSJerome Forissier 25567901324dSJerome Forissier /* dNSName */ 2557*32b31808SJens Wiklander if (san_type == MBEDTLS_X509_SAN_DNS_NAME) { 2558*32b31808SJens Wiklander return x509_crt_check_cn(name, cn, cn_len); 2559*32b31808SJens Wiklander } 25607901324dSJerome Forissier 25617901324dSJerome Forissier /* (We may handle other types here later.) */ 25627901324dSJerome Forissier 25637901324dSJerome Forissier /* Unrecognized type */ 2564*32b31808SJens Wiklander return -1; 25657901324dSJerome Forissier } 25667901324dSJerome Forissier 25677901324dSJerome Forissier /* 25683d3b0591SJens Wiklander * Verify the requested CN - only call this if cn is not NULL! 25693d3b0591SJens Wiklander */ 25703d3b0591SJens Wiklander static void x509_crt_verify_name(const mbedtls_x509_crt *crt, 25713d3b0591SJens Wiklander const char *cn, 25723d3b0591SJens Wiklander uint32_t *flags) 25733d3b0591SJens Wiklander { 25743d3b0591SJens Wiklander const mbedtls_x509_name *name; 25753d3b0591SJens Wiklander const mbedtls_x509_sequence *cur; 25763d3b0591SJens Wiklander size_t cn_len = strlen(cn); 25773d3b0591SJens Wiklander 2578*32b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) { 2579*32b31808SJens Wiklander for (cur = &crt->subject_alt_names; cur != NULL; cur = cur->next) { 2580*32b31808SJens Wiklander if (x509_crt_check_san(&cur->buf, cn, cn_len) == 0) { 2581817466cbSJens Wiklander break; 2582817466cbSJens Wiklander } 2583*32b31808SJens Wiklander } 2584817466cbSJens Wiklander 2585*32b31808SJens Wiklander if (cur == NULL) { 25863d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; 2587817466cbSJens Wiklander } 2588*32b31808SJens Wiklander } else { 2589*32b31808SJens Wiklander for (name = &crt->subject; name != NULL; name = name->next) { 25903d3b0591SJens Wiklander if (MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid) == 0 && 2591*32b31808SJens Wiklander x509_crt_check_cn(&name->val, cn, cn_len) == 0) { 2592817466cbSJens Wiklander break; 2593817466cbSJens Wiklander } 2594817466cbSJens Wiklander } 25953d3b0591SJens Wiklander 2596*32b31808SJens Wiklander if (name == NULL) { 25973d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; 2598817466cbSJens Wiklander } 2599817466cbSJens Wiklander } 2600*32b31808SJens Wiklander } 2601817466cbSJens Wiklander 26023d3b0591SJens Wiklander /* 26033d3b0591SJens Wiklander * Merge the flags for all certs in the chain, after calling callback 26043d3b0591SJens Wiklander */ 26053d3b0591SJens Wiklander static int x509_crt_merge_flags_with_cb( 26063d3b0591SJens Wiklander uint32_t *flags, 26073d3b0591SJens Wiklander const mbedtls_x509_crt_verify_chain *ver_chain, 26083d3b0591SJens Wiklander int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 26093d3b0591SJens Wiklander void *p_vrfy) 26103d3b0591SJens Wiklander { 261111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 26123d3b0591SJens Wiklander unsigned i; 26133d3b0591SJens Wiklander uint32_t cur_flags; 26143d3b0591SJens Wiklander const mbedtls_x509_crt_verify_chain_item *cur; 26153d3b0591SJens Wiklander 2616*32b31808SJens Wiklander for (i = ver_chain->len; i != 0; --i) { 26173d3b0591SJens Wiklander cur = &ver_chain->items[i-1]; 26183d3b0591SJens Wiklander cur_flags = cur->flags; 26193d3b0591SJens Wiklander 2620*32b31808SJens Wiklander if (NULL != f_vrfy) { 2621*32b31808SJens Wiklander if ((ret = f_vrfy(p_vrfy, cur->crt, (int) i-1, &cur_flags)) != 0) { 2622*32b31808SJens Wiklander return ret; 2623*32b31808SJens Wiklander } 2624*32b31808SJens Wiklander } 2625817466cbSJens Wiklander 26263d3b0591SJens Wiklander *flags |= cur_flags; 26273d3b0591SJens Wiklander } 2628817466cbSJens Wiklander 2629*32b31808SJens Wiklander return 0; 2630817466cbSJens Wiklander } 2631817466cbSJens Wiklander 2632817466cbSJens Wiklander /* 26333d3b0591SJens Wiklander * Verify the certificate validity, with profile, restartable version 26343d3b0591SJens Wiklander * 26353d3b0591SJens Wiklander * This function: 26363d3b0591SJens Wiklander * - checks the requested CN (if any) 26373d3b0591SJens Wiklander * - checks the type and size of the EE cert's key, 26383d3b0591SJens Wiklander * as that isn't done as part of chain building/verification currently 26393d3b0591SJens Wiklander * - builds and verifies the chain 26403d3b0591SJens Wiklander * - then calls the callback and merges the flags 264111fa71b9SJerome Forissier * 264211fa71b9SJerome Forissier * The parameters pairs `trust_ca`, `ca_crl` and `f_ca_cb`, `p_ca_cb` 264311fa71b9SJerome Forissier * are mutually exclusive: If `f_ca_cb != NULL`, it will be used by the 264411fa71b9SJerome Forissier * verification routine to search for trusted signers, and CRLs will 264511fa71b9SJerome Forissier * be disabled. Otherwise, `trust_ca` will be used as the static list 264611fa71b9SJerome Forissier * of trusted signers, and `ca_crl` will be use as the static list 264711fa71b9SJerome Forissier * of CRLs. 26483d3b0591SJens Wiklander */ 264911fa71b9SJerome Forissier static int x509_crt_verify_restartable_ca_cb(mbedtls_x509_crt *crt, 26503d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 26513d3b0591SJens Wiklander mbedtls_x509_crl *ca_crl, 265211fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 265311fa71b9SJerome Forissier void *p_ca_cb, 26543d3b0591SJens Wiklander const mbedtls_x509_crt_profile *profile, 26553d3b0591SJens Wiklander const char *cn, uint32_t *flags, 2656*32b31808SJens Wiklander int (*f_vrfy)(void *, 2657*32b31808SJens Wiklander mbedtls_x509_crt *, 2658*32b31808SJens Wiklander int, 2659*32b31808SJens Wiklander uint32_t *), 26603d3b0591SJens Wiklander void *p_vrfy, 26613d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx) 26623d3b0591SJens Wiklander { 266311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2664817466cbSJens Wiklander mbedtls_pk_type_t pk_type; 26653d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain ver_chain; 26663d3b0591SJens Wiklander uint32_t ee_flags; 2667817466cbSJens Wiklander 2668817466cbSJens Wiklander *flags = 0; 26693d3b0591SJens Wiklander ee_flags = 0; 26703d3b0591SJens Wiklander x509_crt_verify_chain_reset(&ver_chain); 2671817466cbSJens Wiklander 2672*32b31808SJens Wiklander if (profile == NULL) { 2673817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; 2674817466cbSJens Wiklander goto exit; 2675817466cbSJens Wiklander } 2676817466cbSJens Wiklander 26773d3b0591SJens Wiklander /* check name if requested */ 2678*32b31808SJens Wiklander if (cn != NULL) { 26793d3b0591SJens Wiklander x509_crt_verify_name(crt, cn, &ee_flags); 2680*32b31808SJens Wiklander } 2681817466cbSJens Wiklander 2682817466cbSJens Wiklander /* Check the type and size of the key */ 2683817466cbSJens Wiklander pk_type = mbedtls_pk_get_type(&crt->pk); 2684817466cbSJens Wiklander 2685*32b31808SJens Wiklander if (x509_profile_check_pk_alg(profile, pk_type) != 0) { 26863d3b0591SJens Wiklander ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK; 2687*32b31808SJens Wiklander } 2688817466cbSJens Wiklander 2689*32b31808SJens Wiklander if (x509_profile_check_key(profile, &crt->pk) != 0) { 26903d3b0591SJens Wiklander ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 2691*32b31808SJens Wiklander } 2692817466cbSJens Wiklander 26933d3b0591SJens Wiklander /* Check the chain */ 269411fa71b9SJerome Forissier ret = x509_crt_verify_chain(crt, trust_ca, ca_crl, 269511fa71b9SJerome Forissier f_ca_cb, p_ca_cb, profile, 26963d3b0591SJens Wiklander &ver_chain, rs_ctx); 2697817466cbSJens Wiklander 2698*32b31808SJens Wiklander if (ret != 0) { 2699817466cbSJens Wiklander goto exit; 2700*32b31808SJens Wiklander } 2701817466cbSJens Wiklander 27023d3b0591SJens Wiklander /* Merge end-entity flags */ 27033d3b0591SJens Wiklander ver_chain.items[0].flags |= ee_flags; 27043d3b0591SJens Wiklander 27053d3b0591SJens Wiklander /* Build final flags, calling callback on the way if any */ 27063d3b0591SJens Wiklander ret = x509_crt_merge_flags_with_cb(flags, &ver_chain, f_vrfy, p_vrfy); 2707817466cbSJens Wiklander 2708817466cbSJens Wiklander exit: 270911fa71b9SJerome Forissier 271011fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 271111fa71b9SJerome Forissier mbedtls_x509_crt_free(ver_chain.trust_ca_cb_result); 271211fa71b9SJerome Forissier mbedtls_free(ver_chain.trust_ca_cb_result); 271311fa71b9SJerome Forissier ver_chain.trust_ca_cb_result = NULL; 271411fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 271511fa71b9SJerome Forissier 27163d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 2717*32b31808SJens Wiklander if (rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS) { 27183d3b0591SJens Wiklander mbedtls_x509_crt_restart_free(rs_ctx); 2719*32b31808SJens Wiklander } 27203d3b0591SJens Wiklander #endif 27213d3b0591SJens Wiklander 2722817466cbSJens Wiklander /* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by 2723817466cbSJens Wiklander * the SSL module for authmode optional, but non-zero return from the 2724817466cbSJens Wiklander * callback means a fatal error so it shouldn't be ignored */ 2725*32b31808SJens Wiklander if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { 2726817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FATAL_ERROR; 2727817466cbSJens Wiklander } 2728817466cbSJens Wiklander 2729*32b31808SJens Wiklander if (ret != 0) { 2730*32b31808SJens Wiklander *flags = (uint32_t) -1; 2731*32b31808SJens Wiklander return ret; 2732*32b31808SJens Wiklander } 2733817466cbSJens Wiklander 2734*32b31808SJens Wiklander if (*flags != 0) { 2735*32b31808SJens Wiklander return MBEDTLS_ERR_X509_CERT_VERIFY_FAILED; 2736*32b31808SJens Wiklander } 2737*32b31808SJens Wiklander 2738*32b31808SJens Wiklander return 0; 2739817466cbSJens Wiklander } 2740817466cbSJens Wiklander 274111fa71b9SJerome Forissier 274211fa71b9SJerome Forissier /* 274311fa71b9SJerome Forissier * Verify the certificate validity (default profile, not restartable) 274411fa71b9SJerome Forissier */ 274511fa71b9SJerome Forissier int mbedtls_x509_crt_verify(mbedtls_x509_crt *crt, 274611fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 274711fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 274811fa71b9SJerome Forissier const char *cn, uint32_t *flags, 274911fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 275011fa71b9SJerome Forissier void *p_vrfy) 275111fa71b9SJerome Forissier { 2752*32b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl, 275311fa71b9SJerome Forissier NULL, NULL, 275411fa71b9SJerome Forissier &mbedtls_x509_crt_profile_default, 275511fa71b9SJerome Forissier cn, flags, 2756*32b31808SJens Wiklander f_vrfy, p_vrfy, NULL); 275711fa71b9SJerome Forissier } 275811fa71b9SJerome Forissier 275911fa71b9SJerome Forissier /* 276011fa71b9SJerome Forissier * Verify the certificate validity (user-chosen profile, not restartable) 276111fa71b9SJerome Forissier */ 276211fa71b9SJerome Forissier int mbedtls_x509_crt_verify_with_profile(mbedtls_x509_crt *crt, 276311fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 276411fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 276511fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 276611fa71b9SJerome Forissier const char *cn, uint32_t *flags, 276711fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 276811fa71b9SJerome Forissier void *p_vrfy) 276911fa71b9SJerome Forissier { 2770*32b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl, 277111fa71b9SJerome Forissier NULL, NULL, 277211fa71b9SJerome Forissier profile, cn, flags, 2773*32b31808SJens Wiklander f_vrfy, p_vrfy, NULL); 277411fa71b9SJerome Forissier } 277511fa71b9SJerome Forissier 277611fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 277711fa71b9SJerome Forissier /* 277811fa71b9SJerome Forissier * Verify the certificate validity (user-chosen profile, CA callback, 277911fa71b9SJerome Forissier * not restartable). 278011fa71b9SJerome Forissier */ 278111fa71b9SJerome Forissier int mbedtls_x509_crt_verify_with_ca_cb(mbedtls_x509_crt *crt, 278211fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 278311fa71b9SJerome Forissier void *p_ca_cb, 278411fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 278511fa71b9SJerome Forissier const char *cn, uint32_t *flags, 278611fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 278711fa71b9SJerome Forissier void *p_vrfy) 278811fa71b9SJerome Forissier { 2789*32b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, NULL, NULL, 279011fa71b9SJerome Forissier f_ca_cb, p_ca_cb, 279111fa71b9SJerome Forissier profile, cn, flags, 2792*32b31808SJens Wiklander f_vrfy, p_vrfy, NULL); 279311fa71b9SJerome Forissier } 279411fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 279511fa71b9SJerome Forissier 279611fa71b9SJerome Forissier int mbedtls_x509_crt_verify_restartable(mbedtls_x509_crt *crt, 279711fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 279811fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 279911fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 280011fa71b9SJerome Forissier const char *cn, uint32_t *flags, 280111fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 280211fa71b9SJerome Forissier void *p_vrfy, 280311fa71b9SJerome Forissier mbedtls_x509_crt_restart_ctx *rs_ctx) 280411fa71b9SJerome Forissier { 2805*32b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl, 280611fa71b9SJerome Forissier NULL, NULL, 280711fa71b9SJerome Forissier profile, cn, flags, 2808*32b31808SJens Wiklander f_vrfy, p_vrfy, rs_ctx); 280911fa71b9SJerome Forissier } 281011fa71b9SJerome Forissier 281111fa71b9SJerome Forissier 2812817466cbSJens Wiklander /* 2813817466cbSJens Wiklander * Initialize a certificate chain 2814817466cbSJens Wiklander */ 2815817466cbSJens Wiklander void mbedtls_x509_crt_init(mbedtls_x509_crt *crt) 2816817466cbSJens Wiklander { 2817817466cbSJens Wiklander memset(crt, 0, sizeof(mbedtls_x509_crt)); 2818817466cbSJens Wiklander } 2819817466cbSJens Wiklander 2820817466cbSJens Wiklander /* 2821817466cbSJens Wiklander * Unallocate all certificate data 2822817466cbSJens Wiklander */ 2823817466cbSJens Wiklander void mbedtls_x509_crt_free(mbedtls_x509_crt *crt) 2824817466cbSJens Wiklander { 2825817466cbSJens Wiklander mbedtls_x509_crt *cert_cur = crt; 2826817466cbSJens Wiklander mbedtls_x509_crt *cert_prv; 2827817466cbSJens Wiklander 2828*32b31808SJens Wiklander while (cert_cur != NULL) { 2829817466cbSJens Wiklander mbedtls_pk_free(&cert_cur->pk); 2830817466cbSJens Wiklander 2831817466cbSJens Wiklander #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) 2832817466cbSJens Wiklander mbedtls_free(cert_cur->sig_opts); 2833817466cbSJens Wiklander #endif 2834817466cbSJens Wiklander 2835*32b31808SJens Wiklander mbedtls_asn1_free_named_data_list_shallow(cert_cur->issuer.next); 2836*32b31808SJens Wiklander mbedtls_asn1_free_named_data_list_shallow(cert_cur->subject.next); 2837*32b31808SJens Wiklander mbedtls_asn1_sequence_free(cert_cur->ext_key_usage.next); 2838*32b31808SJens Wiklander mbedtls_asn1_sequence_free(cert_cur->subject_alt_names.next); 2839*32b31808SJens Wiklander mbedtls_asn1_sequence_free(cert_cur->certificate_policies.next); 2840817466cbSJens Wiklander 2841*32b31808SJens Wiklander if (cert_cur->raw.p != NULL && cert_cur->own_buffer) { 28423d3b0591SJens Wiklander mbedtls_platform_zeroize(cert_cur->raw.p, cert_cur->raw.len); 2843817466cbSJens Wiklander mbedtls_free(cert_cur->raw.p); 2844817466cbSJens Wiklander } 2845817466cbSJens Wiklander 2846817466cbSJens Wiklander cert_prv = cert_cur; 2847817466cbSJens Wiklander cert_cur = cert_cur->next; 2848817466cbSJens Wiklander 28493d3b0591SJens Wiklander mbedtls_platform_zeroize(cert_prv, sizeof(mbedtls_x509_crt)); 2850*32b31808SJens Wiklander if (cert_prv != crt) { 2851817466cbSJens Wiklander mbedtls_free(cert_prv); 2852817466cbSJens Wiklander } 2853*32b31808SJens Wiklander } 2854817466cbSJens Wiklander } 2855817466cbSJens Wiklander 28563d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 28573d3b0591SJens Wiklander /* 28583d3b0591SJens Wiklander * Initialize a restart context 28593d3b0591SJens Wiklander */ 28603d3b0591SJens Wiklander void mbedtls_x509_crt_restart_init(mbedtls_x509_crt_restart_ctx *ctx) 28613d3b0591SJens Wiklander { 28623d3b0591SJens Wiklander mbedtls_pk_restart_init(&ctx->pk); 28633d3b0591SJens Wiklander 28643d3b0591SJens Wiklander ctx->parent = NULL; 28653d3b0591SJens Wiklander ctx->fallback_parent = NULL; 28663d3b0591SJens Wiklander ctx->fallback_signature_is_good = 0; 28673d3b0591SJens Wiklander 28683d3b0591SJens Wiklander ctx->parent_is_trusted = -1; 28693d3b0591SJens Wiklander 28703d3b0591SJens Wiklander ctx->in_progress = x509_crt_rs_none; 28713d3b0591SJens Wiklander ctx->self_cnt = 0; 28723d3b0591SJens Wiklander x509_crt_verify_chain_reset(&ctx->ver_chain); 28733d3b0591SJens Wiklander } 28743d3b0591SJens Wiklander 28753d3b0591SJens Wiklander /* 28763d3b0591SJens Wiklander * Free the components of a restart context 28773d3b0591SJens Wiklander */ 28783d3b0591SJens Wiklander void mbedtls_x509_crt_restart_free(mbedtls_x509_crt_restart_ctx *ctx) 28793d3b0591SJens Wiklander { 2880*32b31808SJens Wiklander if (ctx == NULL) { 28813d3b0591SJens Wiklander return; 2882*32b31808SJens Wiklander } 28833d3b0591SJens Wiklander 28843d3b0591SJens Wiklander mbedtls_pk_restart_free(&ctx->pk); 28853d3b0591SJens Wiklander mbedtls_x509_crt_restart_init(ctx); 28863d3b0591SJens Wiklander } 28873d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ 28883d3b0591SJens Wiklander 2889817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRT_PARSE_C */ 2890