1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * X.509 certificate parsing and verification 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 5*b0563631STom Van Eyck * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6817466cbSJens Wiklander */ 7817466cbSJens Wiklander /* 8817466cbSJens Wiklander * The ITU-T X.509 standard defines a certificate format for PKI. 9817466cbSJens Wiklander * 10817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) 11817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) 12817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) 13817466cbSJens Wiklander * 14817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf 15817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf 163d3b0591SJens Wiklander * 173d3b0591SJens Wiklander * [SIRO] https://cabforum.org/wp-content/uploads/Chunghwatelecom201503cabforumV4.pdf 18817466cbSJens Wiklander */ 19817466cbSJens Wiklander 207901324dSJerome Forissier #include "common.h" 21817466cbSJens Wiklander 22817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRT_PARSE_C) 23817466cbSJens Wiklander 24817466cbSJens Wiklander #include "mbedtls/x509_crt.h" 25*b0563631STom Van Eyck #include "x509_internal.h" 2611fa71b9SJerome Forissier #include "mbedtls/error.h" 27817466cbSJens Wiklander #include "mbedtls/oid.h" 283d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 29817466cbSJens Wiklander 30817466cbSJens Wiklander #include <string.h> 31817466cbSJens Wiklander 32817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 33817466cbSJens Wiklander #include "mbedtls/pem.h" 34817466cbSJens Wiklander #endif 35817466cbSJens Wiklander 3611fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 3711fa71b9SJerome Forissier #include "psa/crypto.h" 38*b0563631STom Van Eyck #include "psa_util_internal.h" 3911fa71b9SJerome Forissier #include "mbedtls/psa_util.h" 4032b31808SJens Wiklander #endif /* MBEDTLS_USE_PSA_CRYPTO */ 41*b0563631STom Van Eyck #include "pk_internal.h" 4211fa71b9SJerome Forissier 43817466cbSJens Wiklander #include "mbedtls/platform.h" 44817466cbSJens Wiklander 45817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 46817466cbSJens Wiklander #include "mbedtls/threading.h" 47817466cbSJens Wiklander #endif 48817466cbSJens Wiklander 49039e02dfSJerome Forissier #if defined(MBEDTLS_HAVE_TIME) 50817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 51*b0563631STom Van Eyck #define WIN32_LEAN_AND_MEAN 52817466cbSJens Wiklander #include <windows.h> 53817466cbSJens Wiklander #else 54817466cbSJens Wiklander #include <time.h> 55817466cbSJens Wiklander #endif 56039e02dfSJerome Forissier #endif 57817466cbSJens Wiklander 58817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 59817466cbSJens Wiklander #include <stdio.h> 60817466cbSJens Wiklander #if !defined(_WIN32) || defined(EFIX64) || defined(EFI32) 61817466cbSJens Wiklander #include <sys/types.h> 62817466cbSJens Wiklander #include <sys/stat.h> 6332b31808SJens Wiklander #if defined(__MBED__) 6432b31808SJens Wiklander #include <platform/mbed_retarget.h> 6532b31808SJens Wiklander #else 66817466cbSJens Wiklander #include <dirent.h> 6732b31808SJens Wiklander #endif /* __MBED__ */ 6832b31808SJens Wiklander #include <errno.h> 69817466cbSJens Wiklander #endif /* !_WIN32 || EFIX64 || EFI32 */ 70817466cbSJens Wiklander #endif 71817466cbSJens Wiklander 723d3b0591SJens Wiklander /* 733d3b0591SJens Wiklander * Item in a verification chain: cert and flags for it 743d3b0591SJens Wiklander */ 753d3b0591SJens Wiklander typedef struct { 763d3b0591SJens Wiklander mbedtls_x509_crt *crt; 773d3b0591SJens Wiklander uint32_t flags; 783d3b0591SJens Wiklander } x509_crt_verify_chain_item; 793d3b0591SJens Wiklander 803d3b0591SJens Wiklander /* 813d3b0591SJens Wiklander * Max size of verification chain: end-entity + intermediates + trusted root 823d3b0591SJens Wiklander */ 833d3b0591SJens Wiklander #define X509_MAX_VERIFY_CHAIN_SIZE (MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2) 84817466cbSJens Wiklander 857901324dSJerome Forissier /* Default profile. Do not remove items unless there are serious security 867901324dSJerome Forissier * concerns. */ 87817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default = 88817466cbSJens Wiklander { 8932b31808SJens Wiklander /* Hashes from SHA-256 and above. Note that this selection 9032b31808SJens Wiklander * should be aligned with ssl_preset_default_hashes in ssl_tls.c. */ 91817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | 92817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | 93817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), 94817466cbSJens Wiklander 0xFFFFFFF, /* Any PK alg */ 95*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS) 9632b31808SJens Wiklander /* Curves at or above 128-bit security level. Note that this selection 9732b31808SJens Wiklander * should be aligned with ssl_preset_default_curves in ssl_tls.c. */ 9832b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) | 9932b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1) | 10032b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP521R1) | 10132b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP256R1) | 10232b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP384R1) | 10332b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP512R1) | 10432b31808SJens Wiklander 0, 105*b0563631STom Van Eyck #else /* MBEDTLS_PK_HAVE_ECC_KEYS */ 10632b31808SJens Wiklander 0, 107*b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ 10832b31808SJens Wiklander 2048, 10932b31808SJens Wiklander }; 11032b31808SJens Wiklander 11132b31808SJens Wiklander /* Next-generation profile. Currently identical to the default, but may 11232b31808SJens Wiklander * be tightened at any time. */ 11332b31808SJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next = 11432b31808SJens Wiklander { 11532b31808SJens Wiklander /* Hashes from SHA-256 and above. */ 11632b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | 11732b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | 11832b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), 11932b31808SJens Wiklander 0xFFFFFFF, /* Any PK alg */ 12032b31808SJens Wiklander #if defined(MBEDTLS_ECP_C) 12132b31808SJens Wiklander /* Curves at or above 128-bit security level. */ 122817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) | 123817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1) | 124817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP521R1) | 125817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP256R1) | 126817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP384R1) | 127817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP512R1) | 128817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256K1), 129817466cbSJens Wiklander #else 130817466cbSJens Wiklander 0, 131817466cbSJens Wiklander #endif 132817466cbSJens Wiklander 2048, 133817466cbSJens Wiklander }; 134817466cbSJens Wiklander 135817466cbSJens Wiklander /* 136817466cbSJens Wiklander * NSA Suite B Profile 137817466cbSJens Wiklander */ 138817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb = 139817466cbSJens Wiklander { 140817466cbSJens Wiklander /* Only SHA-256 and 384 */ 141817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | 142817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384), 143817466cbSJens Wiklander /* Only ECDSA */ 1443d3b0591SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECDSA) | 1453d3b0591SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECKEY), 146*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS) 147817466cbSJens Wiklander /* Only NIST P-256 and P-384 */ 148817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) | 149817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1), 150*b0563631STom Van Eyck #else /* MBEDTLS_PK_HAVE_ECC_KEYS */ 151817466cbSJens Wiklander 0, 152*b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ 153817466cbSJens Wiklander 0, 154817466cbSJens Wiklander }; 155817466cbSJens Wiklander 156817466cbSJens Wiklander /* 15732b31808SJens Wiklander * Empty / all-forbidden profile 15832b31808SJens Wiklander */ 15932b31808SJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_none = 16032b31808SJens Wiklander { 16132b31808SJens Wiklander 0, 16232b31808SJens Wiklander 0, 16332b31808SJens Wiklander 0, 16432b31808SJens Wiklander (uint32_t) -1, 16532b31808SJens Wiklander }; 16632b31808SJens Wiklander 16732b31808SJens Wiklander /* 168817466cbSJens Wiklander * Check md_alg against profile 1693d3b0591SJens Wiklander * Return 0 if md_alg is acceptable for this profile, -1 otherwise 170817466cbSJens Wiklander */ 171817466cbSJens Wiklander static int x509_profile_check_md_alg(const mbedtls_x509_crt_profile *profile, 172817466cbSJens Wiklander mbedtls_md_type_t md_alg) 173817466cbSJens Wiklander { 17432b31808SJens Wiklander if (md_alg == MBEDTLS_MD_NONE) { 17532b31808SJens Wiklander return -1; 17632b31808SJens Wiklander } 1773d3b0591SJens Wiklander 17832b31808SJens Wiklander if ((profile->allowed_mds & MBEDTLS_X509_ID_FLAG(md_alg)) != 0) { 17932b31808SJens Wiklander return 0; 18032b31808SJens Wiklander } 181817466cbSJens Wiklander 18232b31808SJens Wiklander return -1; 183817466cbSJens Wiklander } 184817466cbSJens Wiklander 185817466cbSJens Wiklander /* 186817466cbSJens Wiklander * Check pk_alg against profile 1873d3b0591SJens Wiklander * Return 0 if pk_alg is acceptable for this profile, -1 otherwise 188817466cbSJens Wiklander */ 189817466cbSJens Wiklander static int x509_profile_check_pk_alg(const mbedtls_x509_crt_profile *profile, 190817466cbSJens Wiklander mbedtls_pk_type_t pk_alg) 191817466cbSJens Wiklander { 19232b31808SJens Wiklander if (pk_alg == MBEDTLS_PK_NONE) { 19332b31808SJens Wiklander return -1; 19432b31808SJens Wiklander } 1953d3b0591SJens Wiklander 19632b31808SJens Wiklander if ((profile->allowed_pks & MBEDTLS_X509_ID_FLAG(pk_alg)) != 0) { 19732b31808SJens Wiklander return 0; 19832b31808SJens Wiklander } 199817466cbSJens Wiklander 20032b31808SJens Wiklander return -1; 201817466cbSJens Wiklander } 202817466cbSJens Wiklander 203817466cbSJens Wiklander /* 204817466cbSJens Wiklander * Check key against profile 2053d3b0591SJens Wiklander * Return 0 if pk is acceptable for this profile, -1 otherwise 206817466cbSJens Wiklander */ 207817466cbSJens Wiklander static int x509_profile_check_key(const mbedtls_x509_crt_profile *profile, 208817466cbSJens Wiklander const mbedtls_pk_context *pk) 209817466cbSJens Wiklander { 2103d3b0591SJens Wiklander const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type(pk); 2113d3b0591SJens Wiklander 212817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 21332b31808SJens Wiklander if (pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS) { 21432b31808SJens Wiklander if (mbedtls_pk_get_bitlen(pk) >= profile->rsa_min_bitlen) { 21532b31808SJens Wiklander return 0; 21632b31808SJens Wiklander } 217817466cbSJens Wiklander 21832b31808SJens Wiklander return -1; 219817466cbSJens Wiklander } 220*b0563631STom Van Eyck #endif /* MBEDTLS_RSA_C */ 221817466cbSJens Wiklander 222*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS) 223817466cbSJens Wiklander if (pk_alg == MBEDTLS_PK_ECDSA || 224817466cbSJens Wiklander pk_alg == MBEDTLS_PK_ECKEY || 22532b31808SJens Wiklander pk_alg == MBEDTLS_PK_ECKEY_DH) { 226*b0563631STom Van Eyck const mbedtls_ecp_group_id gid = mbedtls_pk_get_ec_group_id(pk); 2273d3b0591SJens Wiklander 22832b31808SJens Wiklander if (gid == MBEDTLS_ECP_DP_NONE) { 22932b31808SJens Wiklander return -1; 23032b31808SJens Wiklander } 231817466cbSJens Wiklander 23232b31808SJens Wiklander if ((profile->allowed_curves & MBEDTLS_X509_ID_FLAG(gid)) != 0) { 23332b31808SJens Wiklander return 0; 23432b31808SJens Wiklander } 235817466cbSJens Wiklander 23632b31808SJens Wiklander return -1; 237817466cbSJens Wiklander } 238*b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ 239817466cbSJens Wiklander 24032b31808SJens Wiklander return -1; 241817466cbSJens Wiklander } 242817466cbSJens Wiklander 243817466cbSJens Wiklander /* 2443d3b0591SJens Wiklander * Like memcmp, but case-insensitive and always returns -1 if different 2453d3b0591SJens Wiklander */ 2463d3b0591SJens Wiklander static int x509_memcasecmp(const void *s1, const void *s2, size_t len) 2473d3b0591SJens Wiklander { 2483d3b0591SJens Wiklander size_t i; 2493d3b0591SJens Wiklander unsigned char diff; 2503d3b0591SJens Wiklander const unsigned char *n1 = s1, *n2 = s2; 2513d3b0591SJens Wiklander 25232b31808SJens Wiklander for (i = 0; i < len; i++) { 2533d3b0591SJens Wiklander diff = n1[i] ^ n2[i]; 2543d3b0591SJens Wiklander 25532b31808SJens Wiklander if (diff == 0) { 2563d3b0591SJens Wiklander continue; 25732b31808SJens Wiklander } 2583d3b0591SJens Wiklander 2593d3b0591SJens Wiklander if (diff == 32 && 2603d3b0591SJens Wiklander ((n1[i] >= 'a' && n1[i] <= 'z') || 26132b31808SJens Wiklander (n1[i] >= 'A' && n1[i] <= 'Z'))) { 2623d3b0591SJens Wiklander continue; 2633d3b0591SJens Wiklander } 2643d3b0591SJens Wiklander 26532b31808SJens Wiklander return -1; 2663d3b0591SJens Wiklander } 2673d3b0591SJens Wiklander 26832b31808SJens Wiklander return 0; 2693d3b0591SJens Wiklander } 2703d3b0591SJens Wiklander 2713d3b0591SJens Wiklander /* 2723d3b0591SJens Wiklander * Return 0 if name matches wildcard, -1 otherwise 2733d3b0591SJens Wiklander */ 2743d3b0591SJens Wiklander static int x509_check_wildcard(const char *cn, const mbedtls_x509_buf *name) 2753d3b0591SJens Wiklander { 2763d3b0591SJens Wiklander size_t i; 2773d3b0591SJens Wiklander size_t cn_idx = 0, cn_len = strlen(cn); 2783d3b0591SJens Wiklander 2793d3b0591SJens Wiklander /* We can't have a match if there is no wildcard to match */ 28032b31808SJens Wiklander if (name->len < 3 || name->p[0] != '*' || name->p[1] != '.') { 28132b31808SJens Wiklander return -1; 28232b31808SJens Wiklander } 2833d3b0591SJens Wiklander 28432b31808SJens Wiklander for (i = 0; i < cn_len; ++i) { 28532b31808SJens Wiklander if (cn[i] == '.') { 2863d3b0591SJens Wiklander cn_idx = i; 2873d3b0591SJens Wiklander break; 2883d3b0591SJens Wiklander } 2893d3b0591SJens Wiklander } 2903d3b0591SJens Wiklander 29132b31808SJens Wiklander if (cn_idx == 0) { 29232b31808SJens Wiklander return -1; 2933d3b0591SJens Wiklander } 2943d3b0591SJens Wiklander 29532b31808SJens Wiklander if (cn_len - cn_idx == name->len - 1 && 29632b31808SJens Wiklander x509_memcasecmp(name->p + 1, cn + cn_idx, name->len - 1) == 0) { 29732b31808SJens Wiklander return 0; 29832b31808SJens Wiklander } 29932b31808SJens Wiklander 30032b31808SJens Wiklander return -1; 3013d3b0591SJens Wiklander } 3023d3b0591SJens Wiklander 3033d3b0591SJens Wiklander /* 3043d3b0591SJens Wiklander * Compare two X.509 strings, case-insensitive, and allowing for some encoding 3053d3b0591SJens Wiklander * variations (but not all). 3063d3b0591SJens Wiklander * 3073d3b0591SJens Wiklander * Return 0 if equal, -1 otherwise. 3083d3b0591SJens Wiklander */ 3093d3b0591SJens Wiklander static int x509_string_cmp(const mbedtls_x509_buf *a, const mbedtls_x509_buf *b) 3103d3b0591SJens Wiklander { 3113d3b0591SJens Wiklander if (a->tag == b->tag && 3123d3b0591SJens Wiklander a->len == b->len && 31332b31808SJens Wiklander memcmp(a->p, b->p, b->len) == 0) { 31432b31808SJens Wiklander return 0; 3153d3b0591SJens Wiklander } 3163d3b0591SJens Wiklander 3173d3b0591SJens Wiklander if ((a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING) && 3183d3b0591SJens Wiklander (b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING) && 3193d3b0591SJens Wiklander a->len == b->len && 32032b31808SJens Wiklander x509_memcasecmp(a->p, b->p, b->len) == 0) { 32132b31808SJens Wiklander return 0; 3223d3b0591SJens Wiklander } 3233d3b0591SJens Wiklander 32432b31808SJens Wiklander return -1; 3253d3b0591SJens Wiklander } 3263d3b0591SJens Wiklander 3273d3b0591SJens Wiklander /* 3283d3b0591SJens Wiklander * Compare two X.509 Names (aka rdnSequence). 3293d3b0591SJens Wiklander * 3303d3b0591SJens Wiklander * See RFC 5280 section 7.1, though we don't implement the whole algorithm: 3313d3b0591SJens Wiklander * we sometimes return unequal when the full algorithm would return equal, 3323d3b0591SJens Wiklander * but never the other way. (In particular, we don't do Unicode normalisation 3333d3b0591SJens Wiklander * or space folding.) 3343d3b0591SJens Wiklander * 3353d3b0591SJens Wiklander * Return 0 if equal, -1 otherwise. 3363d3b0591SJens Wiklander */ 3373d3b0591SJens Wiklander static int x509_name_cmp(const mbedtls_x509_name *a, const mbedtls_x509_name *b) 3383d3b0591SJens Wiklander { 3393d3b0591SJens Wiklander /* Avoid recursion, it might not be optimised by the compiler */ 34032b31808SJens Wiklander while (a != NULL || b != NULL) { 34132b31808SJens Wiklander if (a == NULL || b == NULL) { 34232b31808SJens Wiklander return -1; 34332b31808SJens Wiklander } 3443d3b0591SJens Wiklander 3453d3b0591SJens Wiklander /* type */ 3463d3b0591SJens Wiklander if (a->oid.tag != b->oid.tag || 3473d3b0591SJens Wiklander a->oid.len != b->oid.len || 34832b31808SJens Wiklander memcmp(a->oid.p, b->oid.p, b->oid.len) != 0) { 34932b31808SJens Wiklander return -1; 3503d3b0591SJens Wiklander } 3513d3b0591SJens Wiklander 3523d3b0591SJens Wiklander /* value */ 35332b31808SJens Wiklander if (x509_string_cmp(&a->val, &b->val) != 0) { 35432b31808SJens Wiklander return -1; 35532b31808SJens Wiklander } 3563d3b0591SJens Wiklander 3573d3b0591SJens Wiklander /* structure of the list of sets */ 35832b31808SJens Wiklander if (a->next_merged != b->next_merged) { 35932b31808SJens Wiklander return -1; 36032b31808SJens Wiklander } 3613d3b0591SJens Wiklander 3623d3b0591SJens Wiklander a = a->next; 3633d3b0591SJens Wiklander b = b->next; 3643d3b0591SJens Wiklander } 3653d3b0591SJens Wiklander 3663d3b0591SJens Wiklander /* a == NULL == b */ 36732b31808SJens Wiklander return 0; 3683d3b0591SJens Wiklander } 3693d3b0591SJens Wiklander 3703d3b0591SJens Wiklander /* 3713d3b0591SJens Wiklander * Reset (init or clear) a verify_chain 3723d3b0591SJens Wiklander */ 3733d3b0591SJens Wiklander static void x509_crt_verify_chain_reset( 3743d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain *ver_chain) 3753d3b0591SJens Wiklander { 3763d3b0591SJens Wiklander size_t i; 3773d3b0591SJens Wiklander 37832b31808SJens Wiklander for (i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++) { 3793d3b0591SJens Wiklander ver_chain->items[i].crt = NULL; 3805b25c76aSJerome Forissier ver_chain->items[i].flags = (uint32_t) -1; 3813d3b0591SJens Wiklander } 3823d3b0591SJens Wiklander 3833d3b0591SJens Wiklander ver_chain->len = 0; 38411fa71b9SJerome Forissier 38511fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 38611fa71b9SJerome Forissier ver_chain->trust_ca_cb_result = NULL; 38711fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 3883d3b0591SJens Wiklander } 3893d3b0591SJens Wiklander 3903d3b0591SJens Wiklander /* 391817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 392817466cbSJens Wiklander */ 393817466cbSJens Wiklander static int x509_get_version(unsigned char **p, 394817466cbSJens Wiklander const unsigned char *end, 395817466cbSJens Wiklander int *ver) 396817466cbSJens Wiklander { 39711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 398817466cbSJens Wiklander size_t len; 399817466cbSJens Wiklander 400817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 40132b31808SJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 40232b31808SJens Wiklander 0)) != 0) { 40332b31808SJens Wiklander if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 404817466cbSJens Wiklander *ver = 0; 40532b31808SJens Wiklander return 0; 406817466cbSJens Wiklander } 407817466cbSJens Wiklander 40832b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 409817466cbSJens Wiklander } 410817466cbSJens Wiklander 411817466cbSJens Wiklander end = *p + len; 412817466cbSJens Wiklander 41332b31808SJens Wiklander if ((ret = mbedtls_asn1_get_int(p, end, ver)) != 0) { 41432b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_VERSION, ret); 41532b31808SJens Wiklander } 416817466cbSJens Wiklander 41732b31808SJens Wiklander if (*p != end) { 41832b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_VERSION, 41932b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 42032b31808SJens Wiklander } 421817466cbSJens Wiklander 42232b31808SJens Wiklander return 0; 423817466cbSJens Wiklander } 424817466cbSJens Wiklander 425817466cbSJens Wiklander /* 426817466cbSJens Wiklander * Validity ::= SEQUENCE { 427817466cbSJens Wiklander * notBefore Time, 428817466cbSJens Wiklander * notAfter Time } 429817466cbSJens Wiklander */ 430817466cbSJens Wiklander static int x509_get_dates(unsigned char **p, 431817466cbSJens Wiklander const unsigned char *end, 432817466cbSJens Wiklander mbedtls_x509_time *from, 433817466cbSJens Wiklander mbedtls_x509_time *to) 434817466cbSJens Wiklander { 43511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 436817466cbSJens Wiklander size_t len; 437817466cbSJens Wiklander 438817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 43932b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 44032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_DATE, ret); 44132b31808SJens Wiklander } 442817466cbSJens Wiklander 443817466cbSJens Wiklander end = *p + len; 444817466cbSJens Wiklander 44532b31808SJens Wiklander if ((ret = mbedtls_x509_get_time(p, end, from)) != 0) { 44632b31808SJens Wiklander return ret; 44732b31808SJens Wiklander } 448817466cbSJens Wiklander 44932b31808SJens Wiklander if ((ret = mbedtls_x509_get_time(p, end, to)) != 0) { 45032b31808SJens Wiklander return ret; 45132b31808SJens Wiklander } 452817466cbSJens Wiklander 45332b31808SJens Wiklander if (*p != end) { 45432b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_DATE, 45532b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 45632b31808SJens Wiklander } 457817466cbSJens Wiklander 45832b31808SJens Wiklander return 0; 459817466cbSJens Wiklander } 460817466cbSJens Wiklander 461817466cbSJens Wiklander /* 462817466cbSJens Wiklander * X.509 v2/v3 unique identifier (not parsed) 463817466cbSJens Wiklander */ 464817466cbSJens Wiklander static int x509_get_uid(unsigned char **p, 465817466cbSJens Wiklander const unsigned char *end, 466817466cbSJens Wiklander mbedtls_x509_buf *uid, int n) 467817466cbSJens Wiklander { 46811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 469817466cbSJens Wiklander 47032b31808SJens Wiklander if (*p == end) { 47132b31808SJens Wiklander return 0; 47232b31808SJens Wiklander } 473817466cbSJens Wiklander 474817466cbSJens Wiklander uid->tag = **p; 475817466cbSJens Wiklander 476817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &uid->len, 47732b31808SJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 47832b31808SJens Wiklander n)) != 0) { 47932b31808SJens Wiklander if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 48032b31808SJens Wiklander return 0; 48132b31808SJens Wiklander } 482817466cbSJens Wiklander 48332b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 484817466cbSJens Wiklander } 485817466cbSJens Wiklander 486817466cbSJens Wiklander uid->p = *p; 487817466cbSJens Wiklander *p += uid->len; 488817466cbSJens Wiklander 48932b31808SJens Wiklander return 0; 490817466cbSJens Wiklander } 491817466cbSJens Wiklander 492817466cbSJens Wiklander static int x509_get_basic_constraints(unsigned char **p, 493817466cbSJens Wiklander const unsigned char *end, 494817466cbSJens Wiklander int *ca_istrue, 495817466cbSJens Wiklander int *max_pathlen) 496817466cbSJens Wiklander { 49711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 498817466cbSJens Wiklander size_t len; 499817466cbSJens Wiklander 500817466cbSJens Wiklander /* 501817466cbSJens Wiklander * BasicConstraints ::= SEQUENCE { 502817466cbSJens Wiklander * cA BOOLEAN DEFAULT FALSE, 503817466cbSJens Wiklander * pathLenConstraint INTEGER (0..MAX) OPTIONAL } 504817466cbSJens Wiklander */ 505817466cbSJens Wiklander *ca_istrue = 0; /* DEFAULT FALSE */ 506817466cbSJens Wiklander *max_pathlen = 0; /* endless */ 507817466cbSJens Wiklander 508817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 50932b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 51032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 511817466cbSJens Wiklander } 512817466cbSJens Wiklander 51332b31808SJens Wiklander if (*p == end) { 51432b31808SJens Wiklander return 0; 51532b31808SJens Wiklander } 516817466cbSJens Wiklander 51732b31808SJens Wiklander if ((ret = mbedtls_asn1_get_bool(p, end, ca_istrue)) != 0) { 51832b31808SJens Wiklander if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 51932b31808SJens Wiklander ret = mbedtls_asn1_get_int(p, end, ca_istrue); 52032b31808SJens Wiklander } 521817466cbSJens Wiklander 52232b31808SJens Wiklander if (ret != 0) { 52332b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 52432b31808SJens Wiklander } 52532b31808SJens Wiklander 52632b31808SJens Wiklander if (*ca_istrue != 0) { 52732b31808SJens Wiklander *ca_istrue = 1; 52832b31808SJens Wiklander } 52932b31808SJens Wiklander } 53032b31808SJens Wiklander 53132b31808SJens Wiklander if (*p == end) { 53232b31808SJens Wiklander return 0; 53332b31808SJens Wiklander } 53432b31808SJens Wiklander 53532b31808SJens Wiklander if ((ret = mbedtls_asn1_get_int(p, end, max_pathlen)) != 0) { 53632b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 53732b31808SJens Wiklander } 53832b31808SJens Wiklander 53932b31808SJens Wiklander if (*p != end) { 54032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 54132b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 54232b31808SJens Wiklander } 5437901324dSJerome Forissier 5447901324dSJerome Forissier /* Do not accept max_pathlen equal to INT_MAX to avoid a signed integer 5457901324dSJerome Forissier * overflow, which is an undefined behavior. */ 54632b31808SJens Wiklander if (*max_pathlen == INT_MAX) { 54732b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 54832b31808SJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH); 54932b31808SJens Wiklander } 550817466cbSJens Wiklander 551817466cbSJens Wiklander (*max_pathlen)++; 552817466cbSJens Wiklander 55332b31808SJens Wiklander return 0; 554817466cbSJens Wiklander } 555817466cbSJens Wiklander 556817466cbSJens Wiklander /* 557817466cbSJens Wiklander * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId 558817466cbSJens Wiklander * 559817466cbSJens Wiklander * KeyPurposeId ::= OBJECT IDENTIFIER 560817466cbSJens Wiklander */ 561817466cbSJens Wiklander static int x509_get_ext_key_usage(unsigned char **p, 562817466cbSJens Wiklander const unsigned char *end, 563817466cbSJens Wiklander mbedtls_x509_sequence *ext_key_usage) 564817466cbSJens Wiklander { 56511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 566817466cbSJens Wiklander 56732b31808SJens Wiklander if ((ret = mbedtls_asn1_get_sequence_of(p, end, ext_key_usage, MBEDTLS_ASN1_OID)) != 0) { 56832b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 56932b31808SJens Wiklander } 570817466cbSJens Wiklander 571817466cbSJens Wiklander /* Sequence length must be >= 1 */ 57232b31808SJens Wiklander if (ext_key_usage->buf.p == NULL) { 57332b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 57432b31808SJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH); 575817466cbSJens Wiklander } 576817466cbSJens Wiklander 57732b31808SJens Wiklander return 0; 578817466cbSJens Wiklander } 579817466cbSJens Wiklander 580817466cbSJens Wiklander /* 581*b0563631STom Van Eyck * SubjectKeyIdentifier ::= KeyIdentifier 582*b0563631STom Van Eyck * 583*b0563631STom Van Eyck * KeyIdentifier ::= OCTET STRING 584*b0563631STom Van Eyck */ 585*b0563631STom Van Eyck static int x509_get_subject_key_id(unsigned char **p, 586*b0563631STom Van Eyck const unsigned char *end, 587*b0563631STom Van Eyck mbedtls_x509_buf *subject_key_id) 588*b0563631STom Van Eyck { 589*b0563631STom Van Eyck int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 590*b0563631STom Van Eyck size_t len = 0u; 591*b0563631STom Van Eyck 592*b0563631STom Van Eyck if ((ret = mbedtls_asn1_get_tag(p, end, &len, 593*b0563631STom Van Eyck MBEDTLS_ASN1_OCTET_STRING)) != 0) { 594*b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 595*b0563631STom Van Eyck } 596*b0563631STom Van Eyck 597*b0563631STom Van Eyck subject_key_id->len = len; 598*b0563631STom Van Eyck subject_key_id->tag = MBEDTLS_ASN1_OCTET_STRING; 599*b0563631STom Van Eyck subject_key_id->p = *p; 600*b0563631STom Van Eyck *p += len; 601*b0563631STom Van Eyck 602*b0563631STom Van Eyck if (*p != end) { 603*b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 604*b0563631STom Van Eyck MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 605*b0563631STom Van Eyck } 606*b0563631STom Van Eyck 607*b0563631STom Van Eyck return 0; 608*b0563631STom Van Eyck } 609*b0563631STom Van Eyck 610*b0563631STom Van Eyck /* 611*b0563631STom Van Eyck * AuthorityKeyIdentifier ::= SEQUENCE { 612*b0563631STom Van Eyck * keyIdentifier [0] KeyIdentifier OPTIONAL, 613*b0563631STom Van Eyck * authorityCertIssuer [1] GeneralNames OPTIONAL, 614*b0563631STom Van Eyck * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } 615*b0563631STom Van Eyck * 616*b0563631STom Van Eyck * KeyIdentifier ::= OCTET STRING 617*b0563631STom Van Eyck */ 618*b0563631STom Van Eyck static int x509_get_authority_key_id(unsigned char **p, 619*b0563631STom Van Eyck unsigned char *end, 620*b0563631STom Van Eyck mbedtls_x509_authority *authority_key_id) 621*b0563631STom Van Eyck { 622*b0563631STom Van Eyck int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 623*b0563631STom Van Eyck size_t len = 0u; 624*b0563631STom Van Eyck 625*b0563631STom Van Eyck if ((ret = mbedtls_asn1_get_tag(p, end, &len, 626*b0563631STom Van Eyck MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 627*b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 628*b0563631STom Van Eyck } 629*b0563631STom Van Eyck 630*b0563631STom Van Eyck if (*p + len != end) { 631*b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 632*b0563631STom Van Eyck MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 633*b0563631STom Van Eyck } 634*b0563631STom Van Eyck 635*b0563631STom Van Eyck ret = mbedtls_asn1_get_tag(p, end, &len, 636*b0563631STom Van Eyck MBEDTLS_ASN1_CONTEXT_SPECIFIC); 637*b0563631STom Van Eyck 638*b0563631STom Van Eyck /* KeyIdentifier is an OPTIONAL field */ 639*b0563631STom Van Eyck if (ret == 0) { 640*b0563631STom Van Eyck authority_key_id->keyIdentifier.len = len; 641*b0563631STom Van Eyck authority_key_id->keyIdentifier.p = *p; 642*b0563631STom Van Eyck /* Setting tag of the keyIdentfier intentionally to 0x04. 643*b0563631STom Van Eyck * Although the .keyIdentfier field is CONTEXT_SPECIFIC ([0] OPTIONAL), 644*b0563631STom Van Eyck * its tag with the content is the payload of on OCTET STRING primitive */ 645*b0563631STom Van Eyck authority_key_id->keyIdentifier.tag = MBEDTLS_ASN1_OCTET_STRING; 646*b0563631STom Van Eyck 647*b0563631STom Van Eyck *p += len; 648*b0563631STom Van Eyck } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 649*b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 650*b0563631STom Van Eyck } 651*b0563631STom Van Eyck 652*b0563631STom Van Eyck if (*p < end) { 653*b0563631STom Van Eyck /* Getting authorityCertIssuer using the required specific class tag [1] */ 654*b0563631STom Van Eyck if ((ret = mbedtls_asn1_get_tag(p, end, &len, 655*b0563631STom Van Eyck MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 656*b0563631STom Van Eyck 1)) != 0) { 657*b0563631STom Van Eyck /* authorityCertIssuer and authorityCertSerialNumber MUST both 658*b0563631STom Van Eyck be present or both be absent. At this point we expect to have both. */ 659*b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 660*b0563631STom Van Eyck } 661*b0563631STom Van Eyck /* "end" also includes the CertSerialNumber field so "len" shall be used */ 662*b0563631STom Van Eyck ret = mbedtls_x509_get_subject_alt_name_ext(p, 663*b0563631STom Van Eyck (*p+len), 664*b0563631STom Van Eyck &authority_key_id->authorityCertIssuer); 665*b0563631STom Van Eyck if (ret != 0) { 666*b0563631STom Van Eyck return ret; 667*b0563631STom Van Eyck } 668*b0563631STom Van Eyck 669*b0563631STom Van Eyck /* Getting authorityCertSerialNumber using the required specific class tag [2] */ 670*b0563631STom Van Eyck if ((ret = mbedtls_asn1_get_tag(p, end, &len, 671*b0563631STom Van Eyck MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2)) != 0) { 672*b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 673*b0563631STom Van Eyck } 674*b0563631STom Van Eyck authority_key_id->authorityCertSerialNumber.len = len; 675*b0563631STom Van Eyck authority_key_id->authorityCertSerialNumber.p = *p; 676*b0563631STom Van Eyck authority_key_id->authorityCertSerialNumber.tag = MBEDTLS_ASN1_INTEGER; 677*b0563631STom Van Eyck *p += len; 678*b0563631STom Van Eyck } 679*b0563631STom Van Eyck 680*b0563631STom Van Eyck if (*p != end) { 681*b0563631STom Van Eyck return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 682*b0563631STom Van Eyck MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; 683*b0563631STom Van Eyck } 684*b0563631STom Van Eyck 685*b0563631STom Van Eyck return 0; 686*b0563631STom Van Eyck } 687*b0563631STom Van Eyck 688*b0563631STom Van Eyck /* 68911fa71b9SJerome Forissier * id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } 69011fa71b9SJerome Forissier * 69111fa71b9SJerome Forissier * anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 } 69211fa71b9SJerome Forissier * 69311fa71b9SJerome Forissier * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation 69411fa71b9SJerome Forissier * 69511fa71b9SJerome Forissier * PolicyInformation ::= SEQUENCE { 69611fa71b9SJerome Forissier * policyIdentifier CertPolicyId, 69711fa71b9SJerome Forissier * policyQualifiers SEQUENCE SIZE (1..MAX) OF 69811fa71b9SJerome Forissier * PolicyQualifierInfo OPTIONAL } 69911fa71b9SJerome Forissier * 70011fa71b9SJerome Forissier * CertPolicyId ::= OBJECT IDENTIFIER 70111fa71b9SJerome Forissier * 70211fa71b9SJerome Forissier * PolicyQualifierInfo ::= SEQUENCE { 70311fa71b9SJerome Forissier * policyQualifierId PolicyQualifierId, 70411fa71b9SJerome Forissier * qualifier ANY DEFINED BY policyQualifierId } 70511fa71b9SJerome Forissier * 70611fa71b9SJerome Forissier * -- policyQualifierIds for Internet policy qualifiers 70711fa71b9SJerome Forissier * 70811fa71b9SJerome Forissier * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 } 70911fa71b9SJerome Forissier * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 } 71011fa71b9SJerome Forissier * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 } 71111fa71b9SJerome Forissier * 71211fa71b9SJerome Forissier * PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ) 71311fa71b9SJerome Forissier * 71411fa71b9SJerome Forissier * Qualifier ::= CHOICE { 71511fa71b9SJerome Forissier * cPSuri CPSuri, 71611fa71b9SJerome Forissier * userNotice UserNotice } 71711fa71b9SJerome Forissier * 71811fa71b9SJerome Forissier * CPSuri ::= IA5String 71911fa71b9SJerome Forissier * 72011fa71b9SJerome Forissier * UserNotice ::= SEQUENCE { 72111fa71b9SJerome Forissier * noticeRef NoticeReference OPTIONAL, 72211fa71b9SJerome Forissier * explicitText DisplayText OPTIONAL } 72311fa71b9SJerome Forissier * 72411fa71b9SJerome Forissier * NoticeReference ::= SEQUENCE { 72511fa71b9SJerome Forissier * organization DisplayText, 72611fa71b9SJerome Forissier * noticeNumbers SEQUENCE OF INTEGER } 72711fa71b9SJerome Forissier * 72811fa71b9SJerome Forissier * DisplayText ::= CHOICE { 72911fa71b9SJerome Forissier * ia5String IA5String (SIZE (1..200)), 73011fa71b9SJerome Forissier * visibleString VisibleString (SIZE (1..200)), 73111fa71b9SJerome Forissier * bmpString BMPString (SIZE (1..200)), 73211fa71b9SJerome Forissier * utf8String UTF8String (SIZE (1..200)) } 73311fa71b9SJerome Forissier * 73411fa71b9SJerome Forissier * NOTE: we only parse and use anyPolicy without qualifiers at this point 73511fa71b9SJerome Forissier * as defined in RFC 5280. 73611fa71b9SJerome Forissier */ 73711fa71b9SJerome Forissier static int x509_get_certificate_policies(unsigned char **p, 73811fa71b9SJerome Forissier const unsigned char *end, 73911fa71b9SJerome Forissier mbedtls_x509_sequence *certificate_policies) 74011fa71b9SJerome Forissier { 74111fa71b9SJerome Forissier int ret, parse_ret = 0; 74211fa71b9SJerome Forissier size_t len; 74311fa71b9SJerome Forissier mbedtls_asn1_buf *buf; 74411fa71b9SJerome Forissier mbedtls_asn1_sequence *cur = certificate_policies; 74511fa71b9SJerome Forissier 74611fa71b9SJerome Forissier /* Get main sequence tag */ 74711fa71b9SJerome Forissier ret = mbedtls_asn1_get_tag(p, end, &len, 74811fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); 74932b31808SJens Wiklander if (ret != 0) { 75032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 75132b31808SJens Wiklander } 75211fa71b9SJerome Forissier 75332b31808SJens Wiklander if (*p + len != end) { 75432b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 75532b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 75632b31808SJens Wiklander } 75711fa71b9SJerome Forissier 75811fa71b9SJerome Forissier /* 75911fa71b9SJerome Forissier * Cannot be an empty sequence. 76011fa71b9SJerome Forissier */ 76132b31808SJens Wiklander if (len == 0) { 76232b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 76332b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 76432b31808SJens Wiklander } 76511fa71b9SJerome Forissier 76632b31808SJens Wiklander while (*p < end) { 76711fa71b9SJerome Forissier mbedtls_x509_buf policy_oid; 76811fa71b9SJerome Forissier const unsigned char *policy_end; 76911fa71b9SJerome Forissier 77011fa71b9SJerome Forissier /* 77111fa71b9SJerome Forissier * Get the policy sequence 77211fa71b9SJerome Forissier */ 77311fa71b9SJerome Forissier if ((ret = mbedtls_asn1_get_tag(p, end, &len, 77432b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 77532b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 77632b31808SJens Wiklander } 77711fa71b9SJerome Forissier 77811fa71b9SJerome Forissier policy_end = *p + len; 77911fa71b9SJerome Forissier 78011fa71b9SJerome Forissier if ((ret = mbedtls_asn1_get_tag(p, policy_end, &len, 78132b31808SJens Wiklander MBEDTLS_ASN1_OID)) != 0) { 78232b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 78332b31808SJens Wiklander } 78411fa71b9SJerome Forissier 78511fa71b9SJerome Forissier policy_oid.tag = MBEDTLS_ASN1_OID; 78611fa71b9SJerome Forissier policy_oid.len = len; 78711fa71b9SJerome Forissier policy_oid.p = *p; 78811fa71b9SJerome Forissier 78911fa71b9SJerome Forissier /* 79011fa71b9SJerome Forissier * Only AnyPolicy is currently supported when enforcing policy. 79111fa71b9SJerome Forissier */ 79232b31808SJens Wiklander if (MBEDTLS_OID_CMP(MBEDTLS_OID_ANY_POLICY, &policy_oid) != 0) { 79311fa71b9SJerome Forissier /* 79411fa71b9SJerome Forissier * Set the parsing return code but continue parsing, in case this 79532b31808SJens Wiklander * extension is critical. 79611fa71b9SJerome Forissier */ 79711fa71b9SJerome Forissier parse_ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; 79811fa71b9SJerome Forissier } 79911fa71b9SJerome Forissier 80011fa71b9SJerome Forissier /* Allocate and assign next pointer */ 80132b31808SJens Wiklander if (cur->buf.p != NULL) { 80232b31808SJens Wiklander if (cur->next != NULL) { 80332b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_EXTENSIONS; 80432b31808SJens Wiklander } 80511fa71b9SJerome Forissier 80611fa71b9SJerome Forissier cur->next = mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence)); 80711fa71b9SJerome Forissier 80832b31808SJens Wiklander if (cur->next == NULL) { 80932b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 81032b31808SJens Wiklander MBEDTLS_ERR_ASN1_ALLOC_FAILED); 81132b31808SJens Wiklander } 81211fa71b9SJerome Forissier 81311fa71b9SJerome Forissier cur = cur->next; 81411fa71b9SJerome Forissier } 81511fa71b9SJerome Forissier 81611fa71b9SJerome Forissier buf = &(cur->buf); 81711fa71b9SJerome Forissier buf->tag = policy_oid.tag; 81811fa71b9SJerome Forissier buf->p = policy_oid.p; 81911fa71b9SJerome Forissier buf->len = policy_oid.len; 82011fa71b9SJerome Forissier 82111fa71b9SJerome Forissier *p += len; 82211fa71b9SJerome Forissier 82311fa71b9SJerome Forissier /* 82411fa71b9SJerome Forissier * If there is an optional qualifier, then *p < policy_end 82511fa71b9SJerome Forissier * Check the Qualifier len to verify it doesn't exceed policy_end. 82611fa71b9SJerome Forissier */ 82732b31808SJens Wiklander if (*p < policy_end) { 82811fa71b9SJerome Forissier if ((ret = mbedtls_asn1_get_tag(p, policy_end, &len, 82932b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 83032b31808SJens Wiklander 0) { 83132b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 83232b31808SJens Wiklander } 83311fa71b9SJerome Forissier /* 83411fa71b9SJerome Forissier * Skip the optional policy qualifiers. 83511fa71b9SJerome Forissier */ 83611fa71b9SJerome Forissier *p += len; 83711fa71b9SJerome Forissier } 83811fa71b9SJerome Forissier 83932b31808SJens Wiklander if (*p != policy_end) { 84032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 84132b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 84232b31808SJens Wiklander } 84311fa71b9SJerome Forissier } 84411fa71b9SJerome Forissier 84511fa71b9SJerome Forissier /* Set final sequence entry's next pointer to NULL */ 84611fa71b9SJerome Forissier cur->next = NULL; 84711fa71b9SJerome Forissier 84832b31808SJens Wiklander if (*p != end) { 84932b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 85032b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 85132b31808SJens Wiklander } 85211fa71b9SJerome Forissier 85332b31808SJens Wiklander return parse_ret; 85411fa71b9SJerome Forissier } 85511fa71b9SJerome Forissier 85611fa71b9SJerome Forissier /* 857817466cbSJens Wiklander * X.509 v3 extensions 858817466cbSJens Wiklander * 859817466cbSJens Wiklander */ 860817466cbSJens Wiklander static int x509_get_crt_ext(unsigned char **p, 861817466cbSJens Wiklander const unsigned char *end, 8627901324dSJerome Forissier mbedtls_x509_crt *crt, 8637901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 8647901324dSJerome Forissier void *p_ctx) 865817466cbSJens Wiklander { 86611fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 867817466cbSJens Wiklander size_t len; 8687901324dSJerome Forissier unsigned char *end_ext_data, *start_ext_octet, *end_ext_octet; 869817466cbSJens Wiklander 87032b31808SJens Wiklander if (*p == end) { 87132b31808SJens Wiklander return 0; 87232b31808SJens Wiklander } 873817466cbSJens Wiklander 87432b31808SJens Wiklander if ((ret = mbedtls_x509_get_ext(p, end, &crt->v3_ext, 3)) != 0) { 87532b31808SJens Wiklander return ret; 87632b31808SJens Wiklander } 877817466cbSJens Wiklander 8785b25c76aSJerome Forissier end = crt->v3_ext.p + crt->v3_ext.len; 87932b31808SJens Wiklander while (*p < end) { 880817466cbSJens Wiklander /* 881817466cbSJens Wiklander * Extension ::= SEQUENCE { 882817466cbSJens Wiklander * extnID OBJECT IDENTIFIER, 883817466cbSJens Wiklander * critical BOOLEAN DEFAULT FALSE, 884817466cbSJens Wiklander * extnValue OCTET STRING } 885817466cbSJens Wiklander */ 886817466cbSJens Wiklander mbedtls_x509_buf extn_oid = { 0, 0, NULL }; 887817466cbSJens Wiklander int is_critical = 0; /* DEFAULT FALSE */ 888817466cbSJens Wiklander int ext_type = 0; 889817466cbSJens Wiklander 890817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 89132b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 89232b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 89332b31808SJens Wiklander } 894817466cbSJens Wiklander 895817466cbSJens Wiklander end_ext_data = *p + len; 896817466cbSJens Wiklander 897817466cbSJens Wiklander /* Get extension ID */ 8983d3b0591SJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &extn_oid.len, 89932b31808SJens Wiklander MBEDTLS_ASN1_OID)) != 0) { 90032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 90132b31808SJens Wiklander } 902817466cbSJens Wiklander 9033d3b0591SJens Wiklander extn_oid.tag = MBEDTLS_ASN1_OID; 904817466cbSJens Wiklander extn_oid.p = *p; 905817466cbSJens Wiklander *p += extn_oid.len; 906817466cbSJens Wiklander 907817466cbSJens Wiklander /* Get optional critical */ 908817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_bool(p, end_ext_data, &is_critical)) != 0 && 90932b31808SJens Wiklander (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) { 91032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 91132b31808SJens Wiklander } 912817466cbSJens Wiklander 913817466cbSJens Wiklander /* Data should be octet string type */ 914817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &len, 91532b31808SJens Wiklander MBEDTLS_ASN1_OCTET_STRING)) != 0) { 91632b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 91732b31808SJens Wiklander } 918817466cbSJens Wiklander 9197901324dSJerome Forissier start_ext_octet = *p; 920817466cbSJens Wiklander end_ext_octet = *p + len; 921817466cbSJens Wiklander 92232b31808SJens Wiklander if (end_ext_octet != end_ext_data) { 92332b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 92432b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 92532b31808SJens Wiklander } 926817466cbSJens Wiklander 927817466cbSJens Wiklander /* 928817466cbSJens Wiklander * Detect supported extensions 929817466cbSJens Wiklander */ 930817466cbSJens Wiklander ret = mbedtls_oid_get_x509_ext_type(&extn_oid, &ext_type); 931817466cbSJens Wiklander 93232b31808SJens Wiklander if (ret != 0) { 9337901324dSJerome Forissier /* Give the callback (if any) a chance to handle the extension */ 93432b31808SJens Wiklander if (cb != NULL) { 9357901324dSJerome Forissier ret = cb(p_ctx, crt, &extn_oid, is_critical, *p, end_ext_octet); 93632b31808SJens Wiklander if (ret != 0 && is_critical) { 93732b31808SJens Wiklander return ret; 93832b31808SJens Wiklander } 9397901324dSJerome Forissier *p = end_ext_octet; 9407901324dSJerome Forissier continue; 9417901324dSJerome Forissier } 9427901324dSJerome Forissier 943817466cbSJens Wiklander /* No parser found, skip extension */ 944817466cbSJens Wiklander *p = end_ext_octet; 945817466cbSJens Wiklander 94632b31808SJens Wiklander if (is_critical) { 947817466cbSJens Wiklander /* Data is marked as critical: fail */ 94832b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 94932b31808SJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG); 950817466cbSJens Wiklander } 951817466cbSJens Wiklander continue; 952817466cbSJens Wiklander } 953817466cbSJens Wiklander 954817466cbSJens Wiklander /* Forbid repeated extensions */ 95532b31808SJens Wiklander if ((crt->ext_types & ext_type) != 0) { 95632b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_EXTENSIONS; 95732b31808SJens Wiklander } 958817466cbSJens Wiklander 959817466cbSJens Wiklander crt->ext_types |= ext_type; 960817466cbSJens Wiklander 96132b31808SJens Wiklander switch (ext_type) { 962817466cbSJens Wiklander case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS: 963817466cbSJens Wiklander /* Parse basic constraints */ 964817466cbSJens Wiklander if ((ret = x509_get_basic_constraints(p, end_ext_octet, 96532b31808SJens Wiklander &crt->ca_istrue, &crt->max_pathlen)) != 0) { 96632b31808SJens Wiklander return ret; 96732b31808SJens Wiklander } 968817466cbSJens Wiklander break; 969817466cbSJens Wiklander 970817466cbSJens Wiklander case MBEDTLS_X509_EXT_KEY_USAGE: 971817466cbSJens Wiklander /* Parse key usage */ 97232b31808SJens Wiklander if ((ret = mbedtls_x509_get_key_usage(p, end_ext_octet, 97332b31808SJens Wiklander &crt->key_usage)) != 0) { 97432b31808SJens Wiklander return ret; 97532b31808SJens Wiklander } 976817466cbSJens Wiklander break; 977817466cbSJens Wiklander 978817466cbSJens Wiklander case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: 979817466cbSJens Wiklander /* Parse extended key usage */ 980817466cbSJens Wiklander if ((ret = x509_get_ext_key_usage(p, end_ext_octet, 98132b31808SJens Wiklander &crt->ext_key_usage)) != 0) { 98232b31808SJens Wiklander return ret; 98332b31808SJens Wiklander } 984817466cbSJens Wiklander break; 985817466cbSJens Wiklander 986*b0563631STom Van Eyck case MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER: 987*b0563631STom Van Eyck /* Parse subject key identifier */ 988*b0563631STom Van Eyck if ((ret = x509_get_subject_key_id(p, end_ext_data, 989*b0563631STom Van Eyck &crt->subject_key_id)) != 0) { 990*b0563631STom Van Eyck return ret; 991*b0563631STom Van Eyck } 992*b0563631STom Van Eyck break; 993*b0563631STom Van Eyck 994*b0563631STom Van Eyck case MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER: 995*b0563631STom Van Eyck /* Parse authority key identifier */ 996*b0563631STom Van Eyck if ((ret = x509_get_authority_key_id(p, end_ext_octet, 997*b0563631STom Van Eyck &crt->authority_key_id)) != 0) { 998*b0563631STom Van Eyck return ret; 999*b0563631STom Van Eyck } 1000*b0563631STom Van Eyck break; 1001817466cbSJens Wiklander case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME: 1002*b0563631STom Van Eyck /* Parse subject alt name 1003*b0563631STom Van Eyck * SubjectAltName ::= GeneralNames 1004*b0563631STom Van Eyck */ 100532b31808SJens Wiklander if ((ret = mbedtls_x509_get_subject_alt_name(p, end_ext_octet, 100632b31808SJens Wiklander &crt->subject_alt_names)) != 0) { 100732b31808SJens Wiklander return ret; 100832b31808SJens Wiklander } 1009817466cbSJens Wiklander break; 1010817466cbSJens Wiklander 1011817466cbSJens Wiklander case MBEDTLS_X509_EXT_NS_CERT_TYPE: 1012817466cbSJens Wiklander /* Parse netscape certificate type */ 101332b31808SJens Wiklander if ((ret = mbedtls_x509_get_ns_cert_type(p, end_ext_octet, 101432b31808SJens Wiklander &crt->ns_cert_type)) != 0) { 101532b31808SJens Wiklander return ret; 101632b31808SJens Wiklander } 1017817466cbSJens Wiklander break; 1018817466cbSJens Wiklander 101911fa71b9SJerome Forissier case MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES: 102011fa71b9SJerome Forissier /* Parse certificate policies type */ 102111fa71b9SJerome Forissier if ((ret = x509_get_certificate_policies(p, end_ext_octet, 102232b31808SJens Wiklander &crt->certificate_policies)) != 0) { 10237901324dSJerome Forissier /* Give the callback (if any) a chance to handle the extension 10247901324dSJerome Forissier * if it contains unsupported policies */ 10257901324dSJerome Forissier if (ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE && cb != NULL && 10267901324dSJerome Forissier cb(p_ctx, crt, &extn_oid, is_critical, 102732b31808SJens Wiklander start_ext_octet, end_ext_octet) == 0) { 10287901324dSJerome Forissier break; 102932b31808SJens Wiklander } 10307901324dSJerome Forissier 103132b31808SJens Wiklander if (is_critical) { 103232b31808SJens Wiklander return ret; 103332b31808SJens Wiklander } else 103411fa71b9SJerome Forissier /* 103511fa71b9SJerome Forissier * If MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, then we 103611fa71b9SJerome Forissier * cannot interpret or enforce the policy. However, it is up to 103711fa71b9SJerome Forissier * the user to choose how to enforce the policies, 103811fa71b9SJerome Forissier * unless the extension is critical. 103911fa71b9SJerome Forissier */ 104032b31808SJens Wiklander if (ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) { 104132b31808SJens Wiklander return ret; 104232b31808SJens Wiklander } 104311fa71b9SJerome Forissier } 104411fa71b9SJerome Forissier break; 104511fa71b9SJerome Forissier 1046817466cbSJens Wiklander default: 104711fa71b9SJerome Forissier /* 104811fa71b9SJerome Forissier * If this is a non-critical extension, which the oid layer 104911fa71b9SJerome Forissier * supports, but there isn't an x509 parser for it, 105011fa71b9SJerome Forissier * skip the extension. 105111fa71b9SJerome Forissier */ 105232b31808SJens Wiklander if (is_critical) { 105332b31808SJens Wiklander return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; 105432b31808SJens Wiklander } else { 105511fa71b9SJerome Forissier *p = end_ext_octet; 1056817466cbSJens Wiklander } 1057817466cbSJens Wiklander } 105832b31808SJens Wiklander } 1059817466cbSJens Wiklander 106032b31808SJens Wiklander if (*p != end) { 106132b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 106232b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 106332b31808SJens Wiklander } 1064817466cbSJens Wiklander 106532b31808SJens Wiklander return 0; 1066817466cbSJens Wiklander } 1067817466cbSJens Wiklander 1068817466cbSJens Wiklander /* 1069817466cbSJens Wiklander * Parse and fill a single X.509 certificate in DER format 1070817466cbSJens Wiklander */ 107111fa71b9SJerome Forissier static int x509_crt_parse_der_core(mbedtls_x509_crt *crt, 107211fa71b9SJerome Forissier const unsigned char *buf, 107311fa71b9SJerome Forissier size_t buflen, 10747901324dSJerome Forissier int make_copy, 10757901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 10767901324dSJerome Forissier void *p_ctx) 1077817466cbSJens Wiklander { 107811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1079817466cbSJens Wiklander size_t len; 1080817466cbSJens Wiklander unsigned char *p, *end, *crt_end; 1081817466cbSJens Wiklander mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; 1082817466cbSJens Wiklander 1083817466cbSJens Wiklander memset(&sig_params1, 0, sizeof(mbedtls_x509_buf)); 1084817466cbSJens Wiklander memset(&sig_params2, 0, sizeof(mbedtls_x509_buf)); 1085817466cbSJens Wiklander memset(&sig_oid2, 0, sizeof(mbedtls_x509_buf)); 1086817466cbSJens Wiklander 1087817466cbSJens Wiklander /* 1088817466cbSJens Wiklander * Check for valid input 1089817466cbSJens Wiklander */ 109032b31808SJens Wiklander if (crt == NULL || buf == NULL) { 109132b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 109232b31808SJens Wiklander } 1093817466cbSJens Wiklander 109411fa71b9SJerome Forissier /* Use the original buffer until we figure out actual length. */ 1095817466cbSJens Wiklander p = (unsigned char *) buf; 1096817466cbSJens Wiklander len = buflen; 1097817466cbSJens Wiklander end = p + len; 1098817466cbSJens Wiklander 1099817466cbSJens Wiklander /* 1100817466cbSJens Wiklander * Certificate ::= SEQUENCE { 1101817466cbSJens Wiklander * tbsCertificate TBSCertificate, 1102817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 1103817466cbSJens Wiklander * signatureValue BIT STRING } 1104817466cbSJens Wiklander */ 1105817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 110632b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 1107817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 110832b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_FORMAT; 1109817466cbSJens Wiklander } 1110817466cbSJens Wiklander 111111fa71b9SJerome Forissier end = crt_end = p + len; 1112*b0563631STom Van Eyck crt->raw.len = (size_t) (crt_end - buf); 111332b31808SJens Wiklander if (make_copy != 0) { 111411fa71b9SJerome Forissier /* Create and populate a new buffer for the raw field. */ 1115817466cbSJens Wiklander crt->raw.p = p = mbedtls_calloc(1, crt->raw.len); 111632b31808SJens Wiklander if (crt->raw.p == NULL) { 111732b31808SJens Wiklander return MBEDTLS_ERR_X509_ALLOC_FAILED; 111832b31808SJens Wiklander } 1119817466cbSJens Wiklander 112011fa71b9SJerome Forissier memcpy(crt->raw.p, buf, crt->raw.len); 112111fa71b9SJerome Forissier crt->own_buffer = 1; 1122817466cbSJens Wiklander 1123817466cbSJens Wiklander p += crt->raw.len - len; 1124817466cbSJens Wiklander end = crt_end = p + len; 112532b31808SJens Wiklander } else { 112611fa71b9SJerome Forissier crt->raw.p = (unsigned char *) buf; 112711fa71b9SJerome Forissier crt->own_buffer = 0; 112811fa71b9SJerome Forissier } 1129817466cbSJens Wiklander 1130817466cbSJens Wiklander /* 1131817466cbSJens Wiklander * TBSCertificate ::= SEQUENCE { 1132817466cbSJens Wiklander */ 1133817466cbSJens Wiklander crt->tbs.p = p; 1134817466cbSJens Wiklander 1135817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 113632b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 1137817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 113832b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 1139817466cbSJens Wiklander } 1140817466cbSJens Wiklander 1141817466cbSJens Wiklander end = p + len; 1142*b0563631STom Van Eyck crt->tbs.len = (size_t) (end - crt->tbs.p); 1143817466cbSJens Wiklander 1144817466cbSJens Wiklander /* 1145817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 1146817466cbSJens Wiklander * 1147817466cbSJens Wiklander * CertificateSerialNumber ::= INTEGER 1148817466cbSJens Wiklander * 1149817466cbSJens Wiklander * signature AlgorithmIdentifier 1150817466cbSJens Wiklander */ 1151817466cbSJens Wiklander if ((ret = x509_get_version(&p, end, &crt->version)) != 0 || 1152817466cbSJens Wiklander (ret = mbedtls_x509_get_serial(&p, end, &crt->serial)) != 0 || 1153817466cbSJens Wiklander (ret = mbedtls_x509_get_alg(&p, end, &crt->sig_oid, 115432b31808SJens Wiklander &sig_params1)) != 0) { 1155817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 115632b31808SJens Wiklander return ret; 1157817466cbSJens Wiklander } 1158817466cbSJens Wiklander 115932b31808SJens Wiklander if (crt->version < 0 || crt->version > 2) { 1160817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 116132b31808SJens Wiklander return MBEDTLS_ERR_X509_UNKNOWN_VERSION; 1162817466cbSJens Wiklander } 1163817466cbSJens Wiklander 1164817466cbSJens Wiklander crt->version++; 1165817466cbSJens Wiklander 1166817466cbSJens Wiklander if ((ret = mbedtls_x509_get_sig_alg(&crt->sig_oid, &sig_params1, 1167817466cbSJens Wiklander &crt->sig_md, &crt->sig_pk, 116832b31808SJens Wiklander &crt->sig_opts)) != 0) { 1169817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 117032b31808SJens Wiklander return ret; 1171817466cbSJens Wiklander } 1172817466cbSJens Wiklander 1173817466cbSJens Wiklander /* 1174817466cbSJens Wiklander * issuer Name 1175817466cbSJens Wiklander */ 1176817466cbSJens Wiklander crt->issuer_raw.p = p; 1177817466cbSJens Wiklander 1178817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 117932b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 1180817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 118132b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 1182817466cbSJens Wiklander } 1183817466cbSJens Wiklander 118432b31808SJens Wiklander if ((ret = mbedtls_x509_get_name(&p, p + len, &crt->issuer)) != 0) { 1185817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 118632b31808SJens Wiklander return ret; 1187817466cbSJens Wiklander } 1188817466cbSJens Wiklander 1189*b0563631STom Van Eyck crt->issuer_raw.len = (size_t) (p - crt->issuer_raw.p); 1190817466cbSJens Wiklander 1191817466cbSJens Wiklander /* 1192817466cbSJens Wiklander * Validity ::= SEQUENCE { 1193817466cbSJens Wiklander * notBefore Time, 1194817466cbSJens Wiklander * notAfter Time } 1195817466cbSJens Wiklander * 1196817466cbSJens Wiklander */ 1197817466cbSJens Wiklander if ((ret = x509_get_dates(&p, end, &crt->valid_from, 119832b31808SJens Wiklander &crt->valid_to)) != 0) { 1199817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 120032b31808SJens Wiklander return ret; 1201817466cbSJens Wiklander } 1202817466cbSJens Wiklander 1203817466cbSJens Wiklander /* 1204817466cbSJens Wiklander * subject Name 1205817466cbSJens Wiklander */ 1206817466cbSJens Wiklander crt->subject_raw.p = p; 1207817466cbSJens Wiklander 1208817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 120932b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 1210817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 121132b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 1212817466cbSJens Wiklander } 1213817466cbSJens Wiklander 121432b31808SJens Wiklander if (len && (ret = mbedtls_x509_get_name(&p, p + len, &crt->subject)) != 0) { 1215817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 121632b31808SJens Wiklander return ret; 1217817466cbSJens Wiklander } 1218817466cbSJens Wiklander 1219*b0563631STom Van Eyck crt->subject_raw.len = (size_t) (p - crt->subject_raw.p); 1220817466cbSJens Wiklander 1221817466cbSJens Wiklander /* 1222817466cbSJens Wiklander * SubjectPublicKeyInfo 1223817466cbSJens Wiklander */ 122411fa71b9SJerome Forissier crt->pk_raw.p = p; 122532b31808SJens Wiklander if ((ret = mbedtls_pk_parse_subpubkey(&p, end, &crt->pk)) != 0) { 1226817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 122732b31808SJens Wiklander return ret; 1228817466cbSJens Wiklander } 1229*b0563631STom Van Eyck crt->pk_raw.len = (size_t) (p - crt->pk_raw.p); 1230817466cbSJens Wiklander 1231817466cbSJens Wiklander /* 1232817466cbSJens Wiklander * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 1233817466cbSJens Wiklander * -- If present, version shall be v2 or v3 1234817466cbSJens Wiklander * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 1235817466cbSJens Wiklander * -- If present, version shall be v2 or v3 1236817466cbSJens Wiklander * extensions [3] EXPLICIT Extensions OPTIONAL 1237817466cbSJens Wiklander * -- If present, version shall be v3 1238817466cbSJens Wiklander */ 123932b31808SJens Wiklander if (crt->version == 2 || crt->version == 3) { 1240817466cbSJens Wiklander ret = x509_get_uid(&p, end, &crt->issuer_id, 1); 124132b31808SJens Wiklander if (ret != 0) { 1242817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 124332b31808SJens Wiklander return ret; 1244817466cbSJens Wiklander } 1245817466cbSJens Wiklander } 1246817466cbSJens Wiklander 124732b31808SJens Wiklander if (crt->version == 2 || crt->version == 3) { 1248817466cbSJens Wiklander ret = x509_get_uid(&p, end, &crt->subject_id, 2); 124932b31808SJens Wiklander if (ret != 0) { 1250817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 125132b31808SJens Wiklander return ret; 1252817466cbSJens Wiklander } 1253817466cbSJens Wiklander } 1254817466cbSJens Wiklander 125532b31808SJens Wiklander if (crt->version == 3) { 12567901324dSJerome Forissier ret = x509_get_crt_ext(&p, end, crt, cb, p_ctx); 125732b31808SJens Wiklander if (ret != 0) { 1258817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 125932b31808SJens Wiklander return ret; 1260817466cbSJens Wiklander } 1261817466cbSJens Wiklander } 1262817466cbSJens Wiklander 126332b31808SJens Wiklander if (p != end) { 1264817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 126532b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, 126632b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 1267817466cbSJens Wiklander } 1268817466cbSJens Wiklander 1269817466cbSJens Wiklander end = crt_end; 1270817466cbSJens Wiklander 1271817466cbSJens Wiklander /* 1272817466cbSJens Wiklander * } 1273817466cbSJens Wiklander * -- end of TBSCertificate 1274817466cbSJens Wiklander * 1275817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 1276817466cbSJens Wiklander * signatureValue BIT STRING 1277817466cbSJens Wiklander */ 127832b31808SJens Wiklander if ((ret = mbedtls_x509_get_alg(&p, end, &sig_oid2, &sig_params2)) != 0) { 1279817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 128032b31808SJens Wiklander return ret; 1281817466cbSJens Wiklander } 1282817466cbSJens Wiklander 1283817466cbSJens Wiklander if (crt->sig_oid.len != sig_oid2.len || 1284817466cbSJens Wiklander memcmp(crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len) != 0 || 12857901324dSJerome Forissier sig_params1.tag != sig_params2.tag || 1286817466cbSJens Wiklander sig_params1.len != sig_params2.len || 1287817466cbSJens Wiklander (sig_params1.len != 0 && 128832b31808SJens Wiklander memcmp(sig_params1.p, sig_params2.p, sig_params1.len) != 0)) { 1289817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 129032b31808SJens Wiklander return MBEDTLS_ERR_X509_SIG_MISMATCH; 1291817466cbSJens Wiklander } 1292817466cbSJens Wiklander 129332b31808SJens Wiklander if ((ret = mbedtls_x509_get_sig(&p, end, &crt->sig)) != 0) { 1294817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 129532b31808SJens Wiklander return ret; 1296817466cbSJens Wiklander } 1297817466cbSJens Wiklander 129832b31808SJens Wiklander if (p != end) { 1299817466cbSJens Wiklander mbedtls_x509_crt_free(crt); 130032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, 130132b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 1302817466cbSJens Wiklander } 1303817466cbSJens Wiklander 130432b31808SJens Wiklander return 0; 1305817466cbSJens Wiklander } 1306817466cbSJens Wiklander 1307817466cbSJens Wiklander /* 1308817466cbSJens Wiklander * Parse one X.509 certificate in DER format from a buffer and add them to a 1309817466cbSJens Wiklander * chained list 1310817466cbSJens Wiklander */ 131111fa71b9SJerome Forissier static int mbedtls_x509_crt_parse_der_internal(mbedtls_x509_crt *chain, 131211fa71b9SJerome Forissier const unsigned char *buf, 131311fa71b9SJerome Forissier size_t buflen, 13147901324dSJerome Forissier int make_copy, 13157901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 13167901324dSJerome Forissier void *p_ctx) 1317817466cbSJens Wiklander { 131811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1319817466cbSJens Wiklander mbedtls_x509_crt *crt = chain, *prev = NULL; 1320817466cbSJens Wiklander 1321817466cbSJens Wiklander /* 1322817466cbSJens Wiklander * Check for valid input 1323817466cbSJens Wiklander */ 132432b31808SJens Wiklander if (crt == NULL || buf == NULL) { 132532b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 132632b31808SJens Wiklander } 1327817466cbSJens Wiklander 132832b31808SJens Wiklander while (crt->version != 0 && crt->next != NULL) { 1329817466cbSJens Wiklander prev = crt; 1330817466cbSJens Wiklander crt = crt->next; 1331817466cbSJens Wiklander } 1332817466cbSJens Wiklander 1333817466cbSJens Wiklander /* 1334817466cbSJens Wiklander * Add new certificate on the end of the chain if needed. 1335817466cbSJens Wiklander */ 133632b31808SJens Wiklander if (crt->version != 0 && crt->next == NULL) { 1337817466cbSJens Wiklander crt->next = mbedtls_calloc(1, sizeof(mbedtls_x509_crt)); 1338817466cbSJens Wiklander 133932b31808SJens Wiklander if (crt->next == NULL) { 134032b31808SJens Wiklander return MBEDTLS_ERR_X509_ALLOC_FAILED; 134132b31808SJens Wiklander } 1342817466cbSJens Wiklander 1343817466cbSJens Wiklander prev = crt; 1344817466cbSJens Wiklander mbedtls_x509_crt_init(crt->next); 1345817466cbSJens Wiklander crt = crt->next; 1346817466cbSJens Wiklander } 1347817466cbSJens Wiklander 13487901324dSJerome Forissier ret = x509_crt_parse_der_core(crt, buf, buflen, make_copy, cb, p_ctx); 134932b31808SJens Wiklander if (ret != 0) { 135032b31808SJens Wiklander if (prev) { 1351817466cbSJens Wiklander prev->next = NULL; 1352817466cbSJens Wiklander } 1353817466cbSJens Wiklander 135432b31808SJens Wiklander if (crt != chain) { 135532b31808SJens Wiklander mbedtls_free(crt); 135632b31808SJens Wiklander } 135732b31808SJens Wiklander 135832b31808SJens Wiklander return ret; 135932b31808SJens Wiklander } 136032b31808SJens Wiklander 136132b31808SJens Wiklander return 0; 1362817466cbSJens Wiklander } 1363817466cbSJens Wiklander 136411fa71b9SJerome Forissier int mbedtls_x509_crt_parse_der_nocopy(mbedtls_x509_crt *chain, 136511fa71b9SJerome Forissier const unsigned char *buf, 136611fa71b9SJerome Forissier size_t buflen) 136711fa71b9SJerome Forissier { 136832b31808SJens Wiklander return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, 0, NULL, NULL); 13697901324dSJerome Forissier } 13707901324dSJerome Forissier 13717901324dSJerome Forissier int mbedtls_x509_crt_parse_der_with_ext_cb(mbedtls_x509_crt *chain, 13727901324dSJerome Forissier const unsigned char *buf, 13737901324dSJerome Forissier size_t buflen, 13747901324dSJerome Forissier int make_copy, 13757901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 13767901324dSJerome Forissier void *p_ctx) 13777901324dSJerome Forissier { 137832b31808SJens Wiklander return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, make_copy, cb, p_ctx); 137911fa71b9SJerome Forissier } 138011fa71b9SJerome Forissier 138111fa71b9SJerome Forissier int mbedtls_x509_crt_parse_der(mbedtls_x509_crt *chain, 138211fa71b9SJerome Forissier const unsigned char *buf, 138311fa71b9SJerome Forissier size_t buflen) 138411fa71b9SJerome Forissier { 138532b31808SJens Wiklander return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, 1, NULL, NULL); 138611fa71b9SJerome Forissier } 138711fa71b9SJerome Forissier 1388817466cbSJens Wiklander /* 1389817466cbSJens Wiklander * Parse one or more PEM certificates from a buffer and add them to the chained 1390817466cbSJens Wiklander * list 1391817466cbSJens Wiklander */ 139211fa71b9SJerome Forissier int mbedtls_x509_crt_parse(mbedtls_x509_crt *chain, 139311fa71b9SJerome Forissier const unsigned char *buf, 139411fa71b9SJerome Forissier size_t buflen) 1395817466cbSJens Wiklander { 1396817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1397817466cbSJens Wiklander int success = 0, first_error = 0, total_failed = 0; 1398817466cbSJens Wiklander int buf_format = MBEDTLS_X509_FORMAT_DER; 1399817466cbSJens Wiklander #endif 1400817466cbSJens Wiklander 1401817466cbSJens Wiklander /* 1402817466cbSJens Wiklander * Check for valid input 1403817466cbSJens Wiklander */ 140432b31808SJens Wiklander if (chain == NULL || buf == NULL) { 140532b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 140632b31808SJens Wiklander } 1407817466cbSJens Wiklander 1408817466cbSJens Wiklander /* 1409817466cbSJens Wiklander * Determine buffer content. Buffer contains either one DER certificate or 1410817466cbSJens Wiklander * one or more PEM certificates. 1411817466cbSJens Wiklander */ 1412817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1413817466cbSJens Wiklander if (buflen != 0 && buf[buflen - 1] == '\0' && 141432b31808SJens Wiklander strstr((const char *) buf, "-----BEGIN CERTIFICATE-----") != NULL) { 1415817466cbSJens Wiklander buf_format = MBEDTLS_X509_FORMAT_PEM; 1416817466cbSJens Wiklander } 1417817466cbSJens Wiklander 141832b31808SJens Wiklander if (buf_format == MBEDTLS_X509_FORMAT_DER) { 1419817466cbSJens Wiklander return mbedtls_x509_crt_parse_der(chain, buf, buflen); 142032b31808SJens Wiklander } 1421817466cbSJens Wiklander #else 1422817466cbSJens Wiklander return mbedtls_x509_crt_parse_der(chain, buf, buflen); 1423817466cbSJens Wiklander #endif 1424817466cbSJens Wiklander 1425817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 142632b31808SJens Wiklander if (buf_format == MBEDTLS_X509_FORMAT_PEM) { 142711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1428817466cbSJens Wiklander mbedtls_pem_context pem; 1429817466cbSJens Wiklander 1430817466cbSJens Wiklander /* 1 rather than 0 since the terminating NULL byte is counted in */ 143132b31808SJens Wiklander while (buflen > 1) { 1432817466cbSJens Wiklander size_t use_len; 1433817466cbSJens Wiklander mbedtls_pem_init(&pem); 1434817466cbSJens Wiklander 1435817466cbSJens Wiklander /* If we get there, we know the string is null-terminated */ 1436817466cbSJens Wiklander ret = mbedtls_pem_read_buffer(&pem, 1437817466cbSJens Wiklander "-----BEGIN CERTIFICATE-----", 1438817466cbSJens Wiklander "-----END CERTIFICATE-----", 1439817466cbSJens Wiklander buf, NULL, 0, &use_len); 1440817466cbSJens Wiklander 144132b31808SJens Wiklander if (ret == 0) { 1442817466cbSJens Wiklander /* 1443817466cbSJens Wiklander * Was PEM encoded 1444817466cbSJens Wiklander */ 1445817466cbSJens Wiklander buflen -= use_len; 1446817466cbSJens Wiklander buf += use_len; 144732b31808SJens Wiklander } else if (ret == MBEDTLS_ERR_PEM_BAD_INPUT_DATA) { 144832b31808SJens Wiklander return ret; 144932b31808SJens Wiklander } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) { 1450817466cbSJens Wiklander mbedtls_pem_free(&pem); 1451817466cbSJens Wiklander 1452817466cbSJens Wiklander /* 1453817466cbSJens Wiklander * PEM header and footer were found 1454817466cbSJens Wiklander */ 1455817466cbSJens Wiklander buflen -= use_len; 1456817466cbSJens Wiklander buf += use_len; 1457817466cbSJens Wiklander 145832b31808SJens Wiklander if (first_error == 0) { 1459817466cbSJens Wiklander first_error = ret; 146032b31808SJens Wiklander } 1461817466cbSJens Wiklander 1462817466cbSJens Wiklander total_failed++; 1463817466cbSJens Wiklander continue; 146432b31808SJens Wiklander } else { 1465817466cbSJens Wiklander break; 146632b31808SJens Wiklander } 1467817466cbSJens Wiklander 1468817466cbSJens Wiklander ret = mbedtls_x509_crt_parse_der(chain, pem.buf, pem.buflen); 1469817466cbSJens Wiklander 1470817466cbSJens Wiklander mbedtls_pem_free(&pem); 1471817466cbSJens Wiklander 147232b31808SJens Wiklander if (ret != 0) { 1473817466cbSJens Wiklander /* 1474817466cbSJens Wiklander * Quit parsing on a memory error 1475817466cbSJens Wiklander */ 147632b31808SJens Wiklander if (ret == MBEDTLS_ERR_X509_ALLOC_FAILED) { 147732b31808SJens Wiklander return ret; 147832b31808SJens Wiklander } 1479817466cbSJens Wiklander 148032b31808SJens Wiklander if (first_error == 0) { 1481817466cbSJens Wiklander first_error = ret; 148232b31808SJens Wiklander } 1483817466cbSJens Wiklander 1484817466cbSJens Wiklander total_failed++; 1485817466cbSJens Wiklander continue; 1486817466cbSJens Wiklander } 1487817466cbSJens Wiklander 1488817466cbSJens Wiklander success = 1; 1489817466cbSJens Wiklander } 1490817466cbSJens Wiklander } 1491817466cbSJens Wiklander 149232b31808SJens Wiklander if (success) { 149332b31808SJens Wiklander return total_failed; 149432b31808SJens Wiklander } else if (first_error) { 149532b31808SJens Wiklander return first_error; 149632b31808SJens Wiklander } else { 149732b31808SJens Wiklander return MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT; 149832b31808SJens Wiklander } 1499817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 1500817466cbSJens Wiklander } 1501817466cbSJens Wiklander 1502817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 1503817466cbSJens Wiklander /* 1504817466cbSJens Wiklander * Load one or more certificates and add them to the chained list 1505817466cbSJens Wiklander */ 1506817466cbSJens Wiklander int mbedtls_x509_crt_parse_file(mbedtls_x509_crt *chain, const char *path) 1507817466cbSJens Wiklander { 150811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1509817466cbSJens Wiklander size_t n; 1510817466cbSJens Wiklander unsigned char *buf; 1511817466cbSJens Wiklander 151232b31808SJens Wiklander if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) { 151332b31808SJens Wiklander return ret; 151432b31808SJens Wiklander } 1515817466cbSJens Wiklander 1516817466cbSJens Wiklander ret = mbedtls_x509_crt_parse(chain, buf, n); 1517817466cbSJens Wiklander 1518*b0563631STom Van Eyck mbedtls_zeroize_and_free(buf, n); 1519817466cbSJens Wiklander 152032b31808SJens Wiklander return ret; 1521817466cbSJens Wiklander } 1522817466cbSJens Wiklander 1523817466cbSJens Wiklander int mbedtls_x509_crt_parse_path(mbedtls_x509_crt *chain, const char *path) 1524817466cbSJens Wiklander { 1525817466cbSJens Wiklander int ret = 0; 1526817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 1527817466cbSJens Wiklander int w_ret; 1528817466cbSJens Wiklander WCHAR szDir[MAX_PATH]; 1529817466cbSJens Wiklander char filename[MAX_PATH]; 1530817466cbSJens Wiklander char *p; 1531817466cbSJens Wiklander size_t len = strlen(path); 1532817466cbSJens Wiklander 1533817466cbSJens Wiklander WIN32_FIND_DATAW file_data; 1534817466cbSJens Wiklander HANDLE hFind; 1535817466cbSJens Wiklander 153632b31808SJens Wiklander if (len > MAX_PATH - 3) { 153732b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 153832b31808SJens Wiklander } 1539817466cbSJens Wiklander 1540817466cbSJens Wiklander memset(szDir, 0, sizeof(szDir)); 1541817466cbSJens Wiklander memset(filename, 0, MAX_PATH); 1542817466cbSJens Wiklander memcpy(filename, path, len); 1543817466cbSJens Wiklander filename[len++] = '\\'; 1544817466cbSJens Wiklander p = filename + len; 1545817466cbSJens Wiklander filename[len++] = '*'; 1546817466cbSJens Wiklander 1547*b0563631STom Van Eyck /* 1548*b0563631STom Van Eyck * Note this function uses the code page CP_ACP which is the system default 1549*b0563631STom Van Eyck * ANSI codepage. The input string is always described in BYTES and the 1550*b0563631STom Van Eyck * output length is described in WCHARs. 1551*b0563631STom Van Eyck */ 1552817466cbSJens Wiklander w_ret = MultiByteToWideChar(CP_ACP, 0, filename, (int) len, szDir, 1553817466cbSJens Wiklander MAX_PATH - 3); 155432b31808SJens Wiklander if (w_ret == 0) { 155532b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 155632b31808SJens Wiklander } 1557817466cbSJens Wiklander 1558817466cbSJens Wiklander hFind = FindFirstFileW(szDir, &file_data); 155932b31808SJens Wiklander if (hFind == INVALID_HANDLE_VALUE) { 156032b31808SJens Wiklander return MBEDTLS_ERR_X509_FILE_IO_ERROR; 156132b31808SJens Wiklander } 1562817466cbSJens Wiklander 1563817466cbSJens Wiklander len = MAX_PATH - len; 156432b31808SJens Wiklander do { 1565817466cbSJens Wiklander memset(p, 0, len); 1566817466cbSJens Wiklander 156732b31808SJens Wiklander if (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 1568817466cbSJens Wiklander continue; 156932b31808SJens Wiklander } 1570817466cbSJens Wiklander w_ret = WideCharToMultiByte(CP_ACP, 0, file_data.cFileName, 1571*b0563631STom Van Eyck -1, p, (int) len, NULL, NULL); 157232b31808SJens Wiklander if (w_ret == 0) { 1573817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1574817466cbSJens Wiklander goto cleanup; 1575817466cbSJens Wiklander } 1576817466cbSJens Wiklander 1577817466cbSJens Wiklander w_ret = mbedtls_x509_crt_parse_file(chain, filename); 157832b31808SJens Wiklander if (w_ret < 0) { 1579817466cbSJens Wiklander ret++; 158032b31808SJens Wiklander } else { 1581817466cbSJens Wiklander ret += w_ret; 1582817466cbSJens Wiklander } 158332b31808SJens Wiklander } while (FindNextFileW(hFind, &file_data) != 0); 1584817466cbSJens Wiklander 158532b31808SJens Wiklander if (GetLastError() != ERROR_NO_MORE_FILES) { 1586817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 158732b31808SJens Wiklander } 1588817466cbSJens Wiklander 1589817466cbSJens Wiklander cleanup: 1590817466cbSJens Wiklander FindClose(hFind); 1591817466cbSJens Wiklander #else /* _WIN32 */ 1592817466cbSJens Wiklander int t_ret; 1593817466cbSJens Wiklander int snp_ret; 1594817466cbSJens Wiklander struct stat sb; 1595817466cbSJens Wiklander struct dirent *entry; 1596817466cbSJens Wiklander char entry_name[MBEDTLS_X509_MAX_FILE_PATH_LEN]; 1597817466cbSJens Wiklander DIR *dir = opendir(path); 1598817466cbSJens Wiklander 159932b31808SJens Wiklander if (dir == NULL) { 160032b31808SJens Wiklander return MBEDTLS_ERR_X509_FILE_IO_ERROR; 160132b31808SJens Wiklander } 1602817466cbSJens Wiklander 1603817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 160432b31808SJens Wiklander if ((ret = mbedtls_mutex_lock(&mbedtls_threading_readdir_mutex)) != 0) { 1605817466cbSJens Wiklander closedir(dir); 160632b31808SJens Wiklander return ret; 1607817466cbSJens Wiklander } 1608817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */ 1609817466cbSJens Wiklander 16107901324dSJerome Forissier memset(&sb, 0, sizeof(sb)); 16117901324dSJerome Forissier 161232b31808SJens Wiklander while ((entry = readdir(dir)) != NULL) { 161332b31808SJens Wiklander snp_ret = mbedtls_snprintf(entry_name, sizeof(entry_name), 1614817466cbSJens Wiklander "%s/%s", path, entry->d_name); 1615817466cbSJens Wiklander 161632b31808SJens Wiklander if (snp_ret < 0 || (size_t) snp_ret >= sizeof(entry_name)) { 1617817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; 1618817466cbSJens Wiklander goto cleanup; 161932b31808SJens Wiklander } else if (stat(entry_name, &sb) == -1) { 162032b31808SJens Wiklander if (errno == ENOENT) { 162132b31808SJens Wiklander /* Broken symbolic link - ignore this entry. 162232b31808SJens Wiklander stat(2) will return this error for either (a) a dangling 162332b31808SJens Wiklander symlink or (b) a missing file. 162432b31808SJens Wiklander Given that we have just obtained the filename from readdir, 162532b31808SJens Wiklander assume that it does exist and therefore treat this as a 162632b31808SJens Wiklander dangling symlink. */ 162732b31808SJens Wiklander continue; 162832b31808SJens Wiklander } else { 162932b31808SJens Wiklander /* Some other file error; report the error. */ 1630817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1631817466cbSJens Wiklander goto cleanup; 1632817466cbSJens Wiklander } 163332b31808SJens Wiklander } 1634817466cbSJens Wiklander 163532b31808SJens Wiklander if (!S_ISREG(sb.st_mode)) { 1636817466cbSJens Wiklander continue; 163732b31808SJens Wiklander } 1638817466cbSJens Wiklander 1639817466cbSJens Wiklander // Ignore parse errors 1640817466cbSJens Wiklander // 1641817466cbSJens Wiklander t_ret = mbedtls_x509_crt_parse_file(chain, entry_name); 164232b31808SJens Wiklander if (t_ret < 0) { 1643817466cbSJens Wiklander ret++; 164432b31808SJens Wiklander } else { 1645817466cbSJens Wiklander ret += t_ret; 1646817466cbSJens Wiklander } 164732b31808SJens Wiklander } 1648817466cbSJens Wiklander 1649817466cbSJens Wiklander cleanup: 1650817466cbSJens Wiklander closedir(dir); 1651817466cbSJens Wiklander 1652817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 165332b31808SJens Wiklander if (mbedtls_mutex_unlock(&mbedtls_threading_readdir_mutex) != 0) { 1654817466cbSJens Wiklander ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR; 165532b31808SJens Wiklander } 1656817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */ 1657817466cbSJens Wiklander 1658817466cbSJens Wiklander #endif /* _WIN32 */ 1659817466cbSJens Wiklander 166032b31808SJens Wiklander return ret; 1661817466cbSJens Wiklander } 1662817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 1663817466cbSJens Wiklander 166432b31808SJens Wiklander #if !defined(MBEDTLS_X509_REMOVE_INFO) 1665*b0563631STom Van Eyck #define PRINT_ITEM(i) \ 1666*b0563631STom Van Eyck do { \ 1667*b0563631STom Van Eyck ret = mbedtls_snprintf(p, n, "%s" i, sep); \ 1668*b0563631STom Van Eyck MBEDTLS_X509_SAFE_SNPRINTF; \ 1669*b0563631STom Van Eyck sep = ", "; \ 1670*b0563631STom Van Eyck } while (0) 1671*b0563631STom Van Eyck 1672*b0563631STom Van Eyck #define CERT_TYPE(type, name) \ 1673*b0563631STom Van Eyck do { \ 1674*b0563631STom Van Eyck if (ns_cert_type & (type)) { \ 1675*b0563631STom Van Eyck PRINT_ITEM(name); \ 1676*b0563631STom Van Eyck } \ 1677*b0563631STom Van Eyck } while (0) 1678*b0563631STom Van Eyck 1679*b0563631STom Van Eyck #define KEY_USAGE(code, name) \ 1680*b0563631STom Van Eyck do { \ 1681*b0563631STom Van Eyck if (key_usage & (code)) { \ 1682*b0563631STom Van Eyck PRINT_ITEM(name); \ 1683*b0563631STom Van Eyck } \ 1684*b0563631STom Van Eyck } while (0) 1685*b0563631STom Van Eyck 1686817466cbSJens Wiklander static int x509_info_ext_key_usage(char **buf, size_t *size, 1687817466cbSJens Wiklander const mbedtls_x509_sequence *extended_key_usage) 1688817466cbSJens Wiklander { 168911fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1690817466cbSJens Wiklander const char *desc; 1691817466cbSJens Wiklander size_t n = *size; 1692817466cbSJens Wiklander char *p = *buf; 1693817466cbSJens Wiklander const mbedtls_x509_sequence *cur = extended_key_usage; 1694817466cbSJens Wiklander const char *sep = ""; 1695817466cbSJens Wiklander 169632b31808SJens Wiklander while (cur != NULL) { 169732b31808SJens Wiklander if (mbedtls_oid_get_extended_key_usage(&cur->buf, &desc) != 0) { 1698817466cbSJens Wiklander desc = "???"; 169932b31808SJens Wiklander } 1700817466cbSJens Wiklander 1701817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%s%s", sep, desc); 1702817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1703817466cbSJens Wiklander 1704817466cbSJens Wiklander sep = ", "; 1705817466cbSJens Wiklander 1706817466cbSJens Wiklander cur = cur->next; 1707817466cbSJens Wiklander } 1708817466cbSJens Wiklander 1709817466cbSJens Wiklander *size = n; 1710817466cbSJens Wiklander *buf = p; 1711817466cbSJens Wiklander 171232b31808SJens Wiklander return 0; 1713817466cbSJens Wiklander } 1714817466cbSJens Wiklander 171511fa71b9SJerome Forissier static int x509_info_cert_policies(char **buf, size_t *size, 171611fa71b9SJerome Forissier const mbedtls_x509_sequence *certificate_policies) 171711fa71b9SJerome Forissier { 171811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 171911fa71b9SJerome Forissier const char *desc; 172011fa71b9SJerome Forissier size_t n = *size; 172111fa71b9SJerome Forissier char *p = *buf; 172211fa71b9SJerome Forissier const mbedtls_x509_sequence *cur = certificate_policies; 172311fa71b9SJerome Forissier const char *sep = ""; 172411fa71b9SJerome Forissier 172532b31808SJens Wiklander while (cur != NULL) { 172632b31808SJens Wiklander if (mbedtls_oid_get_certificate_policies(&cur->buf, &desc) != 0) { 172711fa71b9SJerome Forissier desc = "???"; 172832b31808SJens Wiklander } 172911fa71b9SJerome Forissier 173011fa71b9SJerome Forissier ret = mbedtls_snprintf(p, n, "%s%s", sep, desc); 173111fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 173211fa71b9SJerome Forissier 173311fa71b9SJerome Forissier sep = ", "; 173411fa71b9SJerome Forissier 173511fa71b9SJerome Forissier cur = cur->next; 173611fa71b9SJerome Forissier } 173711fa71b9SJerome Forissier 173811fa71b9SJerome Forissier *size = n; 173911fa71b9SJerome Forissier *buf = p; 174011fa71b9SJerome Forissier 174132b31808SJens Wiklander return 0; 174211fa71b9SJerome Forissier } 174311fa71b9SJerome Forissier 1744817466cbSJens Wiklander /* 1745817466cbSJens Wiklander * Return an informational string about the certificate. 1746817466cbSJens Wiklander */ 1747817466cbSJens Wiklander #define BEFORE_COLON 18 1748817466cbSJens Wiklander #define BC "18" 1749817466cbSJens Wiklander int mbedtls_x509_crt_info(char *buf, size_t size, const char *prefix, 1750817466cbSJens Wiklander const mbedtls_x509_crt *crt) 1751817466cbSJens Wiklander { 175211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1753817466cbSJens Wiklander size_t n; 1754817466cbSJens Wiklander char *p; 1755817466cbSJens Wiklander char key_size_str[BEFORE_COLON]; 1756817466cbSJens Wiklander 1757817466cbSJens Wiklander p = buf; 1758817466cbSJens Wiklander n = size; 1759817466cbSJens Wiklander 176032b31808SJens Wiklander if (NULL == crt) { 1761817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\nCertificate is uninitialised!\n"); 1762817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1763817466cbSJens Wiklander 176432b31808SJens Wiklander return (int) (size - n); 1765817466cbSJens Wiklander } 1766817466cbSJens Wiklander 1767817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%scert. version : %d\n", 1768817466cbSJens Wiklander prefix, crt->version); 1769817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1770817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%sserial number : ", 1771817466cbSJens Wiklander prefix); 1772817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1773817466cbSJens Wiklander 1774817466cbSJens Wiklander ret = mbedtls_x509_serial_gets(p, n, &crt->serial); 1775817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1776817466cbSJens Wiklander 1777817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sissuer name : ", prefix); 1778817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1779817466cbSJens Wiklander ret = mbedtls_x509_dn_gets(p, n, &crt->issuer); 1780817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1781817466cbSJens Wiklander 1782817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssubject name : ", prefix); 1783817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1784817466cbSJens Wiklander ret = mbedtls_x509_dn_gets(p, n, &crt->subject); 1785817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1786817466cbSJens Wiklander 1787817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sissued on : " \ 1788817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix, 1789817466cbSJens Wiklander crt->valid_from.year, crt->valid_from.mon, 1790817466cbSJens Wiklander crt->valid_from.day, crt->valid_from.hour, 1791817466cbSJens Wiklander crt->valid_from.min, crt->valid_from.sec); 1792817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1793817466cbSJens Wiklander 1794817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sexpires on : " \ 1795817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix, 1796817466cbSJens Wiklander crt->valid_to.year, crt->valid_to.mon, 1797817466cbSJens Wiklander crt->valid_to.day, crt->valid_to.hour, 1798817466cbSJens Wiklander crt->valid_to.min, crt->valid_to.sec); 1799817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1800817466cbSJens Wiklander 1801817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssigned using : ", prefix); 1802817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1803817466cbSJens Wiklander 1804817466cbSJens Wiklander ret = mbedtls_x509_sig_alg_gets(p, n, &crt->sig_oid, crt->sig_pk, 1805817466cbSJens Wiklander crt->sig_md, crt->sig_opts); 1806817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1807817466cbSJens Wiklander 1808817466cbSJens Wiklander /* Key size */ 1809817466cbSJens Wiklander if ((ret = mbedtls_x509_key_size_helper(key_size_str, BEFORE_COLON, 181032b31808SJens Wiklander mbedtls_pk_get_name(&crt->pk))) != 0) { 181132b31808SJens Wiklander return ret; 1812817466cbSJens Wiklander } 1813817466cbSJens Wiklander 1814817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, 1815817466cbSJens Wiklander (int) mbedtls_pk_get_bitlen(&crt->pk)); 1816817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1817817466cbSJens Wiklander 1818817466cbSJens Wiklander /* 1819817466cbSJens Wiklander * Optional extensions 1820817466cbSJens Wiklander */ 1821817466cbSJens Wiklander 182232b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS) { 1823817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sbasic constraints : CA=%s", prefix, 1824817466cbSJens Wiklander crt->ca_istrue ? "true" : "false"); 1825817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1826817466cbSJens Wiklander 182732b31808SJens Wiklander if (crt->max_pathlen > 0) { 1828817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, ", max_pathlen=%d", crt->max_pathlen - 1); 1829817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1830817466cbSJens Wiklander } 1831817466cbSJens Wiklander } 1832817466cbSJens Wiklander 183332b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) { 1834817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssubject alt name :", prefix); 1835817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1836817466cbSJens Wiklander 183732b31808SJens Wiklander if ((ret = mbedtls_x509_info_subject_alt_name(&p, &n, 183811fa71b9SJerome Forissier &crt->subject_alt_names, 183932b31808SJens Wiklander prefix)) != 0) { 184032b31808SJens Wiklander return ret; 184132b31808SJens Wiklander } 1842817466cbSJens Wiklander } 1843817466cbSJens Wiklander 184432b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) { 1845817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%scert. type : ", prefix); 1846817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1847817466cbSJens Wiklander 184832b31808SJens Wiklander if ((ret = mbedtls_x509_info_cert_type(&p, &n, crt->ns_cert_type)) != 0) { 184932b31808SJens Wiklander return ret; 185032b31808SJens Wiklander } 1851817466cbSJens Wiklander } 1852817466cbSJens Wiklander 185332b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE) { 1854817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%skey usage : ", prefix); 1855817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1856817466cbSJens Wiklander 185732b31808SJens Wiklander if ((ret = mbedtls_x509_info_key_usage(&p, &n, crt->key_usage)) != 0) { 185832b31808SJens Wiklander return ret; 185932b31808SJens Wiklander } 1860817466cbSJens Wiklander } 1861817466cbSJens Wiklander 186232b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE) { 1863817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sext key usage : ", prefix); 1864817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1865817466cbSJens Wiklander 1866817466cbSJens Wiklander if ((ret = x509_info_ext_key_usage(&p, &n, 186732b31808SJens Wiklander &crt->ext_key_usage)) != 0) { 186832b31808SJens Wiklander return ret; 186932b31808SJens Wiklander } 1870817466cbSJens Wiklander } 1871817466cbSJens Wiklander 187232b31808SJens Wiklander if (crt->ext_types & MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES) { 187311fa71b9SJerome Forissier ret = mbedtls_snprintf(p, n, "\n%scertificate policies : ", prefix); 187411fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 187511fa71b9SJerome Forissier 187611fa71b9SJerome Forissier if ((ret = x509_info_cert_policies(&p, &n, 187732b31808SJens Wiklander &crt->certificate_policies)) != 0) { 187832b31808SJens Wiklander return ret; 187932b31808SJens Wiklander } 188011fa71b9SJerome Forissier } 188111fa71b9SJerome Forissier 1882817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n"); 1883817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1884817466cbSJens Wiklander 188532b31808SJens Wiklander return (int) (size - n); 1886817466cbSJens Wiklander } 1887817466cbSJens Wiklander 1888817466cbSJens Wiklander struct x509_crt_verify_string { 1889817466cbSJens Wiklander int code; 1890817466cbSJens Wiklander const char *string; 1891817466cbSJens Wiklander }; 1892817466cbSJens Wiklander 189332b31808SJens Wiklander #define X509_CRT_ERROR_INFO(err, err_str, info) { err, info }, 1894817466cbSJens Wiklander static const struct x509_crt_verify_string x509_crt_verify_strings[] = { 189532b31808SJens Wiklander MBEDTLS_X509_CRT_ERROR_INFO_LIST 1896817466cbSJens Wiklander { 0, NULL } 1897817466cbSJens Wiklander }; 189832b31808SJens Wiklander #undef X509_CRT_ERROR_INFO 1899817466cbSJens Wiklander 1900817466cbSJens Wiklander int mbedtls_x509_crt_verify_info(char *buf, size_t size, const char *prefix, 1901817466cbSJens Wiklander uint32_t flags) 1902817466cbSJens Wiklander { 190311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1904817466cbSJens Wiklander const struct x509_crt_verify_string *cur; 1905817466cbSJens Wiklander char *p = buf; 1906817466cbSJens Wiklander size_t n = size; 1907817466cbSJens Wiklander 190832b31808SJens Wiklander for (cur = x509_crt_verify_strings; cur->string != NULL; cur++) { 190932b31808SJens Wiklander if ((flags & cur->code) == 0) { 1910817466cbSJens Wiklander continue; 191132b31808SJens Wiklander } 1912817466cbSJens Wiklander 1913817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%s%s\n", prefix, cur->string); 1914817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1915817466cbSJens Wiklander flags ^= cur->code; 1916817466cbSJens Wiklander } 1917817466cbSJens Wiklander 191832b31808SJens Wiklander if (flags != 0) { 1919817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%sUnknown reason " 1920817466cbSJens Wiklander "(this should not happen)\n", prefix); 1921817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1922817466cbSJens Wiklander } 1923817466cbSJens Wiklander 192432b31808SJens Wiklander return (int) (size - n); 1925817466cbSJens Wiklander } 192632b31808SJens Wiklander #endif /* MBEDTLS_X509_REMOVE_INFO */ 1927817466cbSJens Wiklander 1928817466cbSJens Wiklander int mbedtls_x509_crt_check_key_usage(const mbedtls_x509_crt *crt, 1929817466cbSJens Wiklander unsigned int usage) 1930817466cbSJens Wiklander { 1931817466cbSJens Wiklander unsigned int usage_must, usage_may; 1932817466cbSJens Wiklander unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY 1933817466cbSJens Wiklander | MBEDTLS_X509_KU_DECIPHER_ONLY; 1934817466cbSJens Wiklander 193532b31808SJens Wiklander if ((crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE) == 0) { 193632b31808SJens Wiklander return 0; 193732b31808SJens Wiklander } 1938817466cbSJens Wiklander 1939817466cbSJens Wiklander usage_must = usage & ~may_mask; 1940817466cbSJens Wiklander 194132b31808SJens Wiklander if (((crt->key_usage & ~may_mask) & usage_must) != usage_must) { 194232b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 194332b31808SJens Wiklander } 1944817466cbSJens Wiklander 1945817466cbSJens Wiklander usage_may = usage & may_mask; 1946817466cbSJens Wiklander 194732b31808SJens Wiklander if (((crt->key_usage & may_mask) | usage_may) != usage_may) { 194832b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 1949817466cbSJens Wiklander } 1950817466cbSJens Wiklander 195132b31808SJens Wiklander return 0; 195232b31808SJens Wiklander } 195332b31808SJens Wiklander 1954817466cbSJens Wiklander int mbedtls_x509_crt_check_extended_key_usage(const mbedtls_x509_crt *crt, 1955817466cbSJens Wiklander const char *usage_oid, 1956817466cbSJens Wiklander size_t usage_len) 1957817466cbSJens Wiklander { 1958817466cbSJens Wiklander const mbedtls_x509_sequence *cur; 1959817466cbSJens Wiklander 1960817466cbSJens Wiklander /* Extension is not mandatory, absent means no restriction */ 196132b31808SJens Wiklander if ((crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE) == 0) { 196232b31808SJens Wiklander return 0; 196332b31808SJens Wiklander } 1964817466cbSJens Wiklander 1965817466cbSJens Wiklander /* 1966817466cbSJens Wiklander * Look for the requested usage (or wildcard ANY) in our list 1967817466cbSJens Wiklander */ 196832b31808SJens Wiklander for (cur = &crt->ext_key_usage; cur != NULL; cur = cur->next) { 1969817466cbSJens Wiklander const mbedtls_x509_buf *cur_oid = &cur->buf; 1970817466cbSJens Wiklander 1971817466cbSJens Wiklander if (cur_oid->len == usage_len && 197232b31808SJens Wiklander memcmp(cur_oid->p, usage_oid, usage_len) == 0) { 197332b31808SJens Wiklander return 0; 1974817466cbSJens Wiklander } 1975817466cbSJens Wiklander 197632b31808SJens Wiklander if (MBEDTLS_OID_CMP(MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid) == 0) { 197732b31808SJens Wiklander return 0; 197832b31808SJens Wiklander } 1979817466cbSJens Wiklander } 1980817466cbSJens Wiklander 198132b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 1982817466cbSJens Wiklander } 1983817466cbSJens Wiklander 1984817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C) 1985817466cbSJens Wiklander /* 1986817466cbSJens Wiklander * Return 1 if the certificate is revoked, or 0 otherwise. 1987817466cbSJens Wiklander */ 1988817466cbSJens Wiklander int mbedtls_x509_crt_is_revoked(const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl) 1989817466cbSJens Wiklander { 1990817466cbSJens Wiklander const mbedtls_x509_crl_entry *cur = &crl->entry; 1991817466cbSJens Wiklander 199232b31808SJens Wiklander while (cur != NULL && cur->serial.len != 0) { 1993817466cbSJens Wiklander if (crt->serial.len == cur->serial.len && 199432b31808SJens Wiklander memcmp(crt->serial.p, cur->serial.p, crt->serial.len) == 0) { 199532b31808SJens Wiklander return 1; 1996817466cbSJens Wiklander } 1997817466cbSJens Wiklander 1998817466cbSJens Wiklander cur = cur->next; 1999817466cbSJens Wiklander } 2000817466cbSJens Wiklander 200132b31808SJens Wiklander return 0; 2002817466cbSJens Wiklander } 2003817466cbSJens Wiklander 2004817466cbSJens Wiklander /* 2005817466cbSJens Wiklander * Check that the given certificate is not revoked according to the CRL. 20063d3b0591SJens Wiklander * Skip validation if no CRL for the given CA is present. 2007817466cbSJens Wiklander */ 2008817466cbSJens Wiklander static int x509_crt_verifycrl(mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, 2009817466cbSJens Wiklander mbedtls_x509_crl *crl_list, 2010*b0563631STom Van Eyck const mbedtls_x509_crt_profile *profile, 2011*b0563631STom Van Eyck const mbedtls_x509_time *now) 2012817466cbSJens Wiklander { 2013817466cbSJens Wiklander int flags = 0; 2014*b0563631STom Van Eyck unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 201532b31808SJens Wiklander #if defined(MBEDTLS_USE_PSA_CRYPTO) 201632b31808SJens Wiklander psa_algorithm_t psa_algorithm; 201732b31808SJens Wiklander #else 2018817466cbSJens Wiklander const mbedtls_md_info_t *md_info; 201932b31808SJens Wiklander #endif /* MBEDTLS_USE_PSA_CRYPTO */ 202032b31808SJens Wiklander size_t hash_length; 2021817466cbSJens Wiklander 202232b31808SJens Wiklander if (ca == NULL) { 202332b31808SJens Wiklander return flags; 202432b31808SJens Wiklander } 2025817466cbSJens Wiklander 202632b31808SJens Wiklander while (crl_list != NULL) { 2027817466cbSJens Wiklander if (crl_list->version == 0 || 202832b31808SJens Wiklander x509_name_cmp(&crl_list->issuer, &ca->subject) != 0) { 2029817466cbSJens Wiklander crl_list = crl_list->next; 2030817466cbSJens Wiklander continue; 2031817466cbSJens Wiklander } 2032817466cbSJens Wiklander 2033817466cbSJens Wiklander /* 2034817466cbSJens Wiklander * Check if the CA is configured to sign CRLs 2035817466cbSJens Wiklander */ 20363d3b0591SJens Wiklander if (mbedtls_x509_crt_check_key_usage(ca, 203732b31808SJens Wiklander MBEDTLS_X509_KU_CRL_SIGN) != 0) { 2038817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 2039817466cbSJens Wiklander break; 2040817466cbSJens Wiklander } 2041817466cbSJens Wiklander 2042817466cbSJens Wiklander /* 2043817466cbSJens Wiklander * Check if CRL is correctly signed by the trusted CA 2044817466cbSJens Wiklander */ 204532b31808SJens Wiklander if (x509_profile_check_md_alg(profile, crl_list->sig_md) != 0) { 2046817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_MD; 204732b31808SJens Wiklander } 2048817466cbSJens Wiklander 204932b31808SJens Wiklander if (x509_profile_check_pk_alg(profile, crl_list->sig_pk) != 0) { 2050817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_PK; 205132b31808SJens Wiklander } 2052817466cbSJens Wiklander 205332b31808SJens Wiklander #if defined(MBEDTLS_USE_PSA_CRYPTO) 2054*b0563631STom Van Eyck psa_algorithm = mbedtls_md_psa_alg_from_type(crl_list->sig_md); 205532b31808SJens Wiklander if (psa_hash_compute(psa_algorithm, 205632b31808SJens Wiklander crl_list->tbs.p, 205732b31808SJens Wiklander crl_list->tbs.len, 205832b31808SJens Wiklander hash, 205932b31808SJens Wiklander sizeof(hash), 206032b31808SJens Wiklander &hash_length) != PSA_SUCCESS) { 20613d3b0591SJens Wiklander /* Note: this can't happen except after an internal error */ 2062817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 2063817466cbSJens Wiklander break; 2064817466cbSJens Wiklander } 206532b31808SJens Wiklander #else 206632b31808SJens Wiklander md_info = mbedtls_md_info_from_type(crl_list->sig_md); 206732b31808SJens Wiklander hash_length = mbedtls_md_get_size(md_info); 206832b31808SJens Wiklander if (mbedtls_md(md_info, 206932b31808SJens Wiklander crl_list->tbs.p, 207032b31808SJens Wiklander crl_list->tbs.len, 207132b31808SJens Wiklander hash) != 0) { 207232b31808SJens Wiklander /* Note: this can't happen except after an internal error */ 207332b31808SJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 207432b31808SJens Wiklander break; 207532b31808SJens Wiklander } 207632b31808SJens Wiklander #endif /* MBEDTLS_USE_PSA_CRYPTO */ 2077817466cbSJens Wiklander 207832b31808SJens Wiklander if (x509_profile_check_key(profile, &ca->pk) != 0) { 2079817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 208032b31808SJens Wiklander } 2081817466cbSJens Wiklander 2082817466cbSJens Wiklander if (mbedtls_pk_verify_ext(crl_list->sig_pk, crl_list->sig_opts, &ca->pk, 208332b31808SJens Wiklander crl_list->sig_md, hash, hash_length, 208432b31808SJens Wiklander crl_list->sig.p, crl_list->sig.len) != 0) { 2085817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 2086817466cbSJens Wiklander break; 2087817466cbSJens Wiklander } 2088817466cbSJens Wiklander 2089*b0563631STom Van Eyck #if defined(MBEDTLS_HAVE_TIME_DATE) 2090817466cbSJens Wiklander /* 2091817466cbSJens Wiklander * Check for validity of CRL (Do not drop out) 2092817466cbSJens Wiklander */ 2093*b0563631STom Van Eyck if (mbedtls_x509_time_cmp(&crl_list->next_update, now) < 0) { 2094817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_EXPIRED; 209532b31808SJens Wiklander } 2096817466cbSJens Wiklander 2097*b0563631STom Van Eyck if (mbedtls_x509_time_cmp(&crl_list->this_update, now) > 0) { 2098817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_FUTURE; 209932b31808SJens Wiklander } 2100*b0563631STom Van Eyck #else 2101*b0563631STom Van Eyck ((void) now); 2102*b0563631STom Van Eyck #endif 2103817466cbSJens Wiklander 2104817466cbSJens Wiklander /* 2105817466cbSJens Wiklander * Check if certificate is revoked 2106817466cbSJens Wiklander */ 210732b31808SJens Wiklander if (mbedtls_x509_crt_is_revoked(crt, crl_list)) { 2108817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_REVOKED; 2109817466cbSJens Wiklander break; 2110817466cbSJens Wiklander } 2111817466cbSJens Wiklander 2112817466cbSJens Wiklander crl_list = crl_list->next; 2113817466cbSJens Wiklander } 2114817466cbSJens Wiklander 211532b31808SJens Wiklander return flags; 2116817466cbSJens Wiklander } 2117817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRL_PARSE_C */ 2118817466cbSJens Wiklander 2119817466cbSJens Wiklander /* 21203d3b0591SJens Wiklander * Check the signature of a certificate by its parent 2121817466cbSJens Wiklander */ 21223d3b0591SJens Wiklander static int x509_crt_check_signature(const mbedtls_x509_crt *child, 21233d3b0591SJens Wiklander mbedtls_x509_crt *parent, 21243d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx) 2125817466cbSJens Wiklander { 212611fa71b9SJerome Forissier size_t hash_len; 2127*b0563631STom Van Eyck unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 212811fa71b9SJerome Forissier #if !defined(MBEDTLS_USE_PSA_CRYPTO) 212911fa71b9SJerome Forissier const mbedtls_md_info_t *md_info; 21303d3b0591SJens Wiklander md_info = mbedtls_md_info_from_type(child->sig_md); 213111fa71b9SJerome Forissier hash_len = mbedtls_md_get_size(md_info); 213211fa71b9SJerome Forissier 213311fa71b9SJerome Forissier /* Note: hash errors can happen only after an internal error */ 213432b31808SJens Wiklander if (mbedtls_md(md_info, child->tbs.p, child->tbs.len, hash) != 0) { 213532b31808SJens Wiklander return -1; 213632b31808SJens Wiklander } 213711fa71b9SJerome Forissier #else 2138*b0563631STom Van Eyck psa_algorithm_t hash_alg = mbedtls_md_psa_alg_from_type(child->sig_md); 213932b31808SJens Wiklander psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 214011fa71b9SJerome Forissier 214132b31808SJens Wiklander status = psa_hash_compute(hash_alg, 214232b31808SJens Wiklander child->tbs.p, 214332b31808SJens Wiklander child->tbs.len, 214432b31808SJens Wiklander hash, 214532b31808SJens Wiklander sizeof(hash), 214632b31808SJens Wiklander &hash_len); 214732b31808SJens Wiklander if (status != PSA_SUCCESS) { 214832b31808SJens Wiklander return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED; 2149817466cbSJens Wiklander } 2150817466cbSJens Wiklander 215111fa71b9SJerome Forissier #endif /* MBEDTLS_USE_PSA_CRYPTO */ 21523d3b0591SJens Wiklander /* Skip expensive computation on obvious mismatch */ 215332b31808SJens Wiklander if (!mbedtls_pk_can_do(&parent->pk, child->sig_pk)) { 215432b31808SJens Wiklander return -1; 215532b31808SJens Wiklander } 2156817466cbSJens Wiklander 21573d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 215832b31808SJens Wiklander if (rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA) { 215932b31808SJens Wiklander return mbedtls_pk_verify_restartable(&parent->pk, 216011fa71b9SJerome Forissier child->sig_md, hash, hash_len, 216132b31808SJens Wiklander child->sig.p, child->sig.len, &rs_ctx->pk); 2162817466cbSJens Wiklander } 21633d3b0591SJens Wiklander #else 21643d3b0591SJens Wiklander (void) rs_ctx; 21653d3b0591SJens Wiklander #endif 2166817466cbSJens Wiklander 216732b31808SJens Wiklander return mbedtls_pk_verify_ext(child->sig_pk, child->sig_opts, &parent->pk, 216811fa71b9SJerome Forissier child->sig_md, hash, hash_len, 216932b31808SJens Wiklander child->sig.p, child->sig.len); 2170817466cbSJens Wiklander } 2171817466cbSJens Wiklander 2172817466cbSJens Wiklander /* 2173817466cbSJens Wiklander * Check if 'parent' is a suitable parent (signing CA) for 'child'. 2174817466cbSJens Wiklander * Return 0 if yes, -1 if not. 2175817466cbSJens Wiklander * 2176817466cbSJens Wiklander * top means parent is a locally-trusted certificate 2177817466cbSJens Wiklander */ 2178817466cbSJens Wiklander static int x509_crt_check_parent(const mbedtls_x509_crt *child, 2179817466cbSJens Wiklander const mbedtls_x509_crt *parent, 21803d3b0591SJens Wiklander int top) 2181817466cbSJens Wiklander { 2182817466cbSJens Wiklander int need_ca_bit; 2183817466cbSJens Wiklander 2184817466cbSJens Wiklander /* Parent must be the issuer */ 218532b31808SJens Wiklander if (x509_name_cmp(&child->issuer, &parent->subject) != 0) { 218632b31808SJens Wiklander return -1; 218732b31808SJens Wiklander } 2188817466cbSJens Wiklander 2189817466cbSJens Wiklander /* Parent must have the basicConstraints CA bit set as a general rule */ 2190817466cbSJens Wiklander need_ca_bit = 1; 2191817466cbSJens Wiklander 2192817466cbSJens Wiklander /* Exception: v1/v2 certificates that are locally trusted. */ 219332b31808SJens Wiklander if (top && parent->version < 3) { 2194817466cbSJens Wiklander need_ca_bit = 0; 2195817466cbSJens Wiklander } 2196817466cbSJens Wiklander 219732b31808SJens Wiklander if (need_ca_bit && !parent->ca_istrue) { 219832b31808SJens Wiklander return -1; 219932b31808SJens Wiklander } 220032b31808SJens Wiklander 220132b31808SJens Wiklander if (need_ca_bit && 220232b31808SJens Wiklander mbedtls_x509_crt_check_key_usage(parent, MBEDTLS_X509_KU_KEY_CERT_SIGN) != 0) { 220332b31808SJens Wiklander return -1; 220432b31808SJens Wiklander } 220532b31808SJens Wiklander 220632b31808SJens Wiklander return 0; 2207817466cbSJens Wiklander } 2208817466cbSJens Wiklander 22093d3b0591SJens Wiklander /* 22103d3b0591SJens Wiklander * Find a suitable parent for child in candidates, or return NULL. 22113d3b0591SJens Wiklander * 22123d3b0591SJens Wiklander * Here suitable is defined as: 22133d3b0591SJens Wiklander * 1. subject name matches child's issuer 22143d3b0591SJens Wiklander * 2. if necessary, the CA bit is set and key usage allows signing certs 22153d3b0591SJens Wiklander * 3. for trusted roots, the signature is correct 22163d3b0591SJens Wiklander * (for intermediates, the signature is checked and the result reported) 22173d3b0591SJens Wiklander * 4. pathlen constraints are satisfied 22183d3b0591SJens Wiklander * 22193d3b0591SJens Wiklander * If there's a suitable candidate which is also time-valid, return the first 22203d3b0591SJens Wiklander * such. Otherwise, return the first suitable candidate (or NULL if there is 22213d3b0591SJens Wiklander * none). 22223d3b0591SJens Wiklander * 22233d3b0591SJens Wiklander * The rationale for this rule is that someone could have a list of trusted 22243d3b0591SJens Wiklander * roots with two versions on the same root with different validity periods. 22253d3b0591SJens Wiklander * (At least one user reported having such a list and wanted it to just work.) 22263d3b0591SJens Wiklander * The reason we don't just require time-validity is that generally there is 22273d3b0591SJens Wiklander * only one version, and if it's expired we want the flags to state that 22283d3b0591SJens Wiklander * rather than NOT_TRUSTED, as would be the case if we required it here. 22293d3b0591SJens Wiklander * 22303d3b0591SJens Wiklander * The rationale for rule 3 (signature for trusted roots) is that users might 22313d3b0591SJens Wiklander * have two versions of the same CA with different keys in their list, and the 22323d3b0591SJens Wiklander * way we select the correct one is by checking the signature (as we don't 22333d3b0591SJens Wiklander * rely on key identifier extensions). (This is one way users might choose to 22343d3b0591SJens Wiklander * handle key rollover, another relies on self-issued certs, see [SIRO].) 22353d3b0591SJens Wiklander * 22363d3b0591SJens Wiklander * Arguments: 22373d3b0591SJens Wiklander * - [in] child: certificate for which we're looking for a parent 22383d3b0591SJens Wiklander * - [in] candidates: chained list of potential parents 22393d3b0591SJens Wiklander * - [out] r_parent: parent found (or NULL) 22403d3b0591SJens Wiklander * - [out] r_signature_is_good: 1 if child signature by parent is valid, or 0 22413d3b0591SJens Wiklander * - [in] top: 1 if candidates consists of trusted roots, ie we're at the top 22423d3b0591SJens Wiklander * of the chain, 0 otherwise 22433d3b0591SJens Wiklander * - [in] path_cnt: number of intermediates seen so far 22443d3b0591SJens Wiklander * - [in] self_cnt: number of self-signed intermediates seen so far 22453d3b0591SJens Wiklander * (will never be greater than path_cnt) 22463d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 22473d3b0591SJens Wiklander * 22483d3b0591SJens Wiklander * Return value: 22493d3b0591SJens Wiklander * - 0 on success 22503d3b0591SJens Wiklander * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise 22513d3b0591SJens Wiklander */ 22523d3b0591SJens Wiklander static int x509_crt_find_parent_in( 22533d3b0591SJens Wiklander mbedtls_x509_crt *child, 22543d3b0591SJens Wiklander mbedtls_x509_crt *candidates, 22553d3b0591SJens Wiklander mbedtls_x509_crt **r_parent, 22563d3b0591SJens Wiklander int *r_signature_is_good, 22573d3b0591SJens Wiklander int top, 22583d3b0591SJens Wiklander unsigned path_cnt, 22593d3b0591SJens Wiklander unsigned self_cnt, 2260*b0563631STom Van Eyck mbedtls_x509_crt_restart_ctx *rs_ctx, 2261*b0563631STom Van Eyck const mbedtls_x509_time *now) 2262817466cbSJens Wiklander { 226311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 22643d3b0591SJens Wiklander mbedtls_x509_crt *parent, *fallback_parent; 226511fa71b9SJerome Forissier int signature_is_good = 0, fallback_signature_is_good; 2266817466cbSJens Wiklander 22673d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 22683d3b0591SJens Wiklander /* did we have something in progress? */ 226932b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->parent != NULL) { 22703d3b0591SJens Wiklander /* restore saved state */ 22713d3b0591SJens Wiklander parent = rs_ctx->parent; 22723d3b0591SJens Wiklander fallback_parent = rs_ctx->fallback_parent; 22733d3b0591SJens Wiklander fallback_signature_is_good = rs_ctx->fallback_signature_is_good; 22743d3b0591SJens Wiklander 22753d3b0591SJens Wiklander /* clear saved state */ 22763d3b0591SJens Wiklander rs_ctx->parent = NULL; 22773d3b0591SJens Wiklander rs_ctx->fallback_parent = NULL; 22783d3b0591SJens Wiklander rs_ctx->fallback_signature_is_good = 0; 22793d3b0591SJens Wiklander 22803d3b0591SJens Wiklander /* resume where we left */ 22813d3b0591SJens Wiklander goto check_signature; 2282817466cbSJens Wiklander } 22833d3b0591SJens Wiklander #endif 2284817466cbSJens Wiklander 22853d3b0591SJens Wiklander fallback_parent = NULL; 22863d3b0591SJens Wiklander fallback_signature_is_good = 0; 22873d3b0591SJens Wiklander 228832b31808SJens Wiklander for (parent = candidates; parent != NULL; parent = parent->next) { 22893d3b0591SJens Wiklander /* basic parenting skills (name, CA bit, key usage) */ 229032b31808SJens Wiklander if (x509_crt_check_parent(child, parent, top) != 0) { 2291817466cbSJens Wiklander continue; 229232b31808SJens Wiklander } 2293817466cbSJens Wiklander 22943d3b0591SJens Wiklander /* +1 because stored max_pathlen is 1 higher that the actual value */ 22953d3b0591SJens Wiklander if (parent->max_pathlen > 0 && 229632b31808SJens Wiklander (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt) { 2297817466cbSJens Wiklander continue; 2298817466cbSJens Wiklander } 2299817466cbSJens Wiklander 23003d3b0591SJens Wiklander /* Signature */ 23013d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 23023d3b0591SJens Wiklander check_signature: 23033d3b0591SJens Wiklander #endif 23043d3b0591SJens Wiklander ret = x509_crt_check_signature(child, parent, rs_ctx); 2305817466cbSJens Wiklander 23063d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 230732b31808SJens Wiklander if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 23083d3b0591SJens Wiklander /* save state */ 23093d3b0591SJens Wiklander rs_ctx->parent = parent; 23103d3b0591SJens Wiklander rs_ctx->fallback_parent = fallback_parent; 23113d3b0591SJens Wiklander rs_ctx->fallback_signature_is_good = fallback_signature_is_good; 23123d3b0591SJens Wiklander 231332b31808SJens Wiklander return ret; 23143d3b0591SJens Wiklander } 23153d3b0591SJens Wiklander #else 23163d3b0591SJens Wiklander (void) ret; 23173d3b0591SJens Wiklander #endif 23183d3b0591SJens Wiklander 23193d3b0591SJens Wiklander signature_is_good = ret == 0; 232032b31808SJens Wiklander if (top && !signature_is_good) { 23213d3b0591SJens Wiklander continue; 232232b31808SJens Wiklander } 23233d3b0591SJens Wiklander 2324*b0563631STom Van Eyck #if defined(MBEDTLS_HAVE_TIME_DATE) 23253d3b0591SJens Wiklander /* optional time check */ 2326*b0563631STom Van Eyck if (mbedtls_x509_time_cmp(&parent->valid_to, now) < 0 || /* past */ 2327*b0563631STom Van Eyck mbedtls_x509_time_cmp(&parent->valid_from, now) > 0) { /* future */ 232832b31808SJens Wiklander if (fallback_parent == NULL) { 23293d3b0591SJens Wiklander fallback_parent = parent; 23303d3b0591SJens Wiklander fallback_signature_is_good = signature_is_good; 23313d3b0591SJens Wiklander } 2332817466cbSJens Wiklander 2333817466cbSJens Wiklander continue; 2334817466cbSJens Wiklander } 2335*b0563631STom Van Eyck #else 2336*b0563631STom Van Eyck ((void) now); 2337*b0563631STom Van Eyck #endif 2338817466cbSJens Wiklander 23395b25c76aSJerome Forissier *r_parent = parent; 23405b25c76aSJerome Forissier *r_signature_is_good = signature_is_good; 23415b25c76aSJerome Forissier 2342817466cbSJens Wiklander break; 2343817466cbSJens Wiklander } 2344817466cbSJens Wiklander 234532b31808SJens Wiklander if (parent == NULL) { 23463d3b0591SJens Wiklander *r_parent = fallback_parent; 23473d3b0591SJens Wiklander *r_signature_is_good = fallback_signature_is_good; 2348817466cbSJens Wiklander } 2349817466cbSJens Wiklander 235032b31808SJens Wiklander return 0; 2351817466cbSJens Wiklander } 2352817466cbSJens Wiklander 23533d3b0591SJens Wiklander /* 23543d3b0591SJens Wiklander * Find a parent in trusted CAs or the provided chain, or return NULL. 23553d3b0591SJens Wiklander * 23563d3b0591SJens Wiklander * Searches in trusted CAs first, and return the first suitable parent found 23573d3b0591SJens Wiklander * (see find_parent_in() for definition of suitable). 23583d3b0591SJens Wiklander * 23593d3b0591SJens Wiklander * Arguments: 23603d3b0591SJens Wiklander * - [in] child: certificate for which we're looking for a parent, followed 23613d3b0591SJens Wiklander * by a chain of possible intermediates 23623d3b0591SJens Wiklander * - [in] trust_ca: list of locally trusted certificates 23633d3b0591SJens Wiklander * - [out] parent: parent found (or NULL) 23643d3b0591SJens Wiklander * - [out] parent_is_trusted: 1 if returned `parent` is trusted, or 0 23653d3b0591SJens Wiklander * - [out] signature_is_good: 1 if child signature by parent is valid, or 0 23663d3b0591SJens Wiklander * - [in] path_cnt: number of links in the chain so far (EE -> ... -> child) 23673d3b0591SJens Wiklander * - [in] self_cnt: number of self-signed certs in the chain so far 23683d3b0591SJens Wiklander * (will always be no greater than path_cnt) 23693d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 23703d3b0591SJens Wiklander * 23713d3b0591SJens Wiklander * Return value: 23723d3b0591SJens Wiklander * - 0 on success 23733d3b0591SJens Wiklander * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise 23743d3b0591SJens Wiklander */ 23753d3b0591SJens Wiklander static int x509_crt_find_parent( 23763d3b0591SJens Wiklander mbedtls_x509_crt *child, 23773d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 23783d3b0591SJens Wiklander mbedtls_x509_crt **parent, 23793d3b0591SJens Wiklander int *parent_is_trusted, 23803d3b0591SJens Wiklander int *signature_is_good, 23813d3b0591SJens Wiklander unsigned path_cnt, 23823d3b0591SJens Wiklander unsigned self_cnt, 2383*b0563631STom Van Eyck mbedtls_x509_crt_restart_ctx *rs_ctx, 2384*b0563631STom Van Eyck const mbedtls_x509_time *now) 2385817466cbSJens Wiklander { 238611fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 23873d3b0591SJens Wiklander mbedtls_x509_crt *search_list; 2388817466cbSJens Wiklander 23893d3b0591SJens Wiklander *parent_is_trusted = 1; 2390817466cbSJens Wiklander 23913d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 23923d3b0591SJens Wiklander /* restore then clear saved state if we have some stored */ 239332b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->parent_is_trusted != -1) { 23943d3b0591SJens Wiklander *parent_is_trusted = rs_ctx->parent_is_trusted; 23953d3b0591SJens Wiklander rs_ctx->parent_is_trusted = -1; 23963d3b0591SJens Wiklander } 23973d3b0591SJens Wiklander #endif 23983d3b0591SJens Wiklander 23993d3b0591SJens Wiklander while (1) { 24003d3b0591SJens Wiklander search_list = *parent_is_trusted ? trust_ca : child->next; 24013d3b0591SJens Wiklander 24023d3b0591SJens Wiklander ret = x509_crt_find_parent_in(child, search_list, 24033d3b0591SJens Wiklander parent, signature_is_good, 24043d3b0591SJens Wiklander *parent_is_trusted, 2405*b0563631STom Van Eyck path_cnt, self_cnt, rs_ctx, now); 24063d3b0591SJens Wiklander 24073d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 240832b31808SJens Wiklander if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 24093d3b0591SJens Wiklander /* save state */ 24103d3b0591SJens Wiklander rs_ctx->parent_is_trusted = *parent_is_trusted; 241132b31808SJens Wiklander return ret; 24123d3b0591SJens Wiklander } 24133d3b0591SJens Wiklander #else 24143d3b0591SJens Wiklander (void) ret; 24153d3b0591SJens Wiklander #endif 24163d3b0591SJens Wiklander 24173d3b0591SJens Wiklander /* stop here if found or already in second iteration */ 241832b31808SJens Wiklander if (*parent != NULL || *parent_is_trusted == 0) { 24193d3b0591SJens Wiklander break; 242032b31808SJens Wiklander } 24213d3b0591SJens Wiklander 24223d3b0591SJens Wiklander /* prepare second iteration */ 24233d3b0591SJens Wiklander *parent_is_trusted = 0; 2424817466cbSJens Wiklander } 2425817466cbSJens Wiklander 24263d3b0591SJens Wiklander /* extra precaution against mistakes in the caller */ 242732b31808SJens Wiklander if (*parent == NULL) { 24283d3b0591SJens Wiklander *parent_is_trusted = 0; 24293d3b0591SJens Wiklander *signature_is_good = 0; 24303d3b0591SJens Wiklander } 24313d3b0591SJens Wiklander 243232b31808SJens Wiklander return 0; 24333d3b0591SJens Wiklander } 24343d3b0591SJens Wiklander 24353d3b0591SJens Wiklander /* 24363d3b0591SJens Wiklander * Check if an end-entity certificate is locally trusted 24373d3b0591SJens Wiklander * 24383d3b0591SJens Wiklander * Currently we require such certificates to be self-signed (actually only 24393d3b0591SJens Wiklander * check for self-issued as self-signatures are not checked) 24403d3b0591SJens Wiklander */ 24413d3b0591SJens Wiklander static int x509_crt_check_ee_locally_trusted( 24423d3b0591SJens Wiklander mbedtls_x509_crt *crt, 24433d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca) 24443d3b0591SJens Wiklander { 24453d3b0591SJens Wiklander mbedtls_x509_crt *cur; 24463d3b0591SJens Wiklander 24473d3b0591SJens Wiklander /* must be self-issued */ 244832b31808SJens Wiklander if (x509_name_cmp(&crt->issuer, &crt->subject) != 0) { 244932b31808SJens Wiklander return -1; 245032b31808SJens Wiklander } 24513d3b0591SJens Wiklander 24523d3b0591SJens Wiklander /* look for an exact match with trusted cert */ 245332b31808SJens Wiklander for (cur = trust_ca; cur != NULL; cur = cur->next) { 24543d3b0591SJens Wiklander if (crt->raw.len == cur->raw.len && 245532b31808SJens Wiklander memcmp(crt->raw.p, cur->raw.p, crt->raw.len) == 0) { 245632b31808SJens Wiklander return 0; 24573d3b0591SJens Wiklander } 24583d3b0591SJens Wiklander } 24593d3b0591SJens Wiklander 24603d3b0591SJens Wiklander /* too bad */ 246132b31808SJens Wiklander return -1; 24623d3b0591SJens Wiklander } 24633d3b0591SJens Wiklander 24643d3b0591SJens Wiklander /* 24653d3b0591SJens Wiklander * Build and verify a certificate chain 24663d3b0591SJens Wiklander * 24673d3b0591SJens Wiklander * Given a peer-provided list of certificates EE, C1, ..., Cn and 24683d3b0591SJens Wiklander * a list of trusted certs R1, ... Rp, try to build and verify a chain 24693d3b0591SJens Wiklander * EE, Ci1, ... Ciq [, Rj] 24703d3b0591SJens Wiklander * such that every cert in the chain is a child of the next one, 24713d3b0591SJens Wiklander * jumping to a trusted root as early as possible. 24723d3b0591SJens Wiklander * 24733d3b0591SJens Wiklander * Verify that chain and return it with flags for all issues found. 24743d3b0591SJens Wiklander * 24753d3b0591SJens Wiklander * Special cases: 24763d3b0591SJens Wiklander * - EE == Rj -> return a one-element list containing it 24773d3b0591SJens Wiklander * - EE, Ci1, ..., Ciq cannot be continued with a trusted root 24783d3b0591SJens Wiklander * -> return that chain with NOT_TRUSTED set on Ciq 24793d3b0591SJens Wiklander * 24803d3b0591SJens Wiklander * Tests for (aspects of) this function should include at least: 24813d3b0591SJens Wiklander * - trusted EE 24823d3b0591SJens Wiklander * - EE -> trusted root 24835b25c76aSJerome Forissier * - EE -> intermediate CA -> trusted root 24843d3b0591SJens Wiklander * - if relevant: EE untrusted 24853d3b0591SJens Wiklander * - if relevant: EE -> intermediate, untrusted 24863d3b0591SJens Wiklander * with the aspect under test checked at each relevant level (EE, int, root). 24873d3b0591SJens Wiklander * For some aspects longer chains are required, but usually length 2 is 24883d3b0591SJens Wiklander * enough (but length 1 is not in general). 24893d3b0591SJens Wiklander * 24903d3b0591SJens Wiklander * Arguments: 24913d3b0591SJens Wiklander * - [in] crt: the cert list EE, C1, ..., Cn 24923d3b0591SJens Wiklander * - [in] trust_ca: the trusted list R1, ..., Rp 24933d3b0591SJens Wiklander * - [in] ca_crl, profile: as in verify_with_profile() 24943d3b0591SJens Wiklander * - [out] ver_chain: the built and verified chain 24953d3b0591SJens Wiklander * Only valid when return value is 0, may contain garbage otherwise! 24963d3b0591SJens Wiklander * Restart note: need not be the same when calling again to resume. 24973d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 24983d3b0591SJens Wiklander * 24993d3b0591SJens Wiklander * Return value: 25003d3b0591SJens Wiklander * - non-zero if the chain could not be fully built and examined 25013d3b0591SJens Wiklander * - 0 is the chain was successfully built and examined, 25023d3b0591SJens Wiklander * even if it was found to be invalid 25033d3b0591SJens Wiklander */ 25043d3b0591SJens Wiklander static int x509_crt_verify_chain( 25053d3b0591SJens Wiklander mbedtls_x509_crt *crt, 25063d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 25073d3b0591SJens Wiklander mbedtls_x509_crl *ca_crl, 250811fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 250911fa71b9SJerome Forissier void *p_ca_cb, 25103d3b0591SJens Wiklander const mbedtls_x509_crt_profile *profile, 25113d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain *ver_chain, 25123d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx) 25133d3b0591SJens Wiklander { 25143d3b0591SJens Wiklander /* Don't initialize any of those variables here, so that the compiler can 25153d3b0591SJens Wiklander * catch potential issues with jumping ahead when restarting */ 251611fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 25173d3b0591SJens Wiklander uint32_t *flags; 25183d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain_item *cur; 25193d3b0591SJens Wiklander mbedtls_x509_crt *child; 25203d3b0591SJens Wiklander mbedtls_x509_crt *parent; 25213d3b0591SJens Wiklander int parent_is_trusted; 25223d3b0591SJens Wiklander int child_is_trusted; 25233d3b0591SJens Wiklander int signature_is_good; 25243d3b0591SJens Wiklander unsigned self_cnt; 252511fa71b9SJerome Forissier mbedtls_x509_crt *cur_trust_ca = NULL; 2526*b0563631STom Van Eyck mbedtls_x509_time now; 2527*b0563631STom Van Eyck 2528*b0563631STom Van Eyck #if defined(MBEDTLS_HAVE_TIME_DATE) 2529*b0563631STom Van Eyck if (mbedtls_x509_time_gmtime(mbedtls_time(NULL), &now) != 0) { 2530*b0563631STom Van Eyck return MBEDTLS_ERR_X509_FATAL_ERROR; 2531*b0563631STom Van Eyck } 2532*b0563631STom Van Eyck #endif 25333d3b0591SJens Wiklander 25343d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 25353d3b0591SJens Wiklander /* resume if we had an operation in progress */ 253632b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->in_progress == x509_crt_rs_find_parent) { 25373d3b0591SJens Wiklander /* restore saved state */ 25383d3b0591SJens Wiklander *ver_chain = rs_ctx->ver_chain; /* struct copy */ 25393d3b0591SJens Wiklander self_cnt = rs_ctx->self_cnt; 25403d3b0591SJens Wiklander 25413d3b0591SJens Wiklander /* restore derived state */ 25423d3b0591SJens Wiklander cur = &ver_chain->items[ver_chain->len - 1]; 25433d3b0591SJens Wiklander child = cur->crt; 25443d3b0591SJens Wiklander flags = &cur->flags; 25453d3b0591SJens Wiklander 25463d3b0591SJens Wiklander goto find_parent; 25473d3b0591SJens Wiklander } 25483d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ 25493d3b0591SJens Wiklander 25503d3b0591SJens Wiklander child = crt; 25513d3b0591SJens Wiklander self_cnt = 0; 25523d3b0591SJens Wiklander parent_is_trusted = 0; 25533d3b0591SJens Wiklander child_is_trusted = 0; 25543d3b0591SJens Wiklander 25553d3b0591SJens Wiklander while (1) { 25563d3b0591SJens Wiklander /* Add certificate to the verification chain */ 25573d3b0591SJens Wiklander cur = &ver_chain->items[ver_chain->len]; 25583d3b0591SJens Wiklander cur->crt = child; 25593d3b0591SJens Wiklander cur->flags = 0; 25603d3b0591SJens Wiklander ver_chain->len++; 25613d3b0591SJens Wiklander flags = &cur->flags; 25623d3b0591SJens Wiklander 2563*b0563631STom Van Eyck #if defined(MBEDTLS_HAVE_TIME_DATE) 25643d3b0591SJens Wiklander /* Check time-validity (all certificates) */ 2565*b0563631STom Van Eyck if (mbedtls_x509_time_cmp(&child->valid_to, &now) < 0) { 2566817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_EXPIRED; 256732b31808SJens Wiklander } 2568817466cbSJens Wiklander 2569*b0563631STom Van Eyck if (mbedtls_x509_time_cmp(&child->valid_from, &now) > 0) { 2570817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_FUTURE; 257132b31808SJens Wiklander } 2572*b0563631STom Van Eyck #endif 2573817466cbSJens Wiklander 25743d3b0591SJens Wiklander /* Stop here for trusted roots (but not for trusted EE certs) */ 257532b31808SJens Wiklander if (child_is_trusted) { 257632b31808SJens Wiklander return 0; 257732b31808SJens Wiklander } 25783d3b0591SJens Wiklander 25793d3b0591SJens Wiklander /* Check signature algorithm: MD & PK algs */ 258032b31808SJens Wiklander if (x509_profile_check_md_alg(profile, child->sig_md) != 0) { 2581817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_MD; 258232b31808SJens Wiklander } 2583817466cbSJens Wiklander 258432b31808SJens Wiklander if (x509_profile_check_pk_alg(profile, child->sig_pk) != 0) { 2585817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_PK; 258632b31808SJens Wiklander } 2587817466cbSJens Wiklander 25883d3b0591SJens Wiklander /* Special case: EE certs that are locally trusted */ 25893d3b0591SJens Wiklander if (ver_chain->len == 1 && 259032b31808SJens Wiklander x509_crt_check_ee_locally_trusted(child, trust_ca) == 0) { 259132b31808SJens Wiklander return 0; 2592817466cbSJens Wiklander } 2593817466cbSJens Wiklander 25943d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 25953d3b0591SJens Wiklander find_parent: 25963d3b0591SJens Wiklander #endif 259711fa71b9SJerome Forissier 259811fa71b9SJerome Forissier /* Obtain list of potential trusted signers from CA callback, 259911fa71b9SJerome Forissier * or use statically provided list. */ 260011fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 260132b31808SJens Wiklander if (f_ca_cb != NULL) { 260211fa71b9SJerome Forissier mbedtls_x509_crt_free(ver_chain->trust_ca_cb_result); 260311fa71b9SJerome Forissier mbedtls_free(ver_chain->trust_ca_cb_result); 260411fa71b9SJerome Forissier ver_chain->trust_ca_cb_result = NULL; 260511fa71b9SJerome Forissier 260611fa71b9SJerome Forissier ret = f_ca_cb(p_ca_cb, child, &ver_chain->trust_ca_cb_result); 260732b31808SJens Wiklander if (ret != 0) { 260832b31808SJens Wiklander return MBEDTLS_ERR_X509_FATAL_ERROR; 260932b31808SJens Wiklander } 261011fa71b9SJerome Forissier 261111fa71b9SJerome Forissier cur_trust_ca = ver_chain->trust_ca_cb_result; 261232b31808SJens Wiklander } else 261311fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 261411fa71b9SJerome Forissier { 261511fa71b9SJerome Forissier ((void) f_ca_cb); 261611fa71b9SJerome Forissier ((void) p_ca_cb); 261711fa71b9SJerome Forissier cur_trust_ca = trust_ca; 261811fa71b9SJerome Forissier } 261911fa71b9SJerome Forissier 26203d3b0591SJens Wiklander /* Look for a parent in trusted CAs or up the chain */ 262111fa71b9SJerome Forissier ret = x509_crt_find_parent(child, cur_trust_ca, &parent, 26223d3b0591SJens Wiklander &parent_is_trusted, &signature_is_good, 2623*b0563631STom Van Eyck ver_chain->len - 1, self_cnt, rs_ctx, 2624*b0563631STom Van Eyck &now); 26253d3b0591SJens Wiklander 26263d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 262732b31808SJens Wiklander if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 26283d3b0591SJens Wiklander /* save state */ 26293d3b0591SJens Wiklander rs_ctx->in_progress = x509_crt_rs_find_parent; 26303d3b0591SJens Wiklander rs_ctx->self_cnt = self_cnt; 26313d3b0591SJens Wiklander rs_ctx->ver_chain = *ver_chain; /* struct copy */ 26323d3b0591SJens Wiklander 263332b31808SJens Wiklander return ret; 26343d3b0591SJens Wiklander } 26353d3b0591SJens Wiklander #else 26363d3b0591SJens Wiklander (void) ret; 26373d3b0591SJens Wiklander #endif 26383d3b0591SJens Wiklander 26393d3b0591SJens Wiklander /* No parent? We're done here */ 264032b31808SJens Wiklander if (parent == NULL) { 26413d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; 264232b31808SJens Wiklander return 0; 26433d3b0591SJens Wiklander } 26443d3b0591SJens Wiklander 26453d3b0591SJens Wiklander /* Count intermediate self-issued (not necessarily self-signed) certs. 26463d3b0591SJens Wiklander * These can occur with some strategies for key rollover, see [SIRO], 26473d3b0591SJens Wiklander * and should be excluded from max_pathlen checks. */ 26483d3b0591SJens Wiklander if (ver_chain->len != 1 && 264932b31808SJens Wiklander x509_name_cmp(&child->issuer, &child->subject) == 0) { 26503d3b0591SJens Wiklander self_cnt++; 26513d3b0591SJens Wiklander } 26523d3b0591SJens Wiklander 26533d3b0591SJens Wiklander /* path_cnt is 0 for the first intermediate CA, 26543d3b0591SJens Wiklander * and if parent is trusted it's not an intermediate CA */ 26553d3b0591SJens Wiklander if (!parent_is_trusted && 265632b31808SJens Wiklander ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA) { 26573d3b0591SJens Wiklander /* return immediately to avoid overflow the chain array */ 265832b31808SJens Wiklander return MBEDTLS_ERR_X509_FATAL_ERROR; 26593d3b0591SJens Wiklander } 26603d3b0591SJens Wiklander 26613d3b0591SJens Wiklander /* signature was checked while searching parent */ 266232b31808SJens Wiklander if (!signature_is_good) { 26633d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; 266432b31808SJens Wiklander } 26653d3b0591SJens Wiklander 26663d3b0591SJens Wiklander /* check size of signing key */ 266732b31808SJens Wiklander if (x509_profile_check_key(profile, &parent->pk) != 0) { 2668817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 266932b31808SJens Wiklander } 2670817466cbSJens Wiklander 2671817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C) 2672817466cbSJens Wiklander /* Check trusted CA's CRL for the given crt */ 2673*b0563631STom Van Eyck *flags |= x509_crt_verifycrl(child, parent, ca_crl, profile, &now); 26743d3b0591SJens Wiklander #else 26753d3b0591SJens Wiklander (void) ca_crl; 2676817466cbSJens Wiklander #endif 2677817466cbSJens Wiklander 26783d3b0591SJens Wiklander /* prepare for next iteration */ 26793d3b0591SJens Wiklander child = parent; 26803d3b0591SJens Wiklander parent = NULL; 26813d3b0591SJens Wiklander child_is_trusted = parent_is_trusted; 26823d3b0591SJens Wiklander signature_is_good = 0; 26833d3b0591SJens Wiklander } 26843d3b0591SJens Wiklander } 26853d3b0591SJens Wiklander 2686*b0563631STom Van Eyck #ifdef _WIN32 2687*b0563631STom Van Eyck #ifdef _MSC_VER 2688*b0563631STom Van Eyck #pragma comment(lib, "ws2_32.lib") 2689*b0563631STom Van Eyck #include <winsock2.h> 2690*b0563631STom Van Eyck #include <ws2tcpip.h> 2691*b0563631STom Van Eyck #elif (defined(__MINGW32__) || defined(__MINGW64__)) && _WIN32_WINNT >= 0x0600 2692*b0563631STom Van Eyck #include <winsock2.h> 2693*b0563631STom Van Eyck #include <ws2tcpip.h> 2694*b0563631STom Van Eyck #else 2695*b0563631STom Van Eyck /* inet_pton() is not supported, fallback to software version */ 2696*b0563631STom Van Eyck #define MBEDTLS_TEST_SW_INET_PTON 2697*b0563631STom Van Eyck #endif 2698*b0563631STom Van Eyck #elif defined(__sun) 2699*b0563631STom Van Eyck /* Solaris requires -lsocket -lnsl for inet_pton() */ 2700*b0563631STom Van Eyck #elif defined(__has_include) 2701*b0563631STom Van Eyck #if __has_include(<sys/socket.h>) 2702*b0563631STom Van Eyck #include <sys/socket.h> 2703*b0563631STom Van Eyck #endif 2704*b0563631STom Van Eyck #if __has_include(<arpa/inet.h>) 2705*b0563631STom Van Eyck #include <arpa/inet.h> 2706*b0563631STom Van Eyck #endif 2707*b0563631STom Van Eyck #endif 2708*b0563631STom Van Eyck 2709*b0563631STom Van Eyck /* Use whether or not AF_INET6 is defined to indicate whether or not to use 2710*b0563631STom Van Eyck * the platform inet_pton() or a local implementation (below). The local 2711*b0563631STom Van Eyck * implementation may be used even in cases where the platform provides 2712*b0563631STom Van Eyck * inet_pton(), e.g. when there are different includes required and/or the 2713*b0563631STom Van Eyck * platform implementation requires dependencies on additional libraries. 2714*b0563631STom Van Eyck * Specifically, Windows requires custom includes and additional link 2715*b0563631STom Van Eyck * dependencies, and Solaris requires additional link dependencies. 2716*b0563631STom Van Eyck * Also, as a coarse heuristic, use the local implementation if the compiler 2717*b0563631STom Van Eyck * does not support __has_include(), or if the definition of AF_INET6 is not 2718*b0563631STom Van Eyck * provided by headers included (or not) via __has_include() above. 2719*b0563631STom Van Eyck * MBEDTLS_TEST_SW_INET_PTON is a bypass define to force testing of this code //no-check-names 2720*b0563631STom Van Eyck * despite having a platform that has inet_pton. */ 2721*b0563631STom Van Eyck #if !defined(AF_INET6) || defined(MBEDTLS_TEST_SW_INET_PTON) //no-check-names 2722*b0563631STom Van Eyck /* Definition located further below to possibly reduce compiler inlining */ 2723*b0563631STom Van Eyck static int x509_inet_pton_ipv4(const char *src, void *dst); 2724*b0563631STom Van Eyck 2725*b0563631STom Van Eyck #define li_cton(c, n) \ 2726*b0563631STom Van Eyck (((n) = (c) - '0') <= 9 || (((n) = ((c)&0xdf) - 'A') <= 5 ? ((n) += 10) : 0)) 2727*b0563631STom Van Eyck 2728*b0563631STom Van Eyck static int x509_inet_pton_ipv6(const char *src, void *dst) 2729*b0563631STom Van Eyck { 2730*b0563631STom Van Eyck const unsigned char *p = (const unsigned char *) src; 2731*b0563631STom Van Eyck int nonzero_groups = 0, num_digits, zero_group_start = -1; 2732*b0563631STom Van Eyck uint16_t addr[8]; 2733*b0563631STom Van Eyck do { 2734*b0563631STom Van Eyck /* note: allows excess leading 0's, e.g. 1:0002:3:... */ 2735*b0563631STom Van Eyck uint16_t group = num_digits = 0; 2736*b0563631STom Van Eyck for (uint8_t digit; num_digits < 4; num_digits++) { 2737*b0563631STom Van Eyck if (li_cton(*p, digit) == 0) { 2738*b0563631STom Van Eyck break; 2739*b0563631STom Van Eyck } 2740*b0563631STom Van Eyck group = (group << 4) | digit; 2741*b0563631STom Van Eyck p++; 2742*b0563631STom Van Eyck } 2743*b0563631STom Van Eyck if (num_digits != 0) { 2744*b0563631STom Van Eyck MBEDTLS_PUT_UINT16_BE(group, addr, nonzero_groups); 2745*b0563631STom Van Eyck nonzero_groups++; 2746*b0563631STom Van Eyck if (*p == '\0') { 2747*b0563631STom Van Eyck break; 2748*b0563631STom Van Eyck } else if (*p == '.') { 2749*b0563631STom Van Eyck /* Don't accept IPv4 too early or late */ 2750*b0563631STom Van Eyck if ((nonzero_groups == 0 && zero_group_start == -1) || 2751*b0563631STom Van Eyck nonzero_groups >= 7) { 2752*b0563631STom Van Eyck break; 2753*b0563631STom Van Eyck } 2754*b0563631STom Van Eyck 2755*b0563631STom Van Eyck /* Walk back to prior ':', then parse as IPv4-mapped */ 2756*b0563631STom Van Eyck int steps = 4; 2757*b0563631STom Van Eyck do { 2758*b0563631STom Van Eyck p--; 2759*b0563631STom Van Eyck steps--; 2760*b0563631STom Van Eyck } while (*p != ':' && steps > 0); 2761*b0563631STom Van Eyck 2762*b0563631STom Van Eyck if (*p != ':') { 2763*b0563631STom Van Eyck break; 2764*b0563631STom Van Eyck } 2765*b0563631STom Van Eyck p++; 2766*b0563631STom Van Eyck nonzero_groups--; 2767*b0563631STom Van Eyck if (x509_inet_pton_ipv4((const char *) p, 2768*b0563631STom Van Eyck addr + nonzero_groups) != 0) { 2769*b0563631STom Van Eyck break; 2770*b0563631STom Van Eyck } 2771*b0563631STom Van Eyck 2772*b0563631STom Van Eyck nonzero_groups += 2; 2773*b0563631STom Van Eyck p = (const unsigned char *) ""; 2774*b0563631STom Van Eyck break; 2775*b0563631STom Van Eyck } else if (*p != ':') { 2776*b0563631STom Van Eyck return -1; 2777*b0563631STom Van Eyck } 2778*b0563631STom Van Eyck } else { 2779*b0563631STom Van Eyck /* Don't accept a second zero group or an invalid delimiter */ 2780*b0563631STom Van Eyck if (zero_group_start != -1 || *p != ':') { 2781*b0563631STom Van Eyck return -1; 2782*b0563631STom Van Eyck } 2783*b0563631STom Van Eyck zero_group_start = nonzero_groups; 2784*b0563631STom Van Eyck 2785*b0563631STom Van Eyck /* Accept a zero group at start, but it has to be a double colon */ 2786*b0563631STom Van Eyck if (zero_group_start == 0 && *++p != ':') { 2787*b0563631STom Van Eyck return -1; 2788*b0563631STom Van Eyck } 2789*b0563631STom Van Eyck 2790*b0563631STom Van Eyck if (p[1] == '\0') { 2791*b0563631STom Van Eyck ++p; 2792*b0563631STom Van Eyck break; 2793*b0563631STom Van Eyck } 2794*b0563631STom Van Eyck } 2795*b0563631STom Van Eyck ++p; 2796*b0563631STom Van Eyck } while (nonzero_groups < 8); 2797*b0563631STom Van Eyck 2798*b0563631STom Van Eyck if (*p != '\0') { 2799*b0563631STom Van Eyck return -1; 2800*b0563631STom Van Eyck } 2801*b0563631STom Van Eyck 2802*b0563631STom Van Eyck if (zero_group_start != -1) { 2803*b0563631STom Van Eyck if (nonzero_groups > 6) { 2804*b0563631STom Van Eyck return -1; 2805*b0563631STom Van Eyck } 2806*b0563631STom Van Eyck int zero_groups = 8 - nonzero_groups; 2807*b0563631STom Van Eyck int groups_after_zero = nonzero_groups - zero_group_start; 2808*b0563631STom Van Eyck 2809*b0563631STom Van Eyck /* Move the non-zero part to after the zeroes */ 2810*b0563631STom Van Eyck if (groups_after_zero) { 2811*b0563631STom Van Eyck memmove(addr + zero_group_start + zero_groups, 2812*b0563631STom Van Eyck addr + zero_group_start, 2813*b0563631STom Van Eyck groups_after_zero * sizeof(*addr)); 2814*b0563631STom Van Eyck } 2815*b0563631STom Van Eyck memset(addr + zero_group_start, 0, zero_groups * sizeof(*addr)); 2816*b0563631STom Van Eyck } else { 2817*b0563631STom Van Eyck if (nonzero_groups != 8) { 2818*b0563631STom Van Eyck return -1; 2819*b0563631STom Van Eyck } 2820*b0563631STom Van Eyck } 2821*b0563631STom Van Eyck memcpy(dst, addr, sizeof(addr)); 2822*b0563631STom Van Eyck return 0; 2823*b0563631STom Van Eyck } 2824*b0563631STom Van Eyck 2825*b0563631STom Van Eyck static int x509_inet_pton_ipv4(const char *src, void *dst) 2826*b0563631STom Van Eyck { 2827*b0563631STom Van Eyck const unsigned char *p = (const unsigned char *) src; 2828*b0563631STom Van Eyck uint8_t *res = (uint8_t *) dst; 2829*b0563631STom Van Eyck uint8_t digit, num_digits = 0; 2830*b0563631STom Van Eyck uint8_t num_octets = 0; 2831*b0563631STom Van Eyck uint16_t octet; 2832*b0563631STom Van Eyck 2833*b0563631STom Van Eyck do { 2834*b0563631STom Van Eyck octet = num_digits = 0; 2835*b0563631STom Van Eyck do { 2836*b0563631STom Van Eyck digit = *p - '0'; 2837*b0563631STom Van Eyck if (digit > 9) { 2838*b0563631STom Van Eyck break; 2839*b0563631STom Van Eyck } 2840*b0563631STom Van Eyck 2841*b0563631STom Van Eyck /* Don't allow leading zeroes. These might mean octal format, 2842*b0563631STom Van Eyck * which this implementation does not support. */ 2843*b0563631STom Van Eyck if (octet == 0 && num_digits > 0) { 2844*b0563631STom Van Eyck return -1; 2845*b0563631STom Van Eyck } 2846*b0563631STom Van Eyck 2847*b0563631STom Van Eyck octet = octet * 10 + digit; 2848*b0563631STom Van Eyck num_digits++; 2849*b0563631STom Van Eyck p++; 2850*b0563631STom Van Eyck } while (num_digits < 3); 2851*b0563631STom Van Eyck 2852*b0563631STom Van Eyck if (octet >= 256 || num_digits > 3 || num_digits == 0) { 2853*b0563631STom Van Eyck return -1; 2854*b0563631STom Van Eyck } 2855*b0563631STom Van Eyck *res++ = (uint8_t) octet; 2856*b0563631STom Van Eyck num_octets++; 2857*b0563631STom Van Eyck } while (num_octets < 4 && *p++ == '.'); 2858*b0563631STom Van Eyck return num_octets == 4 && *p == '\0' ? 0 : -1; 2859*b0563631STom Van Eyck } 2860*b0563631STom Van Eyck 2861*b0563631STom Van Eyck #else 2862*b0563631STom Van Eyck 2863*b0563631STom Van Eyck static int x509_inet_pton_ipv6(const char *src, void *dst) 2864*b0563631STom Van Eyck { 2865*b0563631STom Van Eyck return inet_pton(AF_INET6, src, dst) == 1 ? 0 : -1; 2866*b0563631STom Van Eyck } 2867*b0563631STom Van Eyck 2868*b0563631STom Van Eyck static int x509_inet_pton_ipv4(const char *src, void *dst) 2869*b0563631STom Van Eyck { 2870*b0563631STom Van Eyck return inet_pton(AF_INET, src, dst) == 1 ? 0 : -1; 2871*b0563631STom Van Eyck } 2872*b0563631STom Van Eyck 2873*b0563631STom Van Eyck #endif /* !AF_INET6 || MBEDTLS_TEST_SW_INET_PTON */ //no-check-names 2874*b0563631STom Van Eyck 2875*b0563631STom Van Eyck size_t mbedtls_x509_crt_parse_cn_inet_pton(const char *cn, void *dst) 2876*b0563631STom Van Eyck { 2877*b0563631STom Van Eyck return strchr(cn, ':') == NULL 2878*b0563631STom Van Eyck ? x509_inet_pton_ipv4(cn, dst) == 0 ? 4 : 0 2879*b0563631STom Van Eyck : x509_inet_pton_ipv6(cn, dst) == 0 ? 16 : 0; 2880*b0563631STom Van Eyck } 2881*b0563631STom Van Eyck 28823d3b0591SJens Wiklander /* 28833d3b0591SJens Wiklander * Check for CN match 28843d3b0591SJens Wiklander */ 28853d3b0591SJens Wiklander static int x509_crt_check_cn(const mbedtls_x509_buf *name, 28863d3b0591SJens Wiklander const char *cn, size_t cn_len) 2887817466cbSJens Wiklander { 28883d3b0591SJens Wiklander /* try exact match */ 28893d3b0591SJens Wiklander if (name->len == cn_len && 289032b31808SJens Wiklander x509_memcasecmp(cn, name->p, cn_len) == 0) { 289132b31808SJens Wiklander return 0; 28923d3b0591SJens Wiklander } 28933d3b0591SJens Wiklander 28943d3b0591SJens Wiklander /* try wildcard match */ 289532b31808SJens Wiklander if (x509_check_wildcard(cn, name) == 0) { 289632b31808SJens Wiklander return 0; 28973d3b0591SJens Wiklander } 28983d3b0591SJens Wiklander 289932b31808SJens Wiklander return -1; 29003d3b0591SJens Wiklander } 29013d3b0591SJens Wiklander 2902*b0563631STom Van Eyck static int x509_crt_check_san_ip(const mbedtls_x509_sequence *san, 2903*b0563631STom Van Eyck const char *cn, size_t cn_len) 2904*b0563631STom Van Eyck { 2905*b0563631STom Van Eyck uint32_t ip[4]; 2906*b0563631STom Van Eyck cn_len = mbedtls_x509_crt_parse_cn_inet_pton(cn, ip); 2907*b0563631STom Van Eyck if (cn_len == 0) { 2908*b0563631STom Van Eyck return -1; 2909*b0563631STom Van Eyck } 2910*b0563631STom Van Eyck 2911*b0563631STom Van Eyck for (const mbedtls_x509_sequence *cur = san; cur != NULL; cur = cur->next) { 2912*b0563631STom Van Eyck const unsigned char san_type = (unsigned char) cur->buf.tag & 2913*b0563631STom Van Eyck MBEDTLS_ASN1_TAG_VALUE_MASK; 2914*b0563631STom Van Eyck if (san_type == MBEDTLS_X509_SAN_IP_ADDRESS && 2915*b0563631STom Van Eyck cur->buf.len == cn_len && memcmp(cur->buf.p, ip, cn_len) == 0) { 2916*b0563631STom Van Eyck return 0; 2917*b0563631STom Van Eyck } 2918*b0563631STom Van Eyck } 2919*b0563631STom Van Eyck 2920*b0563631STom Van Eyck return -1; 2921*b0563631STom Van Eyck } 2922*b0563631STom Van Eyck 2923*b0563631STom Van Eyck static int x509_crt_check_san_uri(const mbedtls_x509_sequence *san, 2924*b0563631STom Van Eyck const char *cn, size_t cn_len) 2925*b0563631STom Van Eyck { 2926*b0563631STom Van Eyck for (const mbedtls_x509_sequence *cur = san; cur != NULL; cur = cur->next) { 2927*b0563631STom Van Eyck const unsigned char san_type = (unsigned char) cur->buf.tag & 2928*b0563631STom Van Eyck MBEDTLS_ASN1_TAG_VALUE_MASK; 2929*b0563631STom Van Eyck if (san_type == MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER && 2930*b0563631STom Van Eyck cur->buf.len == cn_len && memcmp(cur->buf.p, cn, cn_len) == 0) { 2931*b0563631STom Van Eyck return 0; 2932*b0563631STom Van Eyck } 2933*b0563631STom Van Eyck } 2934*b0563631STom Van Eyck 2935*b0563631STom Van Eyck return -1; 2936*b0563631STom Van Eyck } 2937*b0563631STom Van Eyck 29383d3b0591SJens Wiklander /* 29397901324dSJerome Forissier * Check for SAN match, see RFC 5280 Section 4.2.1.6 29407901324dSJerome Forissier */ 2941*b0563631STom Van Eyck static int x509_crt_check_san(const mbedtls_x509_sequence *san, 29427901324dSJerome Forissier const char *cn, size_t cn_len) 29437901324dSJerome Forissier { 2944*b0563631STom Van Eyck int san_ip = 0; 2945*b0563631STom Van Eyck int san_uri = 0; 2946*b0563631STom Van Eyck /* Prioritize DNS name over other subtypes due to popularity */ 2947*b0563631STom Van Eyck for (const mbedtls_x509_sequence *cur = san; cur != NULL; cur = cur->next) { 2948*b0563631STom Van Eyck switch ((unsigned char) cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) { 2949*b0563631STom Van Eyck case MBEDTLS_X509_SAN_DNS_NAME: 2950*b0563631STom Van Eyck if (x509_crt_check_cn(&cur->buf, cn, cn_len) == 0) { 2951*b0563631STom Van Eyck return 0; 2952*b0563631STom Van Eyck } 2953*b0563631STom Van Eyck break; 2954*b0563631STom Van Eyck case MBEDTLS_X509_SAN_IP_ADDRESS: 2955*b0563631STom Van Eyck san_ip = 1; 2956*b0563631STom Van Eyck break; 2957*b0563631STom Van Eyck case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER: 2958*b0563631STom Van Eyck san_uri = 1; 2959*b0563631STom Van Eyck break; 2960*b0563631STom Van Eyck /* (We may handle other types here later.) */ 2961*b0563631STom Van Eyck default: /* Unrecognized type */ 2962*b0563631STom Van Eyck break; 2963*b0563631STom Van Eyck } 2964*b0563631STom Van Eyck } 2965*b0563631STom Van Eyck if (san_ip) { 2966*b0563631STom Van Eyck if (x509_crt_check_san_ip(san, cn, cn_len) == 0) { 2967*b0563631STom Van Eyck return 0; 2968*b0563631STom Van Eyck } 2969*b0563631STom Van Eyck } 2970*b0563631STom Van Eyck if (san_uri) { 2971*b0563631STom Van Eyck if (x509_crt_check_san_uri(san, cn, cn_len) == 0) { 2972*b0563631STom Van Eyck return 0; 2973*b0563631STom Van Eyck } 297432b31808SJens Wiklander } 29757901324dSJerome Forissier 297632b31808SJens Wiklander return -1; 29777901324dSJerome Forissier } 29787901324dSJerome Forissier 29797901324dSJerome Forissier /* 29803d3b0591SJens Wiklander * Verify the requested CN - only call this if cn is not NULL! 29813d3b0591SJens Wiklander */ 29823d3b0591SJens Wiklander static void x509_crt_verify_name(const mbedtls_x509_crt *crt, 29833d3b0591SJens Wiklander const char *cn, 29843d3b0591SJens Wiklander uint32_t *flags) 29853d3b0591SJens Wiklander { 29863d3b0591SJens Wiklander const mbedtls_x509_name *name; 29873d3b0591SJens Wiklander size_t cn_len = strlen(cn); 29883d3b0591SJens Wiklander 298932b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) { 2990*b0563631STom Van Eyck if (x509_crt_check_san(&crt->subject_alt_names, cn, cn_len) == 0) { 2991*b0563631STom Van Eyck return; 2992817466cbSJens Wiklander } 299332b31808SJens Wiklander } else { 299432b31808SJens Wiklander for (name = &crt->subject; name != NULL; name = name->next) { 29953d3b0591SJens Wiklander if (MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid) == 0 && 299632b31808SJens Wiklander x509_crt_check_cn(&name->val, cn, cn_len) == 0) { 2997*b0563631STom Van Eyck return; 2998817466cbSJens Wiklander } 2999817466cbSJens Wiklander } 30003d3b0591SJens Wiklander 3001*b0563631STom Van Eyck } 3002*b0563631STom Van Eyck 30033d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; 3004817466cbSJens Wiklander } 3005817466cbSJens Wiklander 30063d3b0591SJens Wiklander /* 30073d3b0591SJens Wiklander * Merge the flags for all certs in the chain, after calling callback 30083d3b0591SJens Wiklander */ 30093d3b0591SJens Wiklander static int x509_crt_merge_flags_with_cb( 30103d3b0591SJens Wiklander uint32_t *flags, 30113d3b0591SJens Wiklander const mbedtls_x509_crt_verify_chain *ver_chain, 30123d3b0591SJens Wiklander int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 30133d3b0591SJens Wiklander void *p_vrfy) 30143d3b0591SJens Wiklander { 301511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 30163d3b0591SJens Wiklander unsigned i; 30173d3b0591SJens Wiklander uint32_t cur_flags; 30183d3b0591SJens Wiklander const mbedtls_x509_crt_verify_chain_item *cur; 30193d3b0591SJens Wiklander 302032b31808SJens Wiklander for (i = ver_chain->len; i != 0; --i) { 30213d3b0591SJens Wiklander cur = &ver_chain->items[i-1]; 30223d3b0591SJens Wiklander cur_flags = cur->flags; 30233d3b0591SJens Wiklander 302432b31808SJens Wiklander if (NULL != f_vrfy) { 302532b31808SJens Wiklander if ((ret = f_vrfy(p_vrfy, cur->crt, (int) i-1, &cur_flags)) != 0) { 302632b31808SJens Wiklander return ret; 302732b31808SJens Wiklander } 302832b31808SJens Wiklander } 3029817466cbSJens Wiklander 30303d3b0591SJens Wiklander *flags |= cur_flags; 30313d3b0591SJens Wiklander } 3032817466cbSJens Wiklander 303332b31808SJens Wiklander return 0; 3034817466cbSJens Wiklander } 3035817466cbSJens Wiklander 3036817466cbSJens Wiklander /* 30373d3b0591SJens Wiklander * Verify the certificate validity, with profile, restartable version 30383d3b0591SJens Wiklander * 30393d3b0591SJens Wiklander * This function: 30403d3b0591SJens Wiklander * - checks the requested CN (if any) 30413d3b0591SJens Wiklander * - checks the type and size of the EE cert's key, 30423d3b0591SJens Wiklander * as that isn't done as part of chain building/verification currently 30433d3b0591SJens Wiklander * - builds and verifies the chain 30443d3b0591SJens Wiklander * - then calls the callback and merges the flags 304511fa71b9SJerome Forissier * 304611fa71b9SJerome Forissier * The parameters pairs `trust_ca`, `ca_crl` and `f_ca_cb`, `p_ca_cb` 304711fa71b9SJerome Forissier * are mutually exclusive: If `f_ca_cb != NULL`, it will be used by the 304811fa71b9SJerome Forissier * verification routine to search for trusted signers, and CRLs will 304911fa71b9SJerome Forissier * be disabled. Otherwise, `trust_ca` will be used as the static list 305011fa71b9SJerome Forissier * of trusted signers, and `ca_crl` will be use as the static list 305111fa71b9SJerome Forissier * of CRLs. 30523d3b0591SJens Wiklander */ 305311fa71b9SJerome Forissier static int x509_crt_verify_restartable_ca_cb(mbedtls_x509_crt *crt, 30543d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 30553d3b0591SJens Wiklander mbedtls_x509_crl *ca_crl, 305611fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 305711fa71b9SJerome Forissier void *p_ca_cb, 30583d3b0591SJens Wiklander const mbedtls_x509_crt_profile *profile, 30593d3b0591SJens Wiklander const char *cn, uint32_t *flags, 306032b31808SJens Wiklander int (*f_vrfy)(void *, 306132b31808SJens Wiklander mbedtls_x509_crt *, 306232b31808SJens Wiklander int, 306332b31808SJens Wiklander uint32_t *), 30643d3b0591SJens Wiklander void *p_vrfy, 30653d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx) 30663d3b0591SJens Wiklander { 306711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3068817466cbSJens Wiklander mbedtls_pk_type_t pk_type; 30693d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain ver_chain; 30703d3b0591SJens Wiklander uint32_t ee_flags; 3071817466cbSJens Wiklander 3072817466cbSJens Wiklander *flags = 0; 30733d3b0591SJens Wiklander ee_flags = 0; 30743d3b0591SJens Wiklander x509_crt_verify_chain_reset(&ver_chain); 3075817466cbSJens Wiklander 307632b31808SJens Wiklander if (profile == NULL) { 3077817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; 3078817466cbSJens Wiklander goto exit; 3079817466cbSJens Wiklander } 3080817466cbSJens Wiklander 30813d3b0591SJens Wiklander /* check name if requested */ 308232b31808SJens Wiklander if (cn != NULL) { 30833d3b0591SJens Wiklander x509_crt_verify_name(crt, cn, &ee_flags); 308432b31808SJens Wiklander } 3085817466cbSJens Wiklander 3086817466cbSJens Wiklander /* Check the type and size of the key */ 3087817466cbSJens Wiklander pk_type = mbedtls_pk_get_type(&crt->pk); 3088817466cbSJens Wiklander 308932b31808SJens Wiklander if (x509_profile_check_pk_alg(profile, pk_type) != 0) { 30903d3b0591SJens Wiklander ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK; 309132b31808SJens Wiklander } 3092817466cbSJens Wiklander 309332b31808SJens Wiklander if (x509_profile_check_key(profile, &crt->pk) != 0) { 30943d3b0591SJens Wiklander ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 309532b31808SJens Wiklander } 3096817466cbSJens Wiklander 30973d3b0591SJens Wiklander /* Check the chain */ 309811fa71b9SJerome Forissier ret = x509_crt_verify_chain(crt, trust_ca, ca_crl, 309911fa71b9SJerome Forissier f_ca_cb, p_ca_cb, profile, 31003d3b0591SJens Wiklander &ver_chain, rs_ctx); 3101817466cbSJens Wiklander 310232b31808SJens Wiklander if (ret != 0) { 3103817466cbSJens Wiklander goto exit; 310432b31808SJens Wiklander } 3105817466cbSJens Wiklander 31063d3b0591SJens Wiklander /* Merge end-entity flags */ 31073d3b0591SJens Wiklander ver_chain.items[0].flags |= ee_flags; 31083d3b0591SJens Wiklander 31093d3b0591SJens Wiklander /* Build final flags, calling callback on the way if any */ 31103d3b0591SJens Wiklander ret = x509_crt_merge_flags_with_cb(flags, &ver_chain, f_vrfy, p_vrfy); 3111817466cbSJens Wiklander 3112817466cbSJens Wiklander exit: 311311fa71b9SJerome Forissier 311411fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 311511fa71b9SJerome Forissier mbedtls_x509_crt_free(ver_chain.trust_ca_cb_result); 311611fa71b9SJerome Forissier mbedtls_free(ver_chain.trust_ca_cb_result); 311711fa71b9SJerome Forissier ver_chain.trust_ca_cb_result = NULL; 311811fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 311911fa71b9SJerome Forissier 31203d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 312132b31808SJens Wiklander if (rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS) { 31223d3b0591SJens Wiklander mbedtls_x509_crt_restart_free(rs_ctx); 312332b31808SJens Wiklander } 31243d3b0591SJens Wiklander #endif 31253d3b0591SJens Wiklander 3126817466cbSJens Wiklander /* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by 3127817466cbSJens Wiklander * the SSL module for authmode optional, but non-zero return from the 3128817466cbSJens Wiklander * callback means a fatal error so it shouldn't be ignored */ 312932b31808SJens Wiklander if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { 3130817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FATAL_ERROR; 3131817466cbSJens Wiklander } 3132817466cbSJens Wiklander 313332b31808SJens Wiklander if (ret != 0) { 313432b31808SJens Wiklander *flags = (uint32_t) -1; 313532b31808SJens Wiklander return ret; 313632b31808SJens Wiklander } 3137817466cbSJens Wiklander 313832b31808SJens Wiklander if (*flags != 0) { 313932b31808SJens Wiklander return MBEDTLS_ERR_X509_CERT_VERIFY_FAILED; 314032b31808SJens Wiklander } 314132b31808SJens Wiklander 314232b31808SJens Wiklander return 0; 3143817466cbSJens Wiklander } 3144817466cbSJens Wiklander 314511fa71b9SJerome Forissier 314611fa71b9SJerome Forissier /* 314711fa71b9SJerome Forissier * Verify the certificate validity (default profile, not restartable) 314811fa71b9SJerome Forissier */ 314911fa71b9SJerome Forissier int mbedtls_x509_crt_verify(mbedtls_x509_crt *crt, 315011fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 315111fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 315211fa71b9SJerome Forissier const char *cn, uint32_t *flags, 315311fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 315411fa71b9SJerome Forissier void *p_vrfy) 315511fa71b9SJerome Forissier { 315632b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl, 315711fa71b9SJerome Forissier NULL, NULL, 315811fa71b9SJerome Forissier &mbedtls_x509_crt_profile_default, 315911fa71b9SJerome Forissier cn, flags, 316032b31808SJens Wiklander f_vrfy, p_vrfy, NULL); 316111fa71b9SJerome Forissier } 316211fa71b9SJerome Forissier 316311fa71b9SJerome Forissier /* 316411fa71b9SJerome Forissier * Verify the certificate validity (user-chosen profile, not restartable) 316511fa71b9SJerome Forissier */ 316611fa71b9SJerome Forissier int mbedtls_x509_crt_verify_with_profile(mbedtls_x509_crt *crt, 316711fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 316811fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 316911fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 317011fa71b9SJerome Forissier const char *cn, uint32_t *flags, 317111fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 317211fa71b9SJerome Forissier void *p_vrfy) 317311fa71b9SJerome Forissier { 317432b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl, 317511fa71b9SJerome Forissier NULL, NULL, 317611fa71b9SJerome Forissier profile, cn, flags, 317732b31808SJens Wiklander f_vrfy, p_vrfy, NULL); 317811fa71b9SJerome Forissier } 317911fa71b9SJerome Forissier 318011fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 318111fa71b9SJerome Forissier /* 318211fa71b9SJerome Forissier * Verify the certificate validity (user-chosen profile, CA callback, 318311fa71b9SJerome Forissier * not restartable). 318411fa71b9SJerome Forissier */ 318511fa71b9SJerome Forissier int mbedtls_x509_crt_verify_with_ca_cb(mbedtls_x509_crt *crt, 318611fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 318711fa71b9SJerome Forissier void *p_ca_cb, 318811fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 318911fa71b9SJerome Forissier const char *cn, uint32_t *flags, 319011fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 319111fa71b9SJerome Forissier void *p_vrfy) 319211fa71b9SJerome Forissier { 319332b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, NULL, NULL, 319411fa71b9SJerome Forissier f_ca_cb, p_ca_cb, 319511fa71b9SJerome Forissier profile, cn, flags, 319632b31808SJens Wiklander f_vrfy, p_vrfy, NULL); 319711fa71b9SJerome Forissier } 319811fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 319911fa71b9SJerome Forissier 320011fa71b9SJerome Forissier int mbedtls_x509_crt_verify_restartable(mbedtls_x509_crt *crt, 320111fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 320211fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 320311fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 320411fa71b9SJerome Forissier const char *cn, uint32_t *flags, 320511fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 320611fa71b9SJerome Forissier void *p_vrfy, 320711fa71b9SJerome Forissier mbedtls_x509_crt_restart_ctx *rs_ctx) 320811fa71b9SJerome Forissier { 320932b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl, 321011fa71b9SJerome Forissier NULL, NULL, 321111fa71b9SJerome Forissier profile, cn, flags, 321232b31808SJens Wiklander f_vrfy, p_vrfy, rs_ctx); 321311fa71b9SJerome Forissier } 321411fa71b9SJerome Forissier 321511fa71b9SJerome Forissier 3216817466cbSJens Wiklander /* 3217817466cbSJens Wiklander * Initialize a certificate chain 3218817466cbSJens Wiklander */ 3219817466cbSJens Wiklander void mbedtls_x509_crt_init(mbedtls_x509_crt *crt) 3220817466cbSJens Wiklander { 3221817466cbSJens Wiklander memset(crt, 0, sizeof(mbedtls_x509_crt)); 3222817466cbSJens Wiklander } 3223817466cbSJens Wiklander 3224817466cbSJens Wiklander /* 3225817466cbSJens Wiklander * Unallocate all certificate data 3226817466cbSJens Wiklander */ 3227817466cbSJens Wiklander void mbedtls_x509_crt_free(mbedtls_x509_crt *crt) 3228817466cbSJens Wiklander { 3229817466cbSJens Wiklander mbedtls_x509_crt *cert_cur = crt; 3230817466cbSJens Wiklander mbedtls_x509_crt *cert_prv; 3231817466cbSJens Wiklander 323232b31808SJens Wiklander while (cert_cur != NULL) { 3233817466cbSJens Wiklander mbedtls_pk_free(&cert_cur->pk); 3234817466cbSJens Wiklander 3235817466cbSJens Wiklander #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) 3236817466cbSJens Wiklander mbedtls_free(cert_cur->sig_opts); 3237817466cbSJens Wiklander #endif 3238817466cbSJens Wiklander 323932b31808SJens Wiklander mbedtls_asn1_free_named_data_list_shallow(cert_cur->issuer.next); 324032b31808SJens Wiklander mbedtls_asn1_free_named_data_list_shallow(cert_cur->subject.next); 324132b31808SJens Wiklander mbedtls_asn1_sequence_free(cert_cur->ext_key_usage.next); 324232b31808SJens Wiklander mbedtls_asn1_sequence_free(cert_cur->subject_alt_names.next); 324332b31808SJens Wiklander mbedtls_asn1_sequence_free(cert_cur->certificate_policies.next); 3244*b0563631STom Van Eyck mbedtls_asn1_sequence_free(cert_cur->authority_key_id.authorityCertIssuer.next); 3245817466cbSJens Wiklander 324632b31808SJens Wiklander if (cert_cur->raw.p != NULL && cert_cur->own_buffer) { 3247*b0563631STom Van Eyck mbedtls_zeroize_and_free(cert_cur->raw.p, cert_cur->raw.len); 3248817466cbSJens Wiklander } 3249817466cbSJens Wiklander 3250817466cbSJens Wiklander cert_prv = cert_cur; 3251817466cbSJens Wiklander cert_cur = cert_cur->next; 3252817466cbSJens Wiklander 32533d3b0591SJens Wiklander mbedtls_platform_zeroize(cert_prv, sizeof(mbedtls_x509_crt)); 325432b31808SJens Wiklander if (cert_prv != crt) { 3255817466cbSJens Wiklander mbedtls_free(cert_prv); 3256817466cbSJens Wiklander } 325732b31808SJens Wiklander } 3258817466cbSJens Wiklander } 3259817466cbSJens Wiklander 32603d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 32613d3b0591SJens Wiklander /* 32623d3b0591SJens Wiklander * Initialize a restart context 32633d3b0591SJens Wiklander */ 32643d3b0591SJens Wiklander void mbedtls_x509_crt_restart_init(mbedtls_x509_crt_restart_ctx *ctx) 32653d3b0591SJens Wiklander { 32663d3b0591SJens Wiklander mbedtls_pk_restart_init(&ctx->pk); 32673d3b0591SJens Wiklander 32683d3b0591SJens Wiklander ctx->parent = NULL; 32693d3b0591SJens Wiklander ctx->fallback_parent = NULL; 32703d3b0591SJens Wiklander ctx->fallback_signature_is_good = 0; 32713d3b0591SJens Wiklander 32723d3b0591SJens Wiklander ctx->parent_is_trusted = -1; 32733d3b0591SJens Wiklander 32743d3b0591SJens Wiklander ctx->in_progress = x509_crt_rs_none; 32753d3b0591SJens Wiklander ctx->self_cnt = 0; 32763d3b0591SJens Wiklander x509_crt_verify_chain_reset(&ctx->ver_chain); 32773d3b0591SJens Wiklander } 32783d3b0591SJens Wiklander 32793d3b0591SJens Wiklander /* 32803d3b0591SJens Wiklander * Free the components of a restart context 32813d3b0591SJens Wiklander */ 32823d3b0591SJens Wiklander void mbedtls_x509_crt_restart_free(mbedtls_x509_crt_restart_ctx *ctx) 32833d3b0591SJens Wiklander { 328432b31808SJens Wiklander if (ctx == NULL) { 32853d3b0591SJens Wiklander return; 328632b31808SJens Wiklander } 32873d3b0591SJens Wiklander 32883d3b0591SJens Wiklander mbedtls_pk_restart_free(&ctx->pk); 32893d3b0591SJens Wiklander mbedtls_x509_crt_restart_init(ctx); 32903d3b0591SJens Wiklander } 32913d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ 32923d3b0591SJens Wiklander 3293*b0563631STom Van Eyck int mbedtls_x509_crt_get_ca_istrue(const mbedtls_x509_crt *crt) 3294*b0563631STom Van Eyck { 3295*b0563631STom Van Eyck if ((crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS) != 0) { 3296*b0563631STom Van Eyck return crt->MBEDTLS_PRIVATE(ca_istrue); 3297*b0563631STom Van Eyck } 3298*b0563631STom Van Eyck return MBEDTLS_ERR_X509_INVALID_EXTENSIONS; 3299*b0563631STom Van Eyck } 3300*b0563631STom Van Eyck 3301817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRT_PARSE_C */ 3302