1817466cbSJens Wiklander /*
2817466cbSJens Wiklander * X.509 certificate parsing and verification
3817466cbSJens Wiklander *
47901324dSJerome Forissier * Copyright The Mbed TLS Contributors
5b0563631STom 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"
25b0563631STom 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"
38b0563631STom Van Eyck #include "psa_util_internal.h"
3911fa71b9SJerome Forissier #include "mbedtls/psa_util.h"
4032b31808SJens Wiklander #endif /* MBEDTLS_USE_PSA_CRYPTO */
41b0563631STom 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*cb034002SJerome Forissier #ifndef WIN32_LEAN_AND_MEAN
52b0563631STom Van Eyck #define WIN32_LEAN_AND_MEAN
53*cb034002SJerome Forissier #endif
54817466cbSJens Wiklander #include <windows.h>
55817466cbSJens Wiklander #else
56817466cbSJens Wiklander #include <time.h>
57817466cbSJens Wiklander #endif
58039e02dfSJerome Forissier #endif
59817466cbSJens Wiklander
60817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
61817466cbSJens Wiklander #include <stdio.h>
62817466cbSJens Wiklander #if !defined(_WIN32) || defined(EFIX64) || defined(EFI32)
63817466cbSJens Wiklander #include <sys/types.h>
64817466cbSJens Wiklander #include <sys/stat.h>
6532b31808SJens Wiklander #if defined(__MBED__)
6632b31808SJens Wiklander #include <platform/mbed_retarget.h>
6732b31808SJens Wiklander #else
68817466cbSJens Wiklander #include <dirent.h>
6932b31808SJens Wiklander #endif /* __MBED__ */
7032b31808SJens Wiklander #include <errno.h>
71817466cbSJens Wiklander #endif /* !_WIN32 || EFIX64 || EFI32 */
72817466cbSJens Wiklander #endif
73817466cbSJens Wiklander
743d3b0591SJens Wiklander /*
753d3b0591SJens Wiklander * Item in a verification chain: cert and flags for it
763d3b0591SJens Wiklander */
773d3b0591SJens Wiklander typedef struct {
783d3b0591SJens Wiklander mbedtls_x509_crt *crt;
793d3b0591SJens Wiklander uint32_t flags;
803d3b0591SJens Wiklander } x509_crt_verify_chain_item;
813d3b0591SJens Wiklander
823d3b0591SJens Wiklander /*
833d3b0591SJens Wiklander * Max size of verification chain: end-entity + intermediates + trusted root
843d3b0591SJens Wiklander */
853d3b0591SJens Wiklander #define X509_MAX_VERIFY_CHAIN_SIZE (MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2)
86817466cbSJens Wiklander
877901324dSJerome Forissier /* Default profile. Do not remove items unless there are serious security
887901324dSJerome Forissier * concerns. */
89817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default =
90817466cbSJens Wiklander {
9132b31808SJens Wiklander /* Hashes from SHA-256 and above. Note that this selection
9232b31808SJens Wiklander * should be aligned with ssl_preset_default_hashes in ssl_tls.c. */
93817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
94817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
95817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
96817466cbSJens Wiklander 0xFFFFFFF, /* Any PK alg */
97b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
9832b31808SJens Wiklander /* Curves at or above 128-bit security level. Note that this selection
9932b31808SJens Wiklander * should be aligned with ssl_preset_default_curves in ssl_tls.c. */
10032b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) |
10132b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1) |
10232b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP521R1) |
10332b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP256R1) |
10432b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP384R1) |
10532b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP512R1) |
10632b31808SJens Wiklander 0,
107b0563631STom Van Eyck #else /* MBEDTLS_PK_HAVE_ECC_KEYS */
10832b31808SJens Wiklander 0,
109b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
11032b31808SJens Wiklander 2048,
11132b31808SJens Wiklander };
11232b31808SJens Wiklander
11332b31808SJens Wiklander /* Next-generation profile. Currently identical to the default, but may
11432b31808SJens Wiklander * be tightened at any time. */
11532b31808SJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next =
11632b31808SJens Wiklander {
11732b31808SJens Wiklander /* Hashes from SHA-256 and above. */
11832b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
11932b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
12032b31808SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
12132b31808SJens Wiklander 0xFFFFFFF, /* Any PK alg */
12232b31808SJens Wiklander #if defined(MBEDTLS_ECP_C)
12332b31808SJens Wiklander /* Curves at or above 128-bit security level. */
124817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) |
125817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1) |
126817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP521R1) |
127817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP256R1) |
128817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP384R1) |
129817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP512R1) |
130817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256K1),
131817466cbSJens Wiklander #else
132817466cbSJens Wiklander 0,
133817466cbSJens Wiklander #endif
134817466cbSJens Wiklander 2048,
135817466cbSJens Wiklander };
136817466cbSJens Wiklander
137817466cbSJens Wiklander /*
138817466cbSJens Wiklander * NSA Suite B Profile
139817466cbSJens Wiklander */
140817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb =
141817466cbSJens Wiklander {
142817466cbSJens Wiklander /* Only SHA-256 and 384 */
143817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
144817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384),
145817466cbSJens Wiklander /* Only ECDSA */
1463d3b0591SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECDSA) |
1473d3b0591SJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECKEY),
148b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
149817466cbSJens Wiklander /* Only NIST P-256 and P-384 */
150817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) |
151817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1),
152b0563631STom Van Eyck #else /* MBEDTLS_PK_HAVE_ECC_KEYS */
153817466cbSJens Wiklander 0,
154b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
155817466cbSJens Wiklander 0,
156817466cbSJens Wiklander };
157817466cbSJens Wiklander
158817466cbSJens Wiklander /*
15932b31808SJens Wiklander * Empty / all-forbidden profile
16032b31808SJens Wiklander */
16132b31808SJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_none =
16232b31808SJens Wiklander {
16332b31808SJens Wiklander 0,
16432b31808SJens Wiklander 0,
16532b31808SJens Wiklander 0,
16632b31808SJens Wiklander (uint32_t) -1,
16732b31808SJens Wiklander };
16832b31808SJens Wiklander
16932b31808SJens Wiklander /*
170817466cbSJens Wiklander * Check md_alg against profile
1713d3b0591SJens Wiklander * Return 0 if md_alg is acceptable for this profile, -1 otherwise
172817466cbSJens Wiklander */
x509_profile_check_md_alg(const mbedtls_x509_crt_profile * profile,mbedtls_md_type_t md_alg)173817466cbSJens Wiklander static int x509_profile_check_md_alg(const mbedtls_x509_crt_profile *profile,
174817466cbSJens Wiklander mbedtls_md_type_t md_alg)
175817466cbSJens Wiklander {
17632b31808SJens Wiklander if (md_alg == MBEDTLS_MD_NONE) {
17732b31808SJens Wiklander return -1;
17832b31808SJens Wiklander }
1793d3b0591SJens Wiklander
18032b31808SJens Wiklander if ((profile->allowed_mds & MBEDTLS_X509_ID_FLAG(md_alg)) != 0) {
18132b31808SJens Wiklander return 0;
18232b31808SJens Wiklander }
183817466cbSJens Wiklander
18432b31808SJens Wiklander return -1;
185817466cbSJens Wiklander }
186817466cbSJens Wiklander
187817466cbSJens Wiklander /*
188817466cbSJens Wiklander * Check pk_alg against profile
1893d3b0591SJens Wiklander * Return 0 if pk_alg is acceptable for this profile, -1 otherwise
190817466cbSJens Wiklander */
x509_profile_check_pk_alg(const mbedtls_x509_crt_profile * profile,mbedtls_pk_type_t pk_alg)191817466cbSJens Wiklander static int x509_profile_check_pk_alg(const mbedtls_x509_crt_profile *profile,
192817466cbSJens Wiklander mbedtls_pk_type_t pk_alg)
193817466cbSJens Wiklander {
19432b31808SJens Wiklander if (pk_alg == MBEDTLS_PK_NONE) {
19532b31808SJens Wiklander return -1;
19632b31808SJens Wiklander }
1973d3b0591SJens Wiklander
19832b31808SJens Wiklander if ((profile->allowed_pks & MBEDTLS_X509_ID_FLAG(pk_alg)) != 0) {
19932b31808SJens Wiklander return 0;
20032b31808SJens Wiklander }
201817466cbSJens Wiklander
20232b31808SJens Wiklander return -1;
203817466cbSJens Wiklander }
204817466cbSJens Wiklander
205817466cbSJens Wiklander /*
206817466cbSJens Wiklander * Check key against profile
2073d3b0591SJens Wiklander * Return 0 if pk is acceptable for this profile, -1 otherwise
208817466cbSJens Wiklander */
x509_profile_check_key(const mbedtls_x509_crt_profile * profile,const mbedtls_pk_context * pk)209817466cbSJens Wiklander static int x509_profile_check_key(const mbedtls_x509_crt_profile *profile,
210817466cbSJens Wiklander const mbedtls_pk_context *pk)
211817466cbSJens Wiklander {
2123d3b0591SJens Wiklander const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type(pk);
2133d3b0591SJens Wiklander
214817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
21532b31808SJens Wiklander if (pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS) {
21632b31808SJens Wiklander if (mbedtls_pk_get_bitlen(pk) >= profile->rsa_min_bitlen) {
21732b31808SJens Wiklander return 0;
21832b31808SJens Wiklander }
219817466cbSJens Wiklander
22032b31808SJens Wiklander return -1;
221817466cbSJens Wiklander }
222b0563631STom Van Eyck #endif /* MBEDTLS_RSA_C */
223817466cbSJens Wiklander
224b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
225817466cbSJens Wiklander if (pk_alg == MBEDTLS_PK_ECDSA ||
226817466cbSJens Wiklander pk_alg == MBEDTLS_PK_ECKEY ||
22732b31808SJens Wiklander pk_alg == MBEDTLS_PK_ECKEY_DH) {
228b0563631STom Van Eyck const mbedtls_ecp_group_id gid = mbedtls_pk_get_ec_group_id(pk);
2293d3b0591SJens Wiklander
23032b31808SJens Wiklander if (gid == MBEDTLS_ECP_DP_NONE) {
23132b31808SJens Wiklander return -1;
23232b31808SJens Wiklander }
233817466cbSJens Wiklander
23432b31808SJens Wiklander if ((profile->allowed_curves & MBEDTLS_X509_ID_FLAG(gid)) != 0) {
23532b31808SJens Wiklander return 0;
23632b31808SJens Wiklander }
237817466cbSJens Wiklander
23832b31808SJens Wiklander return -1;
239817466cbSJens Wiklander }
240b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
241817466cbSJens Wiklander
24232b31808SJens Wiklander return -1;
243817466cbSJens Wiklander }
244817466cbSJens Wiklander
245817466cbSJens Wiklander /*
2463d3b0591SJens Wiklander * Like memcmp, but case-insensitive and always returns -1 if different
2473d3b0591SJens Wiklander */
x509_memcasecmp(const void * s1,const void * s2,size_t len)2483d3b0591SJens Wiklander static int x509_memcasecmp(const void *s1, const void *s2, size_t len)
2493d3b0591SJens Wiklander {
2503d3b0591SJens Wiklander size_t i;
2513d3b0591SJens Wiklander unsigned char diff;
2523d3b0591SJens Wiklander const unsigned char *n1 = s1, *n2 = s2;
2533d3b0591SJens Wiklander
25432b31808SJens Wiklander for (i = 0; i < len; i++) {
2553d3b0591SJens Wiklander diff = n1[i] ^ n2[i];
2563d3b0591SJens Wiklander
25732b31808SJens Wiklander if (diff == 0) {
2583d3b0591SJens Wiklander continue;
25932b31808SJens Wiklander }
2603d3b0591SJens Wiklander
2613d3b0591SJens Wiklander if (diff == 32 &&
2623d3b0591SJens Wiklander ((n1[i] >= 'a' && n1[i] <= 'z') ||
26332b31808SJens Wiklander (n1[i] >= 'A' && n1[i] <= 'Z'))) {
2643d3b0591SJens Wiklander continue;
2653d3b0591SJens Wiklander }
2663d3b0591SJens Wiklander
26732b31808SJens Wiklander return -1;
2683d3b0591SJens Wiklander }
2693d3b0591SJens Wiklander
27032b31808SJens Wiklander return 0;
2713d3b0591SJens Wiklander }
2723d3b0591SJens Wiklander
2733d3b0591SJens Wiklander /*
2743d3b0591SJens Wiklander * Return 0 if name matches wildcard, -1 otherwise
2753d3b0591SJens Wiklander */
x509_check_wildcard(const char * cn,const mbedtls_x509_buf * name)2763d3b0591SJens Wiklander static int x509_check_wildcard(const char *cn, const mbedtls_x509_buf *name)
2773d3b0591SJens Wiklander {
2783d3b0591SJens Wiklander size_t i;
2793d3b0591SJens Wiklander size_t cn_idx = 0, cn_len = strlen(cn);
2803d3b0591SJens Wiklander
2813d3b0591SJens Wiklander /* We can't have a match if there is no wildcard to match */
28232b31808SJens Wiklander if (name->len < 3 || name->p[0] != '*' || name->p[1] != '.') {
28332b31808SJens Wiklander return -1;
28432b31808SJens Wiklander }
2853d3b0591SJens Wiklander
28632b31808SJens Wiklander for (i = 0; i < cn_len; ++i) {
28732b31808SJens Wiklander if (cn[i] == '.') {
2883d3b0591SJens Wiklander cn_idx = i;
2893d3b0591SJens Wiklander break;
2903d3b0591SJens Wiklander }
2913d3b0591SJens Wiklander }
2923d3b0591SJens Wiklander
29332b31808SJens Wiklander if (cn_idx == 0) {
29432b31808SJens Wiklander return -1;
2953d3b0591SJens Wiklander }
2963d3b0591SJens Wiklander
29732b31808SJens Wiklander if (cn_len - cn_idx == name->len - 1 &&
29832b31808SJens Wiklander x509_memcasecmp(name->p + 1, cn + cn_idx, name->len - 1) == 0) {
29932b31808SJens Wiklander return 0;
30032b31808SJens Wiklander }
30132b31808SJens Wiklander
30232b31808SJens Wiklander return -1;
3033d3b0591SJens Wiklander }
3043d3b0591SJens Wiklander
3053d3b0591SJens Wiklander /*
3063d3b0591SJens Wiklander * Compare two X.509 strings, case-insensitive, and allowing for some encoding
3073d3b0591SJens Wiklander * variations (but not all).
3083d3b0591SJens Wiklander *
3093d3b0591SJens Wiklander * Return 0 if equal, -1 otherwise.
3103d3b0591SJens Wiklander */
x509_string_cmp(const mbedtls_x509_buf * a,const mbedtls_x509_buf * b)3113d3b0591SJens Wiklander static int x509_string_cmp(const mbedtls_x509_buf *a, const mbedtls_x509_buf *b)
3123d3b0591SJens Wiklander {
3133d3b0591SJens Wiklander if (a->tag == b->tag &&
3143d3b0591SJens Wiklander a->len == b->len &&
31532b31808SJens Wiklander memcmp(a->p, b->p, b->len) == 0) {
31632b31808SJens Wiklander return 0;
3173d3b0591SJens Wiklander }
3183d3b0591SJens Wiklander
3193d3b0591SJens Wiklander if ((a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING) &&
3203d3b0591SJens Wiklander (b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING) &&
3213d3b0591SJens Wiklander a->len == b->len &&
32232b31808SJens Wiklander x509_memcasecmp(a->p, b->p, b->len) == 0) {
32332b31808SJens Wiklander return 0;
3243d3b0591SJens Wiklander }
3253d3b0591SJens Wiklander
32632b31808SJens Wiklander return -1;
3273d3b0591SJens Wiklander }
3283d3b0591SJens Wiklander
3293d3b0591SJens Wiklander /*
3303d3b0591SJens Wiklander * Compare two X.509 Names (aka rdnSequence).
3313d3b0591SJens Wiklander *
3323d3b0591SJens Wiklander * See RFC 5280 section 7.1, though we don't implement the whole algorithm:
3333d3b0591SJens Wiklander * we sometimes return unequal when the full algorithm would return equal,
3343d3b0591SJens Wiklander * but never the other way. (In particular, we don't do Unicode normalisation
3353d3b0591SJens Wiklander * or space folding.)
3363d3b0591SJens Wiklander *
3373d3b0591SJens Wiklander * Return 0 if equal, -1 otherwise.
3383d3b0591SJens Wiklander */
x509_name_cmp(const mbedtls_x509_name * a,const mbedtls_x509_name * b)3393d3b0591SJens Wiklander static int x509_name_cmp(const mbedtls_x509_name *a, const mbedtls_x509_name *b)
3403d3b0591SJens Wiklander {
3413d3b0591SJens Wiklander /* Avoid recursion, it might not be optimised by the compiler */
34232b31808SJens Wiklander while (a != NULL || b != NULL) {
34332b31808SJens Wiklander if (a == NULL || b == NULL) {
34432b31808SJens Wiklander return -1;
34532b31808SJens Wiklander }
3463d3b0591SJens Wiklander
3473d3b0591SJens Wiklander /* type */
3483d3b0591SJens Wiklander if (a->oid.tag != b->oid.tag ||
3493d3b0591SJens Wiklander a->oid.len != b->oid.len ||
35032b31808SJens Wiklander memcmp(a->oid.p, b->oid.p, b->oid.len) != 0) {
35132b31808SJens Wiklander return -1;
3523d3b0591SJens Wiklander }
3533d3b0591SJens Wiklander
3543d3b0591SJens Wiklander /* value */
35532b31808SJens Wiklander if (x509_string_cmp(&a->val, &b->val) != 0) {
35632b31808SJens Wiklander return -1;
35732b31808SJens Wiklander }
3583d3b0591SJens Wiklander
3593d3b0591SJens Wiklander /* structure of the list of sets */
36032b31808SJens Wiklander if (a->next_merged != b->next_merged) {
36132b31808SJens Wiklander return -1;
36232b31808SJens Wiklander }
3633d3b0591SJens Wiklander
3643d3b0591SJens Wiklander a = a->next;
3653d3b0591SJens Wiklander b = b->next;
3663d3b0591SJens Wiklander }
3673d3b0591SJens Wiklander
3683d3b0591SJens Wiklander /* a == NULL == b */
36932b31808SJens Wiklander return 0;
3703d3b0591SJens Wiklander }
3713d3b0591SJens Wiklander
3723d3b0591SJens Wiklander /*
3733d3b0591SJens Wiklander * Reset (init or clear) a verify_chain
3743d3b0591SJens Wiklander */
x509_crt_verify_chain_reset(mbedtls_x509_crt_verify_chain * ver_chain)3753d3b0591SJens Wiklander static void x509_crt_verify_chain_reset(
3763d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain *ver_chain)
3773d3b0591SJens Wiklander {
3783d3b0591SJens Wiklander size_t i;
3793d3b0591SJens Wiklander
38032b31808SJens Wiklander for (i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++) {
3813d3b0591SJens Wiklander ver_chain->items[i].crt = NULL;
3825b25c76aSJerome Forissier ver_chain->items[i].flags = (uint32_t) -1;
3833d3b0591SJens Wiklander }
3843d3b0591SJens Wiklander
3853d3b0591SJens Wiklander ver_chain->len = 0;
38611fa71b9SJerome Forissier
38711fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
38811fa71b9SJerome Forissier ver_chain->trust_ca_cb_result = NULL;
38911fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
3903d3b0591SJens Wiklander }
3913d3b0591SJens Wiklander
3923d3b0591SJens Wiklander /*
393817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) }
394817466cbSJens Wiklander */
x509_get_version(unsigned char ** p,const unsigned char * end,int * ver)395817466cbSJens Wiklander static int x509_get_version(unsigned char **p,
396817466cbSJens Wiklander const unsigned char *end,
397817466cbSJens Wiklander int *ver)
398817466cbSJens Wiklander {
39911fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
400817466cbSJens Wiklander size_t len;
401817466cbSJens Wiklander
402817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len,
40332b31808SJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
40432b31808SJens Wiklander 0)) != 0) {
40532b31808SJens Wiklander if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
406817466cbSJens Wiklander *ver = 0;
40732b31808SJens Wiklander return 0;
408817466cbSJens Wiklander }
409817466cbSJens Wiklander
41032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
411817466cbSJens Wiklander }
412817466cbSJens Wiklander
413817466cbSJens Wiklander end = *p + len;
414817466cbSJens Wiklander
41532b31808SJens Wiklander if ((ret = mbedtls_asn1_get_int(p, end, ver)) != 0) {
41632b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_VERSION, ret);
41732b31808SJens Wiklander }
418817466cbSJens Wiklander
41932b31808SJens Wiklander if (*p != end) {
42032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_VERSION,
42132b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
42232b31808SJens Wiklander }
423817466cbSJens Wiklander
42432b31808SJens Wiklander return 0;
425817466cbSJens Wiklander }
426817466cbSJens Wiklander
427817466cbSJens Wiklander /*
428817466cbSJens Wiklander * Validity ::= SEQUENCE {
429817466cbSJens Wiklander * notBefore Time,
430817466cbSJens Wiklander * notAfter Time }
431817466cbSJens Wiklander */
x509_get_dates(unsigned char ** p,const unsigned char * end,mbedtls_x509_time * from,mbedtls_x509_time * to)432817466cbSJens Wiklander static int x509_get_dates(unsigned char **p,
433817466cbSJens Wiklander const unsigned char *end,
434817466cbSJens Wiklander mbedtls_x509_time *from,
435817466cbSJens Wiklander mbedtls_x509_time *to)
436817466cbSJens Wiklander {
43711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
438817466cbSJens Wiklander size_t len;
439817466cbSJens Wiklander
440817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len,
44132b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
44232b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_DATE, ret);
44332b31808SJens Wiklander }
444817466cbSJens Wiklander
445817466cbSJens Wiklander end = *p + len;
446817466cbSJens Wiklander
44732b31808SJens Wiklander if ((ret = mbedtls_x509_get_time(p, end, from)) != 0) {
44832b31808SJens Wiklander return ret;
44932b31808SJens Wiklander }
450817466cbSJens Wiklander
45132b31808SJens Wiklander if ((ret = mbedtls_x509_get_time(p, end, to)) != 0) {
45232b31808SJens Wiklander return ret;
45332b31808SJens Wiklander }
454817466cbSJens Wiklander
45532b31808SJens Wiklander if (*p != end) {
45632b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_DATE,
45732b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
45832b31808SJens Wiklander }
459817466cbSJens Wiklander
46032b31808SJens Wiklander return 0;
461817466cbSJens Wiklander }
462817466cbSJens Wiklander
463817466cbSJens Wiklander /*
464817466cbSJens Wiklander * X.509 v2/v3 unique identifier (not parsed)
465817466cbSJens Wiklander */
x509_get_uid(unsigned char ** p,const unsigned char * end,mbedtls_x509_buf * uid,int n)466817466cbSJens Wiklander static int x509_get_uid(unsigned char **p,
467817466cbSJens Wiklander const unsigned char *end,
468817466cbSJens Wiklander mbedtls_x509_buf *uid, int n)
469817466cbSJens Wiklander {
47011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
471817466cbSJens Wiklander
47232b31808SJens Wiklander if (*p == end) {
47332b31808SJens Wiklander return 0;
47432b31808SJens Wiklander }
475817466cbSJens Wiklander
476817466cbSJens Wiklander uid->tag = **p;
477817466cbSJens Wiklander
478817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &uid->len,
47932b31808SJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
48032b31808SJens Wiklander n)) != 0) {
48132b31808SJens Wiklander if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
48232b31808SJens Wiklander return 0;
48332b31808SJens Wiklander }
484817466cbSJens Wiklander
48532b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
486817466cbSJens Wiklander }
487817466cbSJens Wiklander
488817466cbSJens Wiklander uid->p = *p;
489817466cbSJens Wiklander *p += uid->len;
490817466cbSJens Wiklander
49132b31808SJens Wiklander return 0;
492817466cbSJens Wiklander }
493817466cbSJens Wiklander
x509_get_basic_constraints(unsigned char ** p,const unsigned char * end,int * ca_istrue,int * max_pathlen)494817466cbSJens Wiklander static int x509_get_basic_constraints(unsigned char **p,
495817466cbSJens Wiklander const unsigned char *end,
496817466cbSJens Wiklander int *ca_istrue,
497817466cbSJens Wiklander int *max_pathlen)
498817466cbSJens Wiklander {
49911fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
500817466cbSJens Wiklander size_t len;
501817466cbSJens Wiklander
502817466cbSJens Wiklander /*
503817466cbSJens Wiklander * BasicConstraints ::= SEQUENCE {
504817466cbSJens Wiklander * cA BOOLEAN DEFAULT FALSE,
505817466cbSJens Wiklander * pathLenConstraint INTEGER (0..MAX) OPTIONAL }
506817466cbSJens Wiklander */
507817466cbSJens Wiklander *ca_istrue = 0; /* DEFAULT FALSE */
508817466cbSJens Wiklander *max_pathlen = 0; /* endless */
509817466cbSJens Wiklander
510817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len,
51132b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
51232b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
513817466cbSJens Wiklander }
514817466cbSJens Wiklander
51532b31808SJens Wiklander if (*p == end) {
51632b31808SJens Wiklander return 0;
51732b31808SJens Wiklander }
518817466cbSJens Wiklander
51932b31808SJens Wiklander if ((ret = mbedtls_asn1_get_bool(p, end, ca_istrue)) != 0) {
52032b31808SJens Wiklander if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
52132b31808SJens Wiklander ret = mbedtls_asn1_get_int(p, end, ca_istrue);
52232b31808SJens Wiklander }
523817466cbSJens Wiklander
52432b31808SJens Wiklander if (ret != 0) {
52532b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
52632b31808SJens Wiklander }
52732b31808SJens Wiklander
52832b31808SJens Wiklander if (*ca_istrue != 0) {
52932b31808SJens Wiklander *ca_istrue = 1;
53032b31808SJens Wiklander }
53132b31808SJens Wiklander }
53232b31808SJens Wiklander
53332b31808SJens Wiklander if (*p == end) {
53432b31808SJens Wiklander return 0;
53532b31808SJens Wiklander }
53632b31808SJens Wiklander
53732b31808SJens Wiklander if ((ret = mbedtls_asn1_get_int(p, end, max_pathlen)) != 0) {
53832b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
53932b31808SJens Wiklander }
54032b31808SJens Wiklander
54132b31808SJens Wiklander if (*p != end) {
54232b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
54332b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
54432b31808SJens Wiklander }
5457901324dSJerome Forissier
5467901324dSJerome Forissier /* Do not accept max_pathlen equal to INT_MAX to avoid a signed integer
5477901324dSJerome Forissier * overflow, which is an undefined behavior. */
54832b31808SJens Wiklander if (*max_pathlen == INT_MAX) {
54932b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
55032b31808SJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH);
55132b31808SJens Wiklander }
552817466cbSJens Wiklander
553817466cbSJens Wiklander (*max_pathlen)++;
554817466cbSJens Wiklander
55532b31808SJens Wiklander return 0;
556817466cbSJens Wiklander }
557817466cbSJens Wiklander
558817466cbSJens Wiklander /*
559817466cbSJens Wiklander * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
560817466cbSJens Wiklander *
561817466cbSJens Wiklander * KeyPurposeId ::= OBJECT IDENTIFIER
562817466cbSJens Wiklander */
x509_get_ext_key_usage(unsigned char ** p,const unsigned char * end,mbedtls_x509_sequence * ext_key_usage)563817466cbSJens Wiklander static int x509_get_ext_key_usage(unsigned char **p,
564817466cbSJens Wiklander const unsigned char *end,
565817466cbSJens Wiklander mbedtls_x509_sequence *ext_key_usage)
566817466cbSJens Wiklander {
56711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
568817466cbSJens Wiklander
56932b31808SJens Wiklander if ((ret = mbedtls_asn1_get_sequence_of(p, end, ext_key_usage, MBEDTLS_ASN1_OID)) != 0) {
57032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
57132b31808SJens Wiklander }
572817466cbSJens Wiklander
573817466cbSJens Wiklander /* Sequence length must be >= 1 */
57432b31808SJens Wiklander if (ext_key_usage->buf.p == NULL) {
57532b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
57632b31808SJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH);
577817466cbSJens Wiklander }
578817466cbSJens Wiklander
57932b31808SJens Wiklander return 0;
580817466cbSJens Wiklander }
581817466cbSJens Wiklander
582817466cbSJens Wiklander /*
583b0563631STom Van Eyck * SubjectKeyIdentifier ::= KeyIdentifier
584b0563631STom Van Eyck *
585b0563631STom Van Eyck * KeyIdentifier ::= OCTET STRING
586b0563631STom Van Eyck */
x509_get_subject_key_id(unsigned char ** p,const unsigned char * end,mbedtls_x509_buf * subject_key_id)587b0563631STom Van Eyck static int x509_get_subject_key_id(unsigned char **p,
588b0563631STom Van Eyck const unsigned char *end,
589b0563631STom Van Eyck mbedtls_x509_buf *subject_key_id)
590b0563631STom Van Eyck {
591b0563631STom Van Eyck int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
592b0563631STom Van Eyck size_t len = 0u;
593b0563631STom Van Eyck
594b0563631STom Van Eyck if ((ret = mbedtls_asn1_get_tag(p, end, &len,
595b0563631STom Van Eyck MBEDTLS_ASN1_OCTET_STRING)) != 0) {
596b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
597b0563631STom Van Eyck }
598b0563631STom Van Eyck
599b0563631STom Van Eyck subject_key_id->len = len;
600b0563631STom Van Eyck subject_key_id->tag = MBEDTLS_ASN1_OCTET_STRING;
601b0563631STom Van Eyck subject_key_id->p = *p;
602b0563631STom Van Eyck *p += len;
603b0563631STom Van Eyck
604b0563631STom Van Eyck if (*p != end) {
605b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
606b0563631STom Van Eyck MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
607b0563631STom Van Eyck }
608b0563631STom Van Eyck
609b0563631STom Van Eyck return 0;
610b0563631STom Van Eyck }
611b0563631STom Van Eyck
612b0563631STom Van Eyck /*
613b0563631STom Van Eyck * AuthorityKeyIdentifier ::= SEQUENCE {
614b0563631STom Van Eyck * keyIdentifier [0] KeyIdentifier OPTIONAL,
615b0563631STom Van Eyck * authorityCertIssuer [1] GeneralNames OPTIONAL,
616b0563631STom Van Eyck * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
617b0563631STom Van Eyck *
618b0563631STom Van Eyck * KeyIdentifier ::= OCTET STRING
619b0563631STom Van Eyck */
x509_get_authority_key_id(unsigned char ** p,unsigned char * end,mbedtls_x509_authority * authority_key_id)620b0563631STom Van Eyck static int x509_get_authority_key_id(unsigned char **p,
621b0563631STom Van Eyck unsigned char *end,
622b0563631STom Van Eyck mbedtls_x509_authority *authority_key_id)
623b0563631STom Van Eyck {
624b0563631STom Van Eyck int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
625b0563631STom Van Eyck size_t len = 0u;
626b0563631STom Van Eyck
627b0563631STom Van Eyck if ((ret = mbedtls_asn1_get_tag(p, end, &len,
628b0563631STom Van Eyck MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
629b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
630b0563631STom Van Eyck }
631b0563631STom Van Eyck
632b0563631STom Van Eyck if (*p + len != end) {
633b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
634b0563631STom Van Eyck MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
635b0563631STom Van Eyck }
636b0563631STom Van Eyck
637b0563631STom Van Eyck ret = mbedtls_asn1_get_tag(p, end, &len,
638b0563631STom Van Eyck MBEDTLS_ASN1_CONTEXT_SPECIFIC);
639b0563631STom Van Eyck
640b0563631STom Van Eyck /* KeyIdentifier is an OPTIONAL field */
641b0563631STom Van Eyck if (ret == 0) {
642b0563631STom Van Eyck authority_key_id->keyIdentifier.len = len;
643b0563631STom Van Eyck authority_key_id->keyIdentifier.p = *p;
644b0563631STom Van Eyck /* Setting tag of the keyIdentfier intentionally to 0x04.
645b0563631STom Van Eyck * Although the .keyIdentfier field is CONTEXT_SPECIFIC ([0] OPTIONAL),
646b0563631STom Van Eyck * its tag with the content is the payload of on OCTET STRING primitive */
647b0563631STom Van Eyck authority_key_id->keyIdentifier.tag = MBEDTLS_ASN1_OCTET_STRING;
648b0563631STom Van Eyck
649b0563631STom Van Eyck *p += len;
650b0563631STom Van Eyck } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
651b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
652b0563631STom Van Eyck }
653b0563631STom Van Eyck
654b0563631STom Van Eyck if (*p < end) {
655b0563631STom Van Eyck /* Getting authorityCertIssuer using the required specific class tag [1] */
656b0563631STom Van Eyck if ((ret = mbedtls_asn1_get_tag(p, end, &len,
657b0563631STom Van Eyck MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
658b0563631STom Van Eyck 1)) != 0) {
659b0563631STom Van Eyck /* authorityCertIssuer and authorityCertSerialNumber MUST both
660b0563631STom Van Eyck be present or both be absent. At this point we expect to have both. */
661b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
662b0563631STom Van Eyck }
663b0563631STom Van Eyck /* "end" also includes the CertSerialNumber field so "len" shall be used */
664b0563631STom Van Eyck ret = mbedtls_x509_get_subject_alt_name_ext(p,
665b0563631STom Van Eyck (*p+len),
666b0563631STom Van Eyck &authority_key_id->authorityCertIssuer);
667b0563631STom Van Eyck if (ret != 0) {
668b0563631STom Van Eyck return ret;
669b0563631STom Van Eyck }
670b0563631STom Van Eyck
671b0563631STom Van Eyck /* Getting authorityCertSerialNumber using the required specific class tag [2] */
672b0563631STom Van Eyck if ((ret = mbedtls_asn1_get_tag(p, end, &len,
673b0563631STom Van Eyck MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2)) != 0) {
674b0563631STom Van Eyck return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
675b0563631STom Van Eyck }
676b0563631STom Van Eyck authority_key_id->authorityCertSerialNumber.len = len;
677b0563631STom Van Eyck authority_key_id->authorityCertSerialNumber.p = *p;
678b0563631STom Van Eyck authority_key_id->authorityCertSerialNumber.tag = MBEDTLS_ASN1_INTEGER;
679b0563631STom Van Eyck *p += len;
680b0563631STom Van Eyck }
681b0563631STom Van Eyck
682b0563631STom Van Eyck if (*p != end) {
683b0563631STom Van Eyck return MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
684b0563631STom Van Eyck MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
685b0563631STom Van Eyck }
686b0563631STom Van Eyck
687b0563631STom Van Eyck return 0;
688b0563631STom Van Eyck }
689b0563631STom Van Eyck
690b0563631STom Van Eyck /*
69111fa71b9SJerome Forissier * id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 }
69211fa71b9SJerome Forissier *
69311fa71b9SJerome Forissier * anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 }
69411fa71b9SJerome Forissier *
69511fa71b9SJerome Forissier * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
69611fa71b9SJerome Forissier *
69711fa71b9SJerome Forissier * PolicyInformation ::= SEQUENCE {
69811fa71b9SJerome Forissier * policyIdentifier CertPolicyId,
69911fa71b9SJerome Forissier * policyQualifiers SEQUENCE SIZE (1..MAX) OF
70011fa71b9SJerome Forissier * PolicyQualifierInfo OPTIONAL }
70111fa71b9SJerome Forissier *
70211fa71b9SJerome Forissier * CertPolicyId ::= OBJECT IDENTIFIER
70311fa71b9SJerome Forissier *
70411fa71b9SJerome Forissier * PolicyQualifierInfo ::= SEQUENCE {
70511fa71b9SJerome Forissier * policyQualifierId PolicyQualifierId,
70611fa71b9SJerome Forissier * qualifier ANY DEFINED BY policyQualifierId }
70711fa71b9SJerome Forissier *
70811fa71b9SJerome Forissier * -- policyQualifierIds for Internet policy qualifiers
70911fa71b9SJerome Forissier *
71011fa71b9SJerome Forissier * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 }
71111fa71b9SJerome Forissier * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 }
71211fa71b9SJerome Forissier * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 }
71311fa71b9SJerome Forissier *
71411fa71b9SJerome Forissier * PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
71511fa71b9SJerome Forissier *
71611fa71b9SJerome Forissier * Qualifier ::= CHOICE {
71711fa71b9SJerome Forissier * cPSuri CPSuri,
71811fa71b9SJerome Forissier * userNotice UserNotice }
71911fa71b9SJerome Forissier *
72011fa71b9SJerome Forissier * CPSuri ::= IA5String
72111fa71b9SJerome Forissier *
72211fa71b9SJerome Forissier * UserNotice ::= SEQUENCE {
72311fa71b9SJerome Forissier * noticeRef NoticeReference OPTIONAL,
72411fa71b9SJerome Forissier * explicitText DisplayText OPTIONAL }
72511fa71b9SJerome Forissier *
72611fa71b9SJerome Forissier * NoticeReference ::= SEQUENCE {
72711fa71b9SJerome Forissier * organization DisplayText,
72811fa71b9SJerome Forissier * noticeNumbers SEQUENCE OF INTEGER }
72911fa71b9SJerome Forissier *
73011fa71b9SJerome Forissier * DisplayText ::= CHOICE {
73111fa71b9SJerome Forissier * ia5String IA5String (SIZE (1..200)),
73211fa71b9SJerome Forissier * visibleString VisibleString (SIZE (1..200)),
73311fa71b9SJerome Forissier * bmpString BMPString (SIZE (1..200)),
73411fa71b9SJerome Forissier * utf8String UTF8String (SIZE (1..200)) }
73511fa71b9SJerome Forissier *
73611fa71b9SJerome Forissier * NOTE: we only parse and use anyPolicy without qualifiers at this point
73711fa71b9SJerome Forissier * as defined in RFC 5280.
73811fa71b9SJerome Forissier */
x509_get_certificate_policies(unsigned char ** p,const unsigned char * end,mbedtls_x509_sequence * certificate_policies)73911fa71b9SJerome Forissier static int x509_get_certificate_policies(unsigned char **p,
74011fa71b9SJerome Forissier const unsigned char *end,
74111fa71b9SJerome Forissier mbedtls_x509_sequence *certificate_policies)
74211fa71b9SJerome Forissier {
74311fa71b9SJerome Forissier int ret, parse_ret = 0;
74411fa71b9SJerome Forissier size_t len;
74511fa71b9SJerome Forissier mbedtls_asn1_buf *buf;
74611fa71b9SJerome Forissier mbedtls_asn1_sequence *cur = certificate_policies;
74711fa71b9SJerome Forissier
74811fa71b9SJerome Forissier /* Get main sequence tag */
74911fa71b9SJerome Forissier ret = mbedtls_asn1_get_tag(p, end, &len,
75011fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
75132b31808SJens Wiklander if (ret != 0) {
75232b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
75332b31808SJens Wiklander }
75411fa71b9SJerome Forissier
75532b31808SJens Wiklander if (*p + len != end) {
75632b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
75732b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
75832b31808SJens Wiklander }
75911fa71b9SJerome Forissier
76011fa71b9SJerome Forissier /*
76111fa71b9SJerome Forissier * Cannot be an empty sequence.
76211fa71b9SJerome Forissier */
76332b31808SJens Wiklander if (len == 0) {
76432b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
76532b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
76632b31808SJens Wiklander }
76711fa71b9SJerome Forissier
76832b31808SJens Wiklander while (*p < end) {
76911fa71b9SJerome Forissier mbedtls_x509_buf policy_oid;
77011fa71b9SJerome Forissier const unsigned char *policy_end;
77111fa71b9SJerome Forissier
77211fa71b9SJerome Forissier /*
77311fa71b9SJerome Forissier * Get the policy sequence
77411fa71b9SJerome Forissier */
77511fa71b9SJerome Forissier if ((ret = mbedtls_asn1_get_tag(p, end, &len,
77632b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
77732b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
77832b31808SJens Wiklander }
77911fa71b9SJerome Forissier
78011fa71b9SJerome Forissier policy_end = *p + len;
78111fa71b9SJerome Forissier
78211fa71b9SJerome Forissier if ((ret = mbedtls_asn1_get_tag(p, policy_end, &len,
78332b31808SJens Wiklander MBEDTLS_ASN1_OID)) != 0) {
78432b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
78532b31808SJens Wiklander }
78611fa71b9SJerome Forissier
78711fa71b9SJerome Forissier policy_oid.tag = MBEDTLS_ASN1_OID;
78811fa71b9SJerome Forissier policy_oid.len = len;
78911fa71b9SJerome Forissier policy_oid.p = *p;
79011fa71b9SJerome Forissier
79111fa71b9SJerome Forissier /*
79211fa71b9SJerome Forissier * Only AnyPolicy is currently supported when enforcing policy.
79311fa71b9SJerome Forissier */
79432b31808SJens Wiklander if (MBEDTLS_OID_CMP(MBEDTLS_OID_ANY_POLICY, &policy_oid) != 0) {
79511fa71b9SJerome Forissier /*
79611fa71b9SJerome Forissier * Set the parsing return code but continue parsing, in case this
79732b31808SJens Wiklander * extension is critical.
79811fa71b9SJerome Forissier */
79911fa71b9SJerome Forissier parse_ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
80011fa71b9SJerome Forissier }
80111fa71b9SJerome Forissier
80211fa71b9SJerome Forissier /* Allocate and assign next pointer */
80332b31808SJens Wiklander if (cur->buf.p != NULL) {
80432b31808SJens Wiklander if (cur->next != NULL) {
80532b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
80632b31808SJens Wiklander }
80711fa71b9SJerome Forissier
80811fa71b9SJerome Forissier cur->next = mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence));
80911fa71b9SJerome Forissier
81032b31808SJens Wiklander if (cur->next == NULL) {
81132b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
81232b31808SJens Wiklander MBEDTLS_ERR_ASN1_ALLOC_FAILED);
81332b31808SJens Wiklander }
81411fa71b9SJerome Forissier
81511fa71b9SJerome Forissier cur = cur->next;
81611fa71b9SJerome Forissier }
81711fa71b9SJerome Forissier
81811fa71b9SJerome Forissier buf = &(cur->buf);
81911fa71b9SJerome Forissier buf->tag = policy_oid.tag;
82011fa71b9SJerome Forissier buf->p = policy_oid.p;
82111fa71b9SJerome Forissier buf->len = policy_oid.len;
82211fa71b9SJerome Forissier
82311fa71b9SJerome Forissier *p += len;
82411fa71b9SJerome Forissier
82511fa71b9SJerome Forissier /*
82611fa71b9SJerome Forissier * If there is an optional qualifier, then *p < policy_end
82711fa71b9SJerome Forissier * Check the Qualifier len to verify it doesn't exceed policy_end.
82811fa71b9SJerome Forissier */
82932b31808SJens Wiklander if (*p < policy_end) {
83011fa71b9SJerome Forissier if ((ret = mbedtls_asn1_get_tag(p, policy_end, &len,
83132b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) !=
83232b31808SJens Wiklander 0) {
83332b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
83432b31808SJens Wiklander }
83511fa71b9SJerome Forissier /*
83611fa71b9SJerome Forissier * Skip the optional policy qualifiers.
83711fa71b9SJerome Forissier */
83811fa71b9SJerome Forissier *p += len;
83911fa71b9SJerome Forissier }
84011fa71b9SJerome Forissier
84132b31808SJens Wiklander if (*p != policy_end) {
84232b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
84332b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
84432b31808SJens Wiklander }
84511fa71b9SJerome Forissier }
84611fa71b9SJerome Forissier
84711fa71b9SJerome Forissier /* Set final sequence entry's next pointer to NULL */
84811fa71b9SJerome Forissier cur->next = NULL;
84911fa71b9SJerome Forissier
85032b31808SJens Wiklander if (*p != end) {
85132b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
85232b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
85332b31808SJens Wiklander }
85411fa71b9SJerome Forissier
85532b31808SJens Wiklander return parse_ret;
85611fa71b9SJerome Forissier }
85711fa71b9SJerome Forissier
85811fa71b9SJerome Forissier /*
859817466cbSJens Wiklander * X.509 v3 extensions
860817466cbSJens Wiklander *
861817466cbSJens Wiklander */
x509_get_crt_ext(unsigned char ** p,const unsigned char * end,mbedtls_x509_crt * crt,mbedtls_x509_crt_ext_cb_t cb,void * p_ctx)862817466cbSJens Wiklander static int x509_get_crt_ext(unsigned char **p,
863817466cbSJens Wiklander const unsigned char *end,
8647901324dSJerome Forissier mbedtls_x509_crt *crt,
8657901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb,
8667901324dSJerome Forissier void *p_ctx)
867817466cbSJens Wiklander {
86811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
869817466cbSJens Wiklander size_t len;
8707901324dSJerome Forissier unsigned char *end_ext_data, *start_ext_octet, *end_ext_octet;
871817466cbSJens Wiklander
87232b31808SJens Wiklander if (*p == end) {
87332b31808SJens Wiklander return 0;
87432b31808SJens Wiklander }
875817466cbSJens Wiklander
87632b31808SJens Wiklander if ((ret = mbedtls_x509_get_ext(p, end, &crt->v3_ext, 3)) != 0) {
87732b31808SJens Wiklander return ret;
87832b31808SJens Wiklander }
879817466cbSJens Wiklander
8805b25c76aSJerome Forissier end = crt->v3_ext.p + crt->v3_ext.len;
88132b31808SJens Wiklander while (*p < end) {
882817466cbSJens Wiklander /*
883817466cbSJens Wiklander * Extension ::= SEQUENCE {
884817466cbSJens Wiklander * extnID OBJECT IDENTIFIER,
885817466cbSJens Wiklander * critical BOOLEAN DEFAULT FALSE,
886817466cbSJens Wiklander * extnValue OCTET STRING }
887817466cbSJens Wiklander */
888817466cbSJens Wiklander mbedtls_x509_buf extn_oid = { 0, 0, NULL };
889817466cbSJens Wiklander int is_critical = 0; /* DEFAULT FALSE */
890817466cbSJens Wiklander int ext_type = 0;
891817466cbSJens Wiklander
892817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len,
89332b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
89432b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
89532b31808SJens Wiklander }
896817466cbSJens Wiklander
897817466cbSJens Wiklander end_ext_data = *p + len;
898817466cbSJens Wiklander
899817466cbSJens Wiklander /* Get extension ID */
9003d3b0591SJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &extn_oid.len,
90132b31808SJens Wiklander MBEDTLS_ASN1_OID)) != 0) {
90232b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
90332b31808SJens Wiklander }
904817466cbSJens Wiklander
9053d3b0591SJens Wiklander extn_oid.tag = MBEDTLS_ASN1_OID;
906817466cbSJens Wiklander extn_oid.p = *p;
907817466cbSJens Wiklander *p += extn_oid.len;
908817466cbSJens Wiklander
909817466cbSJens Wiklander /* Get optional critical */
910817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_bool(p, end_ext_data, &is_critical)) != 0 &&
91132b31808SJens Wiklander (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
91232b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
91332b31808SJens Wiklander }
914817466cbSJens Wiklander
915817466cbSJens Wiklander /* Data should be octet string type */
916817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &len,
91732b31808SJens Wiklander MBEDTLS_ASN1_OCTET_STRING)) != 0) {
91832b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
91932b31808SJens Wiklander }
920817466cbSJens Wiklander
9217901324dSJerome Forissier start_ext_octet = *p;
922817466cbSJens Wiklander end_ext_octet = *p + len;
923817466cbSJens Wiklander
92432b31808SJens Wiklander if (end_ext_octet != end_ext_data) {
92532b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
92632b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
92732b31808SJens Wiklander }
928817466cbSJens Wiklander
929817466cbSJens Wiklander /*
930817466cbSJens Wiklander * Detect supported extensions
931817466cbSJens Wiklander */
932817466cbSJens Wiklander ret = mbedtls_oid_get_x509_ext_type(&extn_oid, &ext_type);
933817466cbSJens Wiklander
93432b31808SJens Wiklander if (ret != 0) {
9357901324dSJerome Forissier /* Give the callback (if any) a chance to handle the extension */
93632b31808SJens Wiklander if (cb != NULL) {
9377901324dSJerome Forissier ret = cb(p_ctx, crt, &extn_oid, is_critical, *p, end_ext_octet);
93832b31808SJens Wiklander if (ret != 0 && is_critical) {
93932b31808SJens Wiklander return ret;
94032b31808SJens Wiklander }
9417901324dSJerome Forissier *p = end_ext_octet;
9427901324dSJerome Forissier continue;
9437901324dSJerome Forissier }
9447901324dSJerome Forissier
945817466cbSJens Wiklander /* No parser found, skip extension */
946817466cbSJens Wiklander *p = end_ext_octet;
947817466cbSJens Wiklander
94832b31808SJens Wiklander if (is_critical) {
949817466cbSJens Wiklander /* Data is marked as critical: fail */
95032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
95132b31808SJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
952817466cbSJens Wiklander }
953817466cbSJens Wiklander continue;
954817466cbSJens Wiklander }
955817466cbSJens Wiklander
956817466cbSJens Wiklander /* Forbid repeated extensions */
95732b31808SJens Wiklander if ((crt->ext_types & ext_type) != 0) {
95832b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
95932b31808SJens Wiklander }
960817466cbSJens Wiklander
961817466cbSJens Wiklander crt->ext_types |= ext_type;
962817466cbSJens Wiklander
96332b31808SJens Wiklander switch (ext_type) {
964817466cbSJens Wiklander case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS:
965817466cbSJens Wiklander /* Parse basic constraints */
966817466cbSJens Wiklander if ((ret = x509_get_basic_constraints(p, end_ext_octet,
96732b31808SJens Wiklander &crt->ca_istrue, &crt->max_pathlen)) != 0) {
96832b31808SJens Wiklander return ret;
96932b31808SJens Wiklander }
970817466cbSJens Wiklander break;
971817466cbSJens Wiklander
972817466cbSJens Wiklander case MBEDTLS_X509_EXT_KEY_USAGE:
973817466cbSJens Wiklander /* Parse key usage */
97432b31808SJens Wiklander if ((ret = mbedtls_x509_get_key_usage(p, end_ext_octet,
97532b31808SJens Wiklander &crt->key_usage)) != 0) {
97632b31808SJens Wiklander return ret;
97732b31808SJens Wiklander }
978817466cbSJens Wiklander break;
979817466cbSJens Wiklander
980817466cbSJens Wiklander case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE:
981817466cbSJens Wiklander /* Parse extended key usage */
982817466cbSJens Wiklander if ((ret = x509_get_ext_key_usage(p, end_ext_octet,
98332b31808SJens Wiklander &crt->ext_key_usage)) != 0) {
98432b31808SJens Wiklander return ret;
98532b31808SJens Wiklander }
986817466cbSJens Wiklander break;
987817466cbSJens Wiklander
988b0563631STom Van Eyck case MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER:
989b0563631STom Van Eyck /* Parse subject key identifier */
990b0563631STom Van Eyck if ((ret = x509_get_subject_key_id(p, end_ext_data,
991b0563631STom Van Eyck &crt->subject_key_id)) != 0) {
992b0563631STom Van Eyck return ret;
993b0563631STom Van Eyck }
994b0563631STom Van Eyck break;
995b0563631STom Van Eyck
996b0563631STom Van Eyck case MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER:
997b0563631STom Van Eyck /* Parse authority key identifier */
998b0563631STom Van Eyck if ((ret = x509_get_authority_key_id(p, end_ext_octet,
999b0563631STom Van Eyck &crt->authority_key_id)) != 0) {
1000b0563631STom Van Eyck return ret;
1001b0563631STom Van Eyck }
1002b0563631STom Van Eyck break;
1003817466cbSJens Wiklander case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME:
1004b0563631STom Van Eyck /* Parse subject alt name
1005b0563631STom Van Eyck * SubjectAltName ::= GeneralNames
1006b0563631STom Van Eyck */
100732b31808SJens Wiklander if ((ret = mbedtls_x509_get_subject_alt_name(p, end_ext_octet,
100832b31808SJens Wiklander &crt->subject_alt_names)) != 0) {
100932b31808SJens Wiklander return ret;
101032b31808SJens Wiklander }
1011817466cbSJens Wiklander break;
1012817466cbSJens Wiklander
1013817466cbSJens Wiklander case MBEDTLS_X509_EXT_NS_CERT_TYPE:
1014817466cbSJens Wiklander /* Parse netscape certificate type */
101532b31808SJens Wiklander if ((ret = mbedtls_x509_get_ns_cert_type(p, end_ext_octet,
101632b31808SJens Wiklander &crt->ns_cert_type)) != 0) {
101732b31808SJens Wiklander return ret;
101832b31808SJens Wiklander }
1019817466cbSJens Wiklander break;
1020817466cbSJens Wiklander
102111fa71b9SJerome Forissier case MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES:
102211fa71b9SJerome Forissier /* Parse certificate policies type */
102311fa71b9SJerome Forissier if ((ret = x509_get_certificate_policies(p, end_ext_octet,
102432b31808SJens Wiklander &crt->certificate_policies)) != 0) {
10257901324dSJerome Forissier /* Give the callback (if any) a chance to handle the extension
10267901324dSJerome Forissier * if it contains unsupported policies */
10277901324dSJerome Forissier if (ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE && cb != NULL &&
10287901324dSJerome Forissier cb(p_ctx, crt, &extn_oid, is_critical,
102932b31808SJens Wiklander start_ext_octet, end_ext_octet) == 0) {
10307901324dSJerome Forissier break;
103132b31808SJens Wiklander }
10327901324dSJerome Forissier
103332b31808SJens Wiklander if (is_critical) {
103432b31808SJens Wiklander return ret;
103532b31808SJens Wiklander } else
103611fa71b9SJerome Forissier /*
103711fa71b9SJerome Forissier * If MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, then we
103811fa71b9SJerome Forissier * cannot interpret or enforce the policy. However, it is up to
103911fa71b9SJerome Forissier * the user to choose how to enforce the policies,
104011fa71b9SJerome Forissier * unless the extension is critical.
104111fa71b9SJerome Forissier */
104232b31808SJens Wiklander if (ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) {
104332b31808SJens Wiklander return ret;
104432b31808SJens Wiklander }
104511fa71b9SJerome Forissier }
104611fa71b9SJerome Forissier break;
104711fa71b9SJerome Forissier
1048817466cbSJens Wiklander default:
104911fa71b9SJerome Forissier /*
105011fa71b9SJerome Forissier * If this is a non-critical extension, which the oid layer
105111fa71b9SJerome Forissier * supports, but there isn't an x509 parser for it,
105211fa71b9SJerome Forissier * skip the extension.
105311fa71b9SJerome Forissier */
105432b31808SJens Wiklander if (is_critical) {
105532b31808SJens Wiklander return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
105632b31808SJens Wiklander } else {
105711fa71b9SJerome Forissier *p = end_ext_octet;
1058817466cbSJens Wiklander }
1059817466cbSJens Wiklander }
106032b31808SJens Wiklander }
1061817466cbSJens Wiklander
106232b31808SJens Wiklander if (*p != end) {
106332b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
106432b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
106532b31808SJens Wiklander }
1066817466cbSJens Wiklander
106732b31808SJens Wiklander return 0;
1068817466cbSJens Wiklander }
1069817466cbSJens Wiklander
1070817466cbSJens Wiklander /*
1071817466cbSJens Wiklander * Parse and fill a single X.509 certificate in DER format
1072817466cbSJens Wiklander */
x509_crt_parse_der_core(mbedtls_x509_crt * crt,const unsigned char * buf,size_t buflen,int make_copy,mbedtls_x509_crt_ext_cb_t cb,void * p_ctx)107311fa71b9SJerome Forissier static int x509_crt_parse_der_core(mbedtls_x509_crt *crt,
107411fa71b9SJerome Forissier const unsigned char *buf,
107511fa71b9SJerome Forissier size_t buflen,
10767901324dSJerome Forissier int make_copy,
10777901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb,
10787901324dSJerome Forissier void *p_ctx)
1079817466cbSJens Wiklander {
108011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1081817466cbSJens Wiklander size_t len;
1082817466cbSJens Wiklander unsigned char *p, *end, *crt_end;
1083817466cbSJens Wiklander mbedtls_x509_buf sig_params1, sig_params2, sig_oid2;
1084817466cbSJens Wiklander
1085817466cbSJens Wiklander memset(&sig_params1, 0, sizeof(mbedtls_x509_buf));
1086817466cbSJens Wiklander memset(&sig_params2, 0, sizeof(mbedtls_x509_buf));
1087817466cbSJens Wiklander memset(&sig_oid2, 0, sizeof(mbedtls_x509_buf));
1088817466cbSJens Wiklander
1089817466cbSJens Wiklander /*
1090817466cbSJens Wiklander * Check for valid input
1091817466cbSJens Wiklander */
109232b31808SJens Wiklander if (crt == NULL || buf == NULL) {
109332b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
109432b31808SJens Wiklander }
1095817466cbSJens Wiklander
109611fa71b9SJerome Forissier /* Use the original buffer until we figure out actual length. */
1097817466cbSJens Wiklander p = (unsigned char *) buf;
1098817466cbSJens Wiklander len = buflen;
1099817466cbSJens Wiklander end = p + len;
1100817466cbSJens Wiklander
1101817466cbSJens Wiklander /*
1102817466cbSJens Wiklander * Certificate ::= SEQUENCE {
1103817466cbSJens Wiklander * tbsCertificate TBSCertificate,
1104817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier,
1105817466cbSJens Wiklander * signatureValue BIT STRING }
1106817466cbSJens Wiklander */
1107817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
110832b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
1109817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
111032b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_FORMAT;
1111817466cbSJens Wiklander }
1112817466cbSJens Wiklander
111311fa71b9SJerome Forissier end = crt_end = p + len;
1114b0563631STom Van Eyck crt->raw.len = (size_t) (crt_end - buf);
111532b31808SJens Wiklander if (make_copy != 0) {
111611fa71b9SJerome Forissier /* Create and populate a new buffer for the raw field. */
1117817466cbSJens Wiklander crt->raw.p = p = mbedtls_calloc(1, crt->raw.len);
111832b31808SJens Wiklander if (crt->raw.p == NULL) {
111932b31808SJens Wiklander return MBEDTLS_ERR_X509_ALLOC_FAILED;
112032b31808SJens Wiklander }
1121817466cbSJens Wiklander
112211fa71b9SJerome Forissier memcpy(crt->raw.p, buf, crt->raw.len);
112311fa71b9SJerome Forissier crt->own_buffer = 1;
1124817466cbSJens Wiklander
1125817466cbSJens Wiklander p += crt->raw.len - len;
1126817466cbSJens Wiklander end = crt_end = p + len;
112732b31808SJens Wiklander } else {
112811fa71b9SJerome Forissier crt->raw.p = (unsigned char *) buf;
112911fa71b9SJerome Forissier crt->own_buffer = 0;
113011fa71b9SJerome Forissier }
1131817466cbSJens Wiklander
1132817466cbSJens Wiklander /*
1133817466cbSJens Wiklander * TBSCertificate ::= SEQUENCE {
1134817466cbSJens Wiklander */
1135817466cbSJens Wiklander crt->tbs.p = p;
1136817466cbSJens Wiklander
1137817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
113832b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
1139817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
114032b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
1141817466cbSJens Wiklander }
1142817466cbSJens Wiklander
1143817466cbSJens Wiklander end = p + len;
1144b0563631STom Van Eyck crt->tbs.len = (size_t) (end - crt->tbs.p);
1145817466cbSJens Wiklander
1146817466cbSJens Wiklander /*
1147817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) }
1148817466cbSJens Wiklander *
1149817466cbSJens Wiklander * CertificateSerialNumber ::= INTEGER
1150817466cbSJens Wiklander *
1151817466cbSJens Wiklander * signature AlgorithmIdentifier
1152817466cbSJens Wiklander */
1153817466cbSJens Wiklander if ((ret = x509_get_version(&p, end, &crt->version)) != 0 ||
1154817466cbSJens Wiklander (ret = mbedtls_x509_get_serial(&p, end, &crt->serial)) != 0 ||
1155817466cbSJens Wiklander (ret = mbedtls_x509_get_alg(&p, end, &crt->sig_oid,
115632b31808SJens Wiklander &sig_params1)) != 0) {
1157817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
115832b31808SJens Wiklander return ret;
1159817466cbSJens Wiklander }
1160817466cbSJens Wiklander
116132b31808SJens Wiklander if (crt->version < 0 || crt->version > 2) {
1162817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
116332b31808SJens Wiklander return MBEDTLS_ERR_X509_UNKNOWN_VERSION;
1164817466cbSJens Wiklander }
1165817466cbSJens Wiklander
1166817466cbSJens Wiklander crt->version++;
1167817466cbSJens Wiklander
1168817466cbSJens Wiklander if ((ret = mbedtls_x509_get_sig_alg(&crt->sig_oid, &sig_params1,
1169817466cbSJens Wiklander &crt->sig_md, &crt->sig_pk,
117032b31808SJens Wiklander &crt->sig_opts)) != 0) {
1171817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
117232b31808SJens Wiklander return ret;
1173817466cbSJens Wiklander }
1174817466cbSJens Wiklander
1175817466cbSJens Wiklander /*
1176817466cbSJens Wiklander * issuer Name
1177817466cbSJens Wiklander */
1178817466cbSJens Wiklander crt->issuer_raw.p = p;
1179817466cbSJens Wiklander
1180817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
118132b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
1182817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
118332b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
1184817466cbSJens Wiklander }
1185817466cbSJens Wiklander
118632b31808SJens Wiklander if ((ret = mbedtls_x509_get_name(&p, p + len, &crt->issuer)) != 0) {
1187817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
118832b31808SJens Wiklander return ret;
1189817466cbSJens Wiklander }
1190817466cbSJens Wiklander
1191b0563631STom Van Eyck crt->issuer_raw.len = (size_t) (p - crt->issuer_raw.p);
1192817466cbSJens Wiklander
1193817466cbSJens Wiklander /*
1194817466cbSJens Wiklander * Validity ::= SEQUENCE {
1195817466cbSJens Wiklander * notBefore Time,
1196817466cbSJens Wiklander * notAfter Time }
1197817466cbSJens Wiklander *
1198817466cbSJens Wiklander */
1199817466cbSJens Wiklander if ((ret = x509_get_dates(&p, end, &crt->valid_from,
120032b31808SJens Wiklander &crt->valid_to)) != 0) {
1201817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
120232b31808SJens Wiklander return ret;
1203817466cbSJens Wiklander }
1204817466cbSJens Wiklander
1205817466cbSJens Wiklander /*
1206817466cbSJens Wiklander * subject Name
1207817466cbSJens Wiklander */
1208817466cbSJens Wiklander crt->subject_raw.p = p;
1209817466cbSJens Wiklander
1210817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
121132b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
1212817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
121332b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
1214817466cbSJens Wiklander }
1215817466cbSJens Wiklander
121632b31808SJens Wiklander if (len && (ret = mbedtls_x509_get_name(&p, p + len, &crt->subject)) != 0) {
1217817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
121832b31808SJens Wiklander return ret;
1219817466cbSJens Wiklander }
1220817466cbSJens Wiklander
1221b0563631STom Van Eyck crt->subject_raw.len = (size_t) (p - crt->subject_raw.p);
1222817466cbSJens Wiklander
1223817466cbSJens Wiklander /*
1224817466cbSJens Wiklander * SubjectPublicKeyInfo
1225817466cbSJens Wiklander */
122611fa71b9SJerome Forissier crt->pk_raw.p = p;
122732b31808SJens Wiklander if ((ret = mbedtls_pk_parse_subpubkey(&p, end, &crt->pk)) != 0) {
1228817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
122932b31808SJens Wiklander return ret;
1230817466cbSJens Wiklander }
1231b0563631STom Van Eyck crt->pk_raw.len = (size_t) (p - crt->pk_raw.p);
1232817466cbSJens Wiklander
1233817466cbSJens Wiklander /*
1234817466cbSJens Wiklander * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
1235817466cbSJens Wiklander * -- If present, version shall be v2 or v3
1236817466cbSJens Wiklander * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
1237817466cbSJens Wiklander * -- If present, version shall be v2 or v3
1238817466cbSJens Wiklander * extensions [3] EXPLICIT Extensions OPTIONAL
1239817466cbSJens Wiklander * -- If present, version shall be v3
1240817466cbSJens Wiklander */
124132b31808SJens Wiklander if (crt->version == 2 || crt->version == 3) {
1242817466cbSJens Wiklander ret = x509_get_uid(&p, end, &crt->issuer_id, 1);
124332b31808SJens Wiklander if (ret != 0) {
1244817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
124532b31808SJens Wiklander return ret;
1246817466cbSJens Wiklander }
1247817466cbSJens Wiklander }
1248817466cbSJens Wiklander
124932b31808SJens Wiklander if (crt->version == 2 || crt->version == 3) {
1250817466cbSJens Wiklander ret = x509_get_uid(&p, end, &crt->subject_id, 2);
125132b31808SJens Wiklander if (ret != 0) {
1252817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
125332b31808SJens Wiklander return ret;
1254817466cbSJens Wiklander }
1255817466cbSJens Wiklander }
1256817466cbSJens Wiklander
125732b31808SJens Wiklander if (crt->version == 3) {
12587901324dSJerome Forissier ret = x509_get_crt_ext(&p, end, crt, cb, p_ctx);
125932b31808SJens Wiklander if (ret != 0) {
1260817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
126132b31808SJens Wiklander return ret;
1262817466cbSJens Wiklander }
1263817466cbSJens Wiklander }
1264817466cbSJens Wiklander
126532b31808SJens Wiklander if (p != end) {
1266817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
126732b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT,
126832b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
1269817466cbSJens Wiklander }
1270817466cbSJens Wiklander
1271817466cbSJens Wiklander end = crt_end;
1272817466cbSJens Wiklander
1273817466cbSJens Wiklander /*
1274817466cbSJens Wiklander * }
1275817466cbSJens Wiklander * -- end of TBSCertificate
1276817466cbSJens Wiklander *
1277817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier,
1278817466cbSJens Wiklander * signatureValue BIT STRING
1279817466cbSJens Wiklander */
128032b31808SJens Wiklander if ((ret = mbedtls_x509_get_alg(&p, end, &sig_oid2, &sig_params2)) != 0) {
1281817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
128232b31808SJens Wiklander return ret;
1283817466cbSJens Wiklander }
1284817466cbSJens Wiklander
1285817466cbSJens Wiklander if (crt->sig_oid.len != sig_oid2.len ||
1286817466cbSJens Wiklander memcmp(crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len) != 0 ||
12877901324dSJerome Forissier sig_params1.tag != sig_params2.tag ||
1288817466cbSJens Wiklander sig_params1.len != sig_params2.len ||
1289817466cbSJens Wiklander (sig_params1.len != 0 &&
129032b31808SJens Wiklander memcmp(sig_params1.p, sig_params2.p, sig_params1.len) != 0)) {
1291817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
129232b31808SJens Wiklander return MBEDTLS_ERR_X509_SIG_MISMATCH;
1293817466cbSJens Wiklander }
1294817466cbSJens Wiklander
129532b31808SJens Wiklander if ((ret = mbedtls_x509_get_sig(&p, end, &crt->sig)) != 0) {
1296817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
129732b31808SJens Wiklander return ret;
1298817466cbSJens Wiklander }
1299817466cbSJens Wiklander
130032b31808SJens Wiklander if (p != end) {
1301817466cbSJens Wiklander mbedtls_x509_crt_free(crt);
130232b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT,
130332b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
1304817466cbSJens Wiklander }
1305817466cbSJens Wiklander
130632b31808SJens Wiklander return 0;
1307817466cbSJens Wiklander }
1308817466cbSJens Wiklander
1309817466cbSJens Wiklander /*
1310817466cbSJens Wiklander * Parse one X.509 certificate in DER format from a buffer and add them to a
1311817466cbSJens Wiklander * chained list
1312817466cbSJens Wiklander */
mbedtls_x509_crt_parse_der_internal(mbedtls_x509_crt * chain,const unsigned char * buf,size_t buflen,int make_copy,mbedtls_x509_crt_ext_cb_t cb,void * p_ctx)131311fa71b9SJerome Forissier static int mbedtls_x509_crt_parse_der_internal(mbedtls_x509_crt *chain,
131411fa71b9SJerome Forissier const unsigned char *buf,
131511fa71b9SJerome Forissier size_t buflen,
13167901324dSJerome Forissier int make_copy,
13177901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb,
13187901324dSJerome Forissier void *p_ctx)
1319817466cbSJens Wiklander {
132011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1321817466cbSJens Wiklander mbedtls_x509_crt *crt = chain, *prev = NULL;
1322817466cbSJens Wiklander
1323817466cbSJens Wiklander /*
1324817466cbSJens Wiklander * Check for valid input
1325817466cbSJens Wiklander */
132632b31808SJens Wiklander if (crt == NULL || buf == NULL) {
132732b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
132832b31808SJens Wiklander }
1329817466cbSJens Wiklander
133032b31808SJens Wiklander while (crt->version != 0 && crt->next != NULL) {
1331817466cbSJens Wiklander prev = crt;
1332817466cbSJens Wiklander crt = crt->next;
1333817466cbSJens Wiklander }
1334817466cbSJens Wiklander
1335817466cbSJens Wiklander /*
1336817466cbSJens Wiklander * Add new certificate on the end of the chain if needed.
1337817466cbSJens Wiklander */
133832b31808SJens Wiklander if (crt->version != 0 && crt->next == NULL) {
1339817466cbSJens Wiklander crt->next = mbedtls_calloc(1, sizeof(mbedtls_x509_crt));
1340817466cbSJens Wiklander
134132b31808SJens Wiklander if (crt->next == NULL) {
134232b31808SJens Wiklander return MBEDTLS_ERR_X509_ALLOC_FAILED;
134332b31808SJens Wiklander }
1344817466cbSJens Wiklander
1345817466cbSJens Wiklander prev = crt;
1346817466cbSJens Wiklander mbedtls_x509_crt_init(crt->next);
1347817466cbSJens Wiklander crt = crt->next;
1348817466cbSJens Wiklander }
1349817466cbSJens Wiklander
13507901324dSJerome Forissier ret = x509_crt_parse_der_core(crt, buf, buflen, make_copy, cb, p_ctx);
135132b31808SJens Wiklander if (ret != 0) {
135232b31808SJens Wiklander if (prev) {
1353817466cbSJens Wiklander prev->next = NULL;
1354817466cbSJens Wiklander }
1355817466cbSJens Wiklander
135632b31808SJens Wiklander if (crt != chain) {
135732b31808SJens Wiklander mbedtls_free(crt);
135832b31808SJens Wiklander }
135932b31808SJens Wiklander
136032b31808SJens Wiklander return ret;
136132b31808SJens Wiklander }
136232b31808SJens Wiklander
136332b31808SJens Wiklander return 0;
1364817466cbSJens Wiklander }
1365817466cbSJens Wiklander
mbedtls_x509_crt_parse_der_nocopy(mbedtls_x509_crt * chain,const unsigned char * buf,size_t buflen)136611fa71b9SJerome Forissier int mbedtls_x509_crt_parse_der_nocopy(mbedtls_x509_crt *chain,
136711fa71b9SJerome Forissier const unsigned char *buf,
136811fa71b9SJerome Forissier size_t buflen)
136911fa71b9SJerome Forissier {
137032b31808SJens Wiklander return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, 0, NULL, NULL);
13717901324dSJerome Forissier }
13727901324dSJerome Forissier
mbedtls_x509_crt_parse_der_with_ext_cb(mbedtls_x509_crt * chain,const unsigned char * buf,size_t buflen,int make_copy,mbedtls_x509_crt_ext_cb_t cb,void * p_ctx)13737901324dSJerome Forissier int mbedtls_x509_crt_parse_der_with_ext_cb(mbedtls_x509_crt *chain,
13747901324dSJerome Forissier const unsigned char *buf,
13757901324dSJerome Forissier size_t buflen,
13767901324dSJerome Forissier int make_copy,
13777901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb,
13787901324dSJerome Forissier void *p_ctx)
13797901324dSJerome Forissier {
138032b31808SJens Wiklander return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, make_copy, cb, p_ctx);
138111fa71b9SJerome Forissier }
138211fa71b9SJerome Forissier
mbedtls_x509_crt_parse_der(mbedtls_x509_crt * chain,const unsigned char * buf,size_t buflen)138311fa71b9SJerome Forissier int mbedtls_x509_crt_parse_der(mbedtls_x509_crt *chain,
138411fa71b9SJerome Forissier const unsigned char *buf,
138511fa71b9SJerome Forissier size_t buflen)
138611fa71b9SJerome Forissier {
138732b31808SJens Wiklander return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, 1, NULL, NULL);
138811fa71b9SJerome Forissier }
138911fa71b9SJerome Forissier
1390817466cbSJens Wiklander /*
1391817466cbSJens Wiklander * Parse one or more PEM certificates from a buffer and add them to the chained
1392817466cbSJens Wiklander * list
1393817466cbSJens Wiklander */
mbedtls_x509_crt_parse(mbedtls_x509_crt * chain,const unsigned char * buf,size_t buflen)139411fa71b9SJerome Forissier int mbedtls_x509_crt_parse(mbedtls_x509_crt *chain,
139511fa71b9SJerome Forissier const unsigned char *buf,
139611fa71b9SJerome Forissier size_t buflen)
1397817466cbSJens Wiklander {
1398817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
1399817466cbSJens Wiklander int success = 0, first_error = 0, total_failed = 0;
1400817466cbSJens Wiklander int buf_format = MBEDTLS_X509_FORMAT_DER;
1401817466cbSJens Wiklander #endif
1402817466cbSJens Wiklander
1403817466cbSJens Wiklander /*
1404817466cbSJens Wiklander * Check for valid input
1405817466cbSJens Wiklander */
140632b31808SJens Wiklander if (chain == NULL || buf == NULL) {
140732b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
140832b31808SJens Wiklander }
1409817466cbSJens Wiklander
1410817466cbSJens Wiklander /*
1411817466cbSJens Wiklander * Determine buffer content. Buffer contains either one DER certificate or
1412817466cbSJens Wiklander * one or more PEM certificates.
1413817466cbSJens Wiklander */
1414817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
1415817466cbSJens Wiklander if (buflen != 0 && buf[buflen - 1] == '\0' &&
141632b31808SJens Wiklander strstr((const char *) buf, "-----BEGIN CERTIFICATE-----") != NULL) {
1417817466cbSJens Wiklander buf_format = MBEDTLS_X509_FORMAT_PEM;
1418817466cbSJens Wiklander }
1419817466cbSJens Wiklander
142032b31808SJens Wiklander if (buf_format == MBEDTLS_X509_FORMAT_DER) {
1421817466cbSJens Wiklander return mbedtls_x509_crt_parse_der(chain, buf, buflen);
142232b31808SJens Wiklander }
1423817466cbSJens Wiklander #else
1424817466cbSJens Wiklander return mbedtls_x509_crt_parse_der(chain, buf, buflen);
1425817466cbSJens Wiklander #endif
1426817466cbSJens Wiklander
1427817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
142832b31808SJens Wiklander if (buf_format == MBEDTLS_X509_FORMAT_PEM) {
142911fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1430817466cbSJens Wiklander mbedtls_pem_context pem;
1431817466cbSJens Wiklander
1432817466cbSJens Wiklander /* 1 rather than 0 since the terminating NULL byte is counted in */
143332b31808SJens Wiklander while (buflen > 1) {
1434817466cbSJens Wiklander size_t use_len;
1435817466cbSJens Wiklander mbedtls_pem_init(&pem);
1436817466cbSJens Wiklander
1437817466cbSJens Wiklander /* If we get there, we know the string is null-terminated */
1438817466cbSJens Wiklander ret = mbedtls_pem_read_buffer(&pem,
1439817466cbSJens Wiklander "-----BEGIN CERTIFICATE-----",
1440817466cbSJens Wiklander "-----END CERTIFICATE-----",
1441817466cbSJens Wiklander buf, NULL, 0, &use_len);
1442817466cbSJens Wiklander
144332b31808SJens Wiklander if (ret == 0) {
1444817466cbSJens Wiklander /*
1445817466cbSJens Wiklander * Was PEM encoded
1446817466cbSJens Wiklander */
1447817466cbSJens Wiklander buflen -= use_len;
1448817466cbSJens Wiklander buf += use_len;
144932b31808SJens Wiklander } else if (ret == MBEDTLS_ERR_PEM_BAD_INPUT_DATA) {
145032b31808SJens Wiklander return ret;
145132b31808SJens Wiklander } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
1452817466cbSJens Wiklander mbedtls_pem_free(&pem);
1453817466cbSJens Wiklander
1454817466cbSJens Wiklander /*
1455817466cbSJens Wiklander * PEM header and footer were found
1456817466cbSJens Wiklander */
1457817466cbSJens Wiklander buflen -= use_len;
1458817466cbSJens Wiklander buf += use_len;
1459817466cbSJens Wiklander
146032b31808SJens Wiklander if (first_error == 0) {
1461817466cbSJens Wiklander first_error = ret;
146232b31808SJens Wiklander }
1463817466cbSJens Wiklander
1464817466cbSJens Wiklander total_failed++;
1465817466cbSJens Wiklander continue;
146632b31808SJens Wiklander } else {
1467817466cbSJens Wiklander break;
146832b31808SJens Wiklander }
1469817466cbSJens Wiklander
1470817466cbSJens Wiklander ret = mbedtls_x509_crt_parse_der(chain, pem.buf, pem.buflen);
1471817466cbSJens Wiklander
1472817466cbSJens Wiklander mbedtls_pem_free(&pem);
1473817466cbSJens Wiklander
147432b31808SJens Wiklander if (ret != 0) {
1475817466cbSJens Wiklander /*
1476817466cbSJens Wiklander * Quit parsing on a memory error
1477817466cbSJens Wiklander */
147832b31808SJens Wiklander if (ret == MBEDTLS_ERR_X509_ALLOC_FAILED) {
147932b31808SJens Wiklander return ret;
148032b31808SJens Wiklander }
1481817466cbSJens Wiklander
148232b31808SJens Wiklander if (first_error == 0) {
1483817466cbSJens Wiklander first_error = ret;
148432b31808SJens Wiklander }
1485817466cbSJens Wiklander
1486817466cbSJens Wiklander total_failed++;
1487817466cbSJens Wiklander continue;
1488817466cbSJens Wiklander }
1489817466cbSJens Wiklander
1490817466cbSJens Wiklander success = 1;
1491817466cbSJens Wiklander }
1492817466cbSJens Wiklander }
1493817466cbSJens Wiklander
149432b31808SJens Wiklander if (success) {
149532b31808SJens Wiklander return total_failed;
149632b31808SJens Wiklander } else if (first_error) {
149732b31808SJens Wiklander return first_error;
149832b31808SJens Wiklander } else {
149932b31808SJens Wiklander return MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT;
150032b31808SJens Wiklander }
1501817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */
1502817466cbSJens Wiklander }
1503817466cbSJens Wiklander
1504817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
1505817466cbSJens Wiklander /*
1506817466cbSJens Wiklander * Load one or more certificates and add them to the chained list
1507817466cbSJens Wiklander */
mbedtls_x509_crt_parse_file(mbedtls_x509_crt * chain,const char * path)1508817466cbSJens Wiklander int mbedtls_x509_crt_parse_file(mbedtls_x509_crt *chain, const char *path)
1509817466cbSJens Wiklander {
151011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1511817466cbSJens Wiklander size_t n;
1512817466cbSJens Wiklander unsigned char *buf;
1513817466cbSJens Wiklander
151432b31808SJens Wiklander if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
151532b31808SJens Wiklander return ret;
151632b31808SJens Wiklander }
1517817466cbSJens Wiklander
1518817466cbSJens Wiklander ret = mbedtls_x509_crt_parse(chain, buf, n);
1519817466cbSJens Wiklander
1520b0563631STom Van Eyck mbedtls_zeroize_and_free(buf, n);
1521817466cbSJens Wiklander
152232b31808SJens Wiklander return ret;
1523817466cbSJens Wiklander }
1524817466cbSJens Wiklander
mbedtls_x509_crt_parse_path(mbedtls_x509_crt * chain,const char * path)1525817466cbSJens Wiklander int mbedtls_x509_crt_parse_path(mbedtls_x509_crt *chain, const char *path)
1526817466cbSJens Wiklander {
1527817466cbSJens Wiklander int ret = 0;
1528817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
1529817466cbSJens Wiklander int w_ret;
1530817466cbSJens Wiklander WCHAR szDir[MAX_PATH];
1531817466cbSJens Wiklander char filename[MAX_PATH];
1532817466cbSJens Wiklander char *p;
1533817466cbSJens Wiklander size_t len = strlen(path);
1534817466cbSJens Wiklander
1535817466cbSJens Wiklander WIN32_FIND_DATAW file_data;
1536817466cbSJens Wiklander HANDLE hFind;
1537817466cbSJens Wiklander
153832b31808SJens Wiklander if (len > MAX_PATH - 3) {
153932b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
154032b31808SJens Wiklander }
1541817466cbSJens Wiklander
1542817466cbSJens Wiklander memset(szDir, 0, sizeof(szDir));
1543817466cbSJens Wiklander memset(filename, 0, MAX_PATH);
1544817466cbSJens Wiklander memcpy(filename, path, len);
1545817466cbSJens Wiklander filename[len++] = '\\';
1546817466cbSJens Wiklander p = filename + len;
1547817466cbSJens Wiklander filename[len++] = '*';
1548817466cbSJens Wiklander
1549b0563631STom Van Eyck /*
1550b0563631STom Van Eyck * Note this function uses the code page CP_ACP which is the system default
1551b0563631STom Van Eyck * ANSI codepage. The input string is always described in BYTES and the
1552b0563631STom Van Eyck * output length is described in WCHARs.
1553b0563631STom Van Eyck */
1554817466cbSJens Wiklander w_ret = MultiByteToWideChar(CP_ACP, 0, filename, (int) len, szDir,
1555817466cbSJens Wiklander MAX_PATH - 3);
155632b31808SJens Wiklander if (w_ret == 0) {
155732b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
155832b31808SJens Wiklander }
1559817466cbSJens Wiklander
1560817466cbSJens Wiklander hFind = FindFirstFileW(szDir, &file_data);
156132b31808SJens Wiklander if (hFind == INVALID_HANDLE_VALUE) {
156232b31808SJens Wiklander return MBEDTLS_ERR_X509_FILE_IO_ERROR;
156332b31808SJens Wiklander }
1564817466cbSJens Wiklander
1565817466cbSJens Wiklander len = MAX_PATH - len;
156632b31808SJens Wiklander do {
1567817466cbSJens Wiklander memset(p, 0, len);
1568817466cbSJens Wiklander
156932b31808SJens Wiklander if (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1570817466cbSJens Wiklander continue;
157132b31808SJens Wiklander }
1572817466cbSJens Wiklander w_ret = WideCharToMultiByte(CP_ACP, 0, file_data.cFileName,
1573b0563631STom Van Eyck -1, p, (int) len, NULL, NULL);
157432b31808SJens Wiklander if (w_ret == 0) {
1575817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
1576817466cbSJens Wiklander goto cleanup;
1577817466cbSJens Wiklander }
1578817466cbSJens Wiklander
1579817466cbSJens Wiklander w_ret = mbedtls_x509_crt_parse_file(chain, filename);
158032b31808SJens Wiklander if (w_ret < 0) {
1581817466cbSJens Wiklander ret++;
158232b31808SJens Wiklander } else {
1583817466cbSJens Wiklander ret += w_ret;
1584817466cbSJens Wiklander }
158532b31808SJens Wiklander } while (FindNextFileW(hFind, &file_data) != 0);
1586817466cbSJens Wiklander
158732b31808SJens Wiklander if (GetLastError() != ERROR_NO_MORE_FILES) {
1588817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
158932b31808SJens Wiklander }
1590817466cbSJens Wiklander
1591817466cbSJens Wiklander cleanup:
1592817466cbSJens Wiklander FindClose(hFind);
1593817466cbSJens Wiklander #else /* _WIN32 */
1594817466cbSJens Wiklander int t_ret;
1595817466cbSJens Wiklander int snp_ret;
1596817466cbSJens Wiklander struct stat sb;
1597817466cbSJens Wiklander struct dirent *entry;
1598817466cbSJens Wiklander char entry_name[MBEDTLS_X509_MAX_FILE_PATH_LEN];
1599817466cbSJens Wiklander DIR *dir = opendir(path);
1600817466cbSJens Wiklander
160132b31808SJens Wiklander if (dir == NULL) {
160232b31808SJens Wiklander return MBEDTLS_ERR_X509_FILE_IO_ERROR;
160332b31808SJens Wiklander }
1604817466cbSJens Wiklander
1605817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
160632b31808SJens Wiklander if ((ret = mbedtls_mutex_lock(&mbedtls_threading_readdir_mutex)) != 0) {
1607817466cbSJens Wiklander closedir(dir);
160832b31808SJens Wiklander return ret;
1609817466cbSJens Wiklander }
1610817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */
1611817466cbSJens Wiklander
16127901324dSJerome Forissier memset(&sb, 0, sizeof(sb));
16137901324dSJerome Forissier
161432b31808SJens Wiklander while ((entry = readdir(dir)) != NULL) {
161532b31808SJens Wiklander snp_ret = mbedtls_snprintf(entry_name, sizeof(entry_name),
1616817466cbSJens Wiklander "%s/%s", path, entry->d_name);
1617817466cbSJens Wiklander
161832b31808SJens Wiklander if (snp_ret < 0 || (size_t) snp_ret >= sizeof(entry_name)) {
1619817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
1620817466cbSJens Wiklander goto cleanup;
162132b31808SJens Wiklander } else if (stat(entry_name, &sb) == -1) {
162232b31808SJens Wiklander if (errno == ENOENT) {
162332b31808SJens Wiklander /* Broken symbolic link - ignore this entry.
162432b31808SJens Wiklander stat(2) will return this error for either (a) a dangling
162532b31808SJens Wiklander symlink or (b) a missing file.
162632b31808SJens Wiklander Given that we have just obtained the filename from readdir,
162732b31808SJens Wiklander assume that it does exist and therefore treat this as a
162832b31808SJens Wiklander dangling symlink. */
162932b31808SJens Wiklander continue;
163032b31808SJens Wiklander } else {
163132b31808SJens Wiklander /* Some other file error; report the error. */
1632817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
1633817466cbSJens Wiklander goto cleanup;
1634817466cbSJens Wiklander }
163532b31808SJens Wiklander }
1636817466cbSJens Wiklander
163732b31808SJens Wiklander if (!S_ISREG(sb.st_mode)) {
1638817466cbSJens Wiklander continue;
163932b31808SJens Wiklander }
1640817466cbSJens Wiklander
1641817466cbSJens Wiklander // Ignore parse errors
1642817466cbSJens Wiklander //
1643817466cbSJens Wiklander t_ret = mbedtls_x509_crt_parse_file(chain, entry_name);
164432b31808SJens Wiklander if (t_ret < 0) {
1645817466cbSJens Wiklander ret++;
164632b31808SJens Wiklander } else {
1647817466cbSJens Wiklander ret += t_ret;
1648817466cbSJens Wiklander }
164932b31808SJens Wiklander }
1650817466cbSJens Wiklander
1651817466cbSJens Wiklander cleanup:
1652817466cbSJens Wiklander closedir(dir);
1653817466cbSJens Wiklander
1654817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
165532b31808SJens Wiklander if (mbedtls_mutex_unlock(&mbedtls_threading_readdir_mutex) != 0) {
1656817466cbSJens Wiklander ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR;
165732b31808SJens Wiklander }
1658817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */
1659817466cbSJens Wiklander
1660817466cbSJens Wiklander #endif /* _WIN32 */
1661817466cbSJens Wiklander
166232b31808SJens Wiklander return ret;
1663817466cbSJens Wiklander }
1664817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
1665817466cbSJens Wiklander
166632b31808SJens Wiklander #if !defined(MBEDTLS_X509_REMOVE_INFO)
1667b0563631STom Van Eyck #define PRINT_ITEM(i) \
1668b0563631STom Van Eyck do { \
1669b0563631STom Van Eyck ret = mbedtls_snprintf(p, n, "%s" i, sep); \
1670b0563631STom Van Eyck MBEDTLS_X509_SAFE_SNPRINTF; \
1671b0563631STom Van Eyck sep = ", "; \
1672b0563631STom Van Eyck } while (0)
1673b0563631STom Van Eyck
1674b0563631STom Van Eyck #define CERT_TYPE(type, name) \
1675b0563631STom Van Eyck do { \
1676b0563631STom Van Eyck if (ns_cert_type & (type)) { \
1677b0563631STom Van Eyck PRINT_ITEM(name); \
1678b0563631STom Van Eyck } \
1679b0563631STom Van Eyck } while (0)
1680b0563631STom Van Eyck
1681b0563631STom Van Eyck #define KEY_USAGE(code, name) \
1682b0563631STom Van Eyck do { \
1683b0563631STom Van Eyck if (key_usage & (code)) { \
1684b0563631STom Van Eyck PRINT_ITEM(name); \
1685b0563631STom Van Eyck } \
1686b0563631STom Van Eyck } while (0)
1687b0563631STom Van Eyck
x509_info_ext_key_usage(char ** buf,size_t * size,const mbedtls_x509_sequence * extended_key_usage)1688817466cbSJens Wiklander static int x509_info_ext_key_usage(char **buf, size_t *size,
1689817466cbSJens Wiklander const mbedtls_x509_sequence *extended_key_usage)
1690817466cbSJens Wiklander {
169111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1692817466cbSJens Wiklander const char *desc;
1693817466cbSJens Wiklander size_t n = *size;
1694817466cbSJens Wiklander char *p = *buf;
1695817466cbSJens Wiklander const mbedtls_x509_sequence *cur = extended_key_usage;
1696817466cbSJens Wiklander const char *sep = "";
1697817466cbSJens Wiklander
169832b31808SJens Wiklander while (cur != NULL) {
169932b31808SJens Wiklander if (mbedtls_oid_get_extended_key_usage(&cur->buf, &desc) != 0) {
1700817466cbSJens Wiklander desc = "???";
170132b31808SJens Wiklander }
1702817466cbSJens Wiklander
1703817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%s%s", sep, desc);
1704817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1705817466cbSJens Wiklander
1706817466cbSJens Wiklander sep = ", ";
1707817466cbSJens Wiklander
1708817466cbSJens Wiklander cur = cur->next;
1709817466cbSJens Wiklander }
1710817466cbSJens Wiklander
1711817466cbSJens Wiklander *size = n;
1712817466cbSJens Wiklander *buf = p;
1713817466cbSJens Wiklander
171432b31808SJens Wiklander return 0;
1715817466cbSJens Wiklander }
1716817466cbSJens Wiklander
x509_info_cert_policies(char ** buf,size_t * size,const mbedtls_x509_sequence * certificate_policies)171711fa71b9SJerome Forissier static int x509_info_cert_policies(char **buf, size_t *size,
171811fa71b9SJerome Forissier const mbedtls_x509_sequence *certificate_policies)
171911fa71b9SJerome Forissier {
172011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
172111fa71b9SJerome Forissier const char *desc;
172211fa71b9SJerome Forissier size_t n = *size;
172311fa71b9SJerome Forissier char *p = *buf;
172411fa71b9SJerome Forissier const mbedtls_x509_sequence *cur = certificate_policies;
172511fa71b9SJerome Forissier const char *sep = "";
172611fa71b9SJerome Forissier
172732b31808SJens Wiklander while (cur != NULL) {
172832b31808SJens Wiklander if (mbedtls_oid_get_certificate_policies(&cur->buf, &desc) != 0) {
172911fa71b9SJerome Forissier desc = "???";
173032b31808SJens Wiklander }
173111fa71b9SJerome Forissier
173211fa71b9SJerome Forissier ret = mbedtls_snprintf(p, n, "%s%s", sep, desc);
173311fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF;
173411fa71b9SJerome Forissier
173511fa71b9SJerome Forissier sep = ", ";
173611fa71b9SJerome Forissier
173711fa71b9SJerome Forissier cur = cur->next;
173811fa71b9SJerome Forissier }
173911fa71b9SJerome Forissier
174011fa71b9SJerome Forissier *size = n;
174111fa71b9SJerome Forissier *buf = p;
174211fa71b9SJerome Forissier
174332b31808SJens Wiklander return 0;
174411fa71b9SJerome Forissier }
174511fa71b9SJerome Forissier
1746817466cbSJens Wiklander /*
1747817466cbSJens Wiklander * Return an informational string about the certificate.
1748817466cbSJens Wiklander */
1749817466cbSJens Wiklander #define BEFORE_COLON 18
1750817466cbSJens Wiklander #define BC "18"
mbedtls_x509_crt_info(char * buf,size_t size,const char * prefix,const mbedtls_x509_crt * crt)1751817466cbSJens Wiklander int mbedtls_x509_crt_info(char *buf, size_t size, const char *prefix,
1752817466cbSJens Wiklander const mbedtls_x509_crt *crt)
1753817466cbSJens Wiklander {
175411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1755817466cbSJens Wiklander size_t n;
1756817466cbSJens Wiklander char *p;
1757817466cbSJens Wiklander char key_size_str[BEFORE_COLON];
1758817466cbSJens Wiklander
1759817466cbSJens Wiklander p = buf;
1760817466cbSJens Wiklander n = size;
1761817466cbSJens Wiklander
176232b31808SJens Wiklander if (NULL == crt) {
1763817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\nCertificate is uninitialised!\n");
1764817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1765817466cbSJens Wiklander
176632b31808SJens Wiklander return (int) (size - n);
1767817466cbSJens Wiklander }
1768817466cbSJens Wiklander
1769817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%scert. version : %d\n",
1770817466cbSJens Wiklander prefix, crt->version);
1771817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1772817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%sserial number : ",
1773817466cbSJens Wiklander prefix);
1774817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1775817466cbSJens Wiklander
1776817466cbSJens Wiklander ret = mbedtls_x509_serial_gets(p, n, &crt->serial);
1777817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1778817466cbSJens Wiklander
1779817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sissuer name : ", prefix);
1780817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1781817466cbSJens Wiklander ret = mbedtls_x509_dn_gets(p, n, &crt->issuer);
1782817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1783817466cbSJens Wiklander
1784817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssubject name : ", prefix);
1785817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1786817466cbSJens Wiklander ret = mbedtls_x509_dn_gets(p, n, &crt->subject);
1787817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1788817466cbSJens Wiklander
1789817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sissued on : " \
1790817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix,
1791817466cbSJens Wiklander crt->valid_from.year, crt->valid_from.mon,
1792817466cbSJens Wiklander crt->valid_from.day, crt->valid_from.hour,
1793817466cbSJens Wiklander crt->valid_from.min, crt->valid_from.sec);
1794817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1795817466cbSJens Wiklander
1796817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sexpires on : " \
1797817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix,
1798817466cbSJens Wiklander crt->valid_to.year, crt->valid_to.mon,
1799817466cbSJens Wiklander crt->valid_to.day, crt->valid_to.hour,
1800817466cbSJens Wiklander crt->valid_to.min, crt->valid_to.sec);
1801817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1802817466cbSJens Wiklander
1803817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssigned using : ", prefix);
1804817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1805817466cbSJens Wiklander
1806817466cbSJens Wiklander ret = mbedtls_x509_sig_alg_gets(p, n, &crt->sig_oid, crt->sig_pk,
1807817466cbSJens Wiklander crt->sig_md, crt->sig_opts);
1808817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1809817466cbSJens Wiklander
1810817466cbSJens Wiklander /* Key size */
1811817466cbSJens Wiklander if ((ret = mbedtls_x509_key_size_helper(key_size_str, BEFORE_COLON,
181232b31808SJens Wiklander mbedtls_pk_get_name(&crt->pk))) != 0) {
181332b31808SJens Wiklander return ret;
1814817466cbSJens Wiklander }
1815817466cbSJens Wiklander
1816817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str,
1817817466cbSJens Wiklander (int) mbedtls_pk_get_bitlen(&crt->pk));
1818817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1819817466cbSJens Wiklander
1820817466cbSJens Wiklander /*
1821817466cbSJens Wiklander * Optional extensions
1822817466cbSJens Wiklander */
1823817466cbSJens Wiklander
182432b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS) {
1825817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sbasic constraints : CA=%s", prefix,
1826817466cbSJens Wiklander crt->ca_istrue ? "true" : "false");
1827817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1828817466cbSJens Wiklander
182932b31808SJens Wiklander if (crt->max_pathlen > 0) {
1830817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, ", max_pathlen=%d", crt->max_pathlen - 1);
1831817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1832817466cbSJens Wiklander }
1833817466cbSJens Wiklander }
1834817466cbSJens Wiklander
183532b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) {
1836817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssubject alt name :", prefix);
1837817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1838817466cbSJens Wiklander
183932b31808SJens Wiklander if ((ret = mbedtls_x509_info_subject_alt_name(&p, &n,
184011fa71b9SJerome Forissier &crt->subject_alt_names,
184132b31808SJens Wiklander prefix)) != 0) {
184232b31808SJens Wiklander return ret;
184332b31808SJens Wiklander }
1844817466cbSJens Wiklander }
1845817466cbSJens Wiklander
184632b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) {
1847817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%scert. type : ", prefix);
1848817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1849817466cbSJens Wiklander
185032b31808SJens Wiklander if ((ret = mbedtls_x509_info_cert_type(&p, &n, crt->ns_cert_type)) != 0) {
185132b31808SJens Wiklander return ret;
185232b31808SJens Wiklander }
1853817466cbSJens Wiklander }
1854817466cbSJens Wiklander
185532b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE) {
1856817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%skey usage : ", prefix);
1857817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1858817466cbSJens Wiklander
185932b31808SJens Wiklander if ((ret = mbedtls_x509_info_key_usage(&p, &n, crt->key_usage)) != 0) {
186032b31808SJens Wiklander return ret;
186132b31808SJens Wiklander }
1862817466cbSJens Wiklander }
1863817466cbSJens Wiklander
186432b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE) {
1865817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%sext key usage : ", prefix);
1866817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1867817466cbSJens Wiklander
1868817466cbSJens Wiklander if ((ret = x509_info_ext_key_usage(&p, &n,
186932b31808SJens Wiklander &crt->ext_key_usage)) != 0) {
187032b31808SJens Wiklander return ret;
187132b31808SJens Wiklander }
1872817466cbSJens Wiklander }
1873817466cbSJens Wiklander
187432b31808SJens Wiklander if (crt->ext_types & MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES) {
187511fa71b9SJerome Forissier ret = mbedtls_snprintf(p, n, "\n%scertificate policies : ", prefix);
187611fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF;
187711fa71b9SJerome Forissier
187811fa71b9SJerome Forissier if ((ret = x509_info_cert_policies(&p, &n,
187932b31808SJens Wiklander &crt->certificate_policies)) != 0) {
188032b31808SJens Wiklander return ret;
188132b31808SJens Wiklander }
188211fa71b9SJerome Forissier }
188311fa71b9SJerome Forissier
1884817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n");
1885817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1886817466cbSJens Wiklander
188732b31808SJens Wiklander return (int) (size - n);
1888817466cbSJens Wiklander }
1889817466cbSJens Wiklander
1890817466cbSJens Wiklander struct x509_crt_verify_string {
1891817466cbSJens Wiklander int code;
1892817466cbSJens Wiklander const char *string;
1893817466cbSJens Wiklander };
1894817466cbSJens Wiklander
189532b31808SJens Wiklander #define X509_CRT_ERROR_INFO(err, err_str, info) { err, info },
1896817466cbSJens Wiklander static const struct x509_crt_verify_string x509_crt_verify_strings[] = {
189732b31808SJens Wiklander MBEDTLS_X509_CRT_ERROR_INFO_LIST
1898817466cbSJens Wiklander { 0, NULL }
1899817466cbSJens Wiklander };
190032b31808SJens Wiklander #undef X509_CRT_ERROR_INFO
1901817466cbSJens Wiklander
mbedtls_x509_crt_verify_info(char * buf,size_t size,const char * prefix,uint32_t flags)1902817466cbSJens Wiklander int mbedtls_x509_crt_verify_info(char *buf, size_t size, const char *prefix,
1903817466cbSJens Wiklander uint32_t flags)
1904817466cbSJens Wiklander {
190511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1906817466cbSJens Wiklander const struct x509_crt_verify_string *cur;
1907817466cbSJens Wiklander char *p = buf;
1908817466cbSJens Wiklander size_t n = size;
1909817466cbSJens Wiklander
191032b31808SJens Wiklander for (cur = x509_crt_verify_strings; cur->string != NULL; cur++) {
191132b31808SJens Wiklander if ((flags & cur->code) == 0) {
1912817466cbSJens Wiklander continue;
191332b31808SJens Wiklander }
1914817466cbSJens Wiklander
1915817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%s%s\n", prefix, cur->string);
1916817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1917817466cbSJens Wiklander flags ^= cur->code;
1918817466cbSJens Wiklander }
1919817466cbSJens Wiklander
192032b31808SJens Wiklander if (flags != 0) {
1921817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%sUnknown reason "
1922817466cbSJens Wiklander "(this should not happen)\n", prefix);
1923817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF;
1924817466cbSJens Wiklander }
1925817466cbSJens Wiklander
192632b31808SJens Wiklander return (int) (size - n);
1927817466cbSJens Wiklander }
192832b31808SJens Wiklander #endif /* MBEDTLS_X509_REMOVE_INFO */
1929817466cbSJens Wiklander
mbedtls_x509_crt_check_key_usage(const mbedtls_x509_crt * crt,unsigned int usage)1930817466cbSJens Wiklander int mbedtls_x509_crt_check_key_usage(const mbedtls_x509_crt *crt,
1931817466cbSJens Wiklander unsigned int usage)
1932817466cbSJens Wiklander {
1933817466cbSJens Wiklander unsigned int usage_must, usage_may;
1934817466cbSJens Wiklander unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY
1935817466cbSJens Wiklander | MBEDTLS_X509_KU_DECIPHER_ONLY;
1936817466cbSJens Wiklander
193732b31808SJens Wiklander if ((crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE) == 0) {
193832b31808SJens Wiklander return 0;
193932b31808SJens Wiklander }
1940817466cbSJens Wiklander
1941817466cbSJens Wiklander usage_must = usage & ~may_mask;
1942817466cbSJens Wiklander
194332b31808SJens Wiklander if (((crt->key_usage & ~may_mask) & usage_must) != usage_must) {
194432b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
194532b31808SJens Wiklander }
1946817466cbSJens Wiklander
1947817466cbSJens Wiklander usage_may = usage & may_mask;
1948817466cbSJens Wiklander
194932b31808SJens Wiklander if (((crt->key_usage & may_mask) | usage_may) != usage_may) {
195032b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
1951817466cbSJens Wiklander }
1952817466cbSJens Wiklander
195332b31808SJens Wiklander return 0;
195432b31808SJens Wiklander }
195532b31808SJens Wiklander
mbedtls_x509_crt_check_extended_key_usage(const mbedtls_x509_crt * crt,const char * usage_oid,size_t usage_len)1956817466cbSJens Wiklander int mbedtls_x509_crt_check_extended_key_usage(const mbedtls_x509_crt *crt,
1957817466cbSJens Wiklander const char *usage_oid,
1958817466cbSJens Wiklander size_t usage_len)
1959817466cbSJens Wiklander {
1960817466cbSJens Wiklander const mbedtls_x509_sequence *cur;
1961817466cbSJens Wiklander
1962817466cbSJens Wiklander /* Extension is not mandatory, absent means no restriction */
196332b31808SJens Wiklander if ((crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE) == 0) {
196432b31808SJens Wiklander return 0;
196532b31808SJens Wiklander }
1966817466cbSJens Wiklander
1967817466cbSJens Wiklander /*
1968817466cbSJens Wiklander * Look for the requested usage (or wildcard ANY) in our list
1969817466cbSJens Wiklander */
197032b31808SJens Wiklander for (cur = &crt->ext_key_usage; cur != NULL; cur = cur->next) {
1971817466cbSJens Wiklander const mbedtls_x509_buf *cur_oid = &cur->buf;
1972817466cbSJens Wiklander
1973817466cbSJens Wiklander if (cur_oid->len == usage_len &&
197432b31808SJens Wiklander memcmp(cur_oid->p, usage_oid, usage_len) == 0) {
197532b31808SJens Wiklander return 0;
1976817466cbSJens Wiklander }
1977817466cbSJens Wiklander
197832b31808SJens Wiklander if (MBEDTLS_OID_CMP(MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid) == 0) {
197932b31808SJens Wiklander return 0;
198032b31808SJens Wiklander }
1981817466cbSJens Wiklander }
1982817466cbSJens Wiklander
198332b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
1984817466cbSJens Wiklander }
1985817466cbSJens Wiklander
1986817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C)
1987817466cbSJens Wiklander /*
1988817466cbSJens Wiklander * Return 1 if the certificate is revoked, or 0 otherwise.
1989817466cbSJens Wiklander */
mbedtls_x509_crt_is_revoked(const mbedtls_x509_crt * crt,const mbedtls_x509_crl * crl)1990817466cbSJens Wiklander int mbedtls_x509_crt_is_revoked(const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl)
1991817466cbSJens Wiklander {
1992817466cbSJens Wiklander const mbedtls_x509_crl_entry *cur = &crl->entry;
1993817466cbSJens Wiklander
199432b31808SJens Wiklander while (cur != NULL && cur->serial.len != 0) {
1995817466cbSJens Wiklander if (crt->serial.len == cur->serial.len &&
199632b31808SJens Wiklander memcmp(crt->serial.p, cur->serial.p, crt->serial.len) == 0) {
199732b31808SJens Wiklander return 1;
1998817466cbSJens Wiklander }
1999817466cbSJens Wiklander
2000817466cbSJens Wiklander cur = cur->next;
2001817466cbSJens Wiklander }
2002817466cbSJens Wiklander
200332b31808SJens Wiklander return 0;
2004817466cbSJens Wiklander }
2005817466cbSJens Wiklander
2006817466cbSJens Wiklander /*
2007817466cbSJens Wiklander * Check that the given certificate is not revoked according to the CRL.
20083d3b0591SJens Wiklander * Skip validation if no CRL for the given CA is present.
2009817466cbSJens Wiklander */
x509_crt_verifycrl(mbedtls_x509_crt * crt,mbedtls_x509_crt * ca,mbedtls_x509_crl * crl_list,const mbedtls_x509_crt_profile * profile,const mbedtls_x509_time * now)2010817466cbSJens Wiklander static int x509_crt_verifycrl(mbedtls_x509_crt *crt, mbedtls_x509_crt *ca,
2011817466cbSJens Wiklander mbedtls_x509_crl *crl_list,
2012b0563631STom Van Eyck const mbedtls_x509_crt_profile *profile,
2013b0563631STom Van Eyck const mbedtls_x509_time *now)
2014817466cbSJens Wiklander {
2015817466cbSJens Wiklander int flags = 0;
2016b0563631STom Van Eyck unsigned char hash[MBEDTLS_MD_MAX_SIZE];
201732b31808SJens Wiklander #if defined(MBEDTLS_USE_PSA_CRYPTO)
201832b31808SJens Wiklander psa_algorithm_t psa_algorithm;
201932b31808SJens Wiklander #else
2020817466cbSJens Wiklander const mbedtls_md_info_t *md_info;
202132b31808SJens Wiklander #endif /* MBEDTLS_USE_PSA_CRYPTO */
202232b31808SJens Wiklander size_t hash_length;
2023817466cbSJens Wiklander
202432b31808SJens Wiklander if (ca == NULL) {
202532b31808SJens Wiklander return flags;
202632b31808SJens Wiklander }
2027817466cbSJens Wiklander
202832b31808SJens Wiklander while (crl_list != NULL) {
2029817466cbSJens Wiklander if (crl_list->version == 0 ||
203032b31808SJens Wiklander x509_name_cmp(&crl_list->issuer, &ca->subject) != 0) {
2031817466cbSJens Wiklander crl_list = crl_list->next;
2032817466cbSJens Wiklander continue;
2033817466cbSJens Wiklander }
2034817466cbSJens Wiklander
2035817466cbSJens Wiklander /*
2036817466cbSJens Wiklander * Check if the CA is configured to sign CRLs
2037817466cbSJens Wiklander */
20383d3b0591SJens Wiklander if (mbedtls_x509_crt_check_key_usage(ca,
203932b31808SJens Wiklander MBEDTLS_X509_KU_CRL_SIGN) != 0) {
2040817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED;
2041817466cbSJens Wiklander break;
2042817466cbSJens Wiklander }
2043817466cbSJens Wiklander
2044817466cbSJens Wiklander /*
2045817466cbSJens Wiklander * Check if CRL is correctly signed by the trusted CA
2046817466cbSJens Wiklander */
204732b31808SJens Wiklander if (x509_profile_check_md_alg(profile, crl_list->sig_md) != 0) {
2048817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_MD;
204932b31808SJens Wiklander }
2050817466cbSJens Wiklander
205132b31808SJens Wiklander if (x509_profile_check_pk_alg(profile, crl_list->sig_pk) != 0) {
2052817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_PK;
205332b31808SJens Wiklander }
2054817466cbSJens Wiklander
205532b31808SJens Wiklander #if defined(MBEDTLS_USE_PSA_CRYPTO)
2056b0563631STom Van Eyck psa_algorithm = mbedtls_md_psa_alg_from_type(crl_list->sig_md);
205732b31808SJens Wiklander if (psa_hash_compute(psa_algorithm,
205832b31808SJens Wiklander crl_list->tbs.p,
205932b31808SJens Wiklander crl_list->tbs.len,
206032b31808SJens Wiklander hash,
206132b31808SJens Wiklander sizeof(hash),
206232b31808SJens Wiklander &hash_length) != PSA_SUCCESS) {
20633d3b0591SJens Wiklander /* Note: this can't happen except after an internal error */
2064817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED;
2065817466cbSJens Wiklander break;
2066817466cbSJens Wiklander }
206732b31808SJens Wiklander #else
206832b31808SJens Wiklander md_info = mbedtls_md_info_from_type(crl_list->sig_md);
206932b31808SJens Wiklander hash_length = mbedtls_md_get_size(md_info);
207032b31808SJens Wiklander if (mbedtls_md(md_info,
207132b31808SJens Wiklander crl_list->tbs.p,
207232b31808SJens Wiklander crl_list->tbs.len,
207332b31808SJens Wiklander hash) != 0) {
207432b31808SJens Wiklander /* Note: this can't happen except after an internal error */
207532b31808SJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED;
207632b31808SJens Wiklander break;
207732b31808SJens Wiklander }
207832b31808SJens Wiklander #endif /* MBEDTLS_USE_PSA_CRYPTO */
2079817466cbSJens Wiklander
208032b31808SJens Wiklander if (x509_profile_check_key(profile, &ca->pk) != 0) {
2081817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
208232b31808SJens Wiklander }
2083817466cbSJens Wiklander
2084817466cbSJens Wiklander if (mbedtls_pk_verify_ext(crl_list->sig_pk, crl_list->sig_opts, &ca->pk,
208532b31808SJens Wiklander crl_list->sig_md, hash, hash_length,
208632b31808SJens Wiklander crl_list->sig.p, crl_list->sig.len) != 0) {
2087817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED;
2088817466cbSJens Wiklander break;
2089817466cbSJens Wiklander }
2090817466cbSJens Wiklander
2091b0563631STom Van Eyck #if defined(MBEDTLS_HAVE_TIME_DATE)
2092817466cbSJens Wiklander /*
2093817466cbSJens Wiklander * Check for validity of CRL (Do not drop out)
2094817466cbSJens Wiklander */
2095b0563631STom Van Eyck if (mbedtls_x509_time_cmp(&crl_list->next_update, now) < 0) {
2096817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_EXPIRED;
209732b31808SJens Wiklander }
2098817466cbSJens Wiklander
2099b0563631STom Van Eyck if (mbedtls_x509_time_cmp(&crl_list->this_update, now) > 0) {
2100817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_FUTURE;
210132b31808SJens Wiklander }
2102b0563631STom Van Eyck #else
2103b0563631STom Van Eyck ((void) now);
2104b0563631STom Van Eyck #endif
2105817466cbSJens Wiklander
2106817466cbSJens Wiklander /*
2107817466cbSJens Wiklander * Check if certificate is revoked
2108817466cbSJens Wiklander */
210932b31808SJens Wiklander if (mbedtls_x509_crt_is_revoked(crt, crl_list)) {
2110817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_REVOKED;
2111817466cbSJens Wiklander break;
2112817466cbSJens Wiklander }
2113817466cbSJens Wiklander
2114817466cbSJens Wiklander crl_list = crl_list->next;
2115817466cbSJens Wiklander }
2116817466cbSJens Wiklander
211732b31808SJens Wiklander return flags;
2118817466cbSJens Wiklander }
2119817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRL_PARSE_C */
2120817466cbSJens Wiklander
2121817466cbSJens Wiklander /*
21223d3b0591SJens Wiklander * Check the signature of a certificate by its parent
2123817466cbSJens Wiklander */
x509_crt_check_signature(const mbedtls_x509_crt * child,mbedtls_x509_crt * parent,mbedtls_x509_crt_restart_ctx * rs_ctx)21243d3b0591SJens Wiklander static int x509_crt_check_signature(const mbedtls_x509_crt *child,
21253d3b0591SJens Wiklander mbedtls_x509_crt *parent,
21263d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx)
2127817466cbSJens Wiklander {
212811fa71b9SJerome Forissier size_t hash_len;
2129b0563631STom Van Eyck unsigned char hash[MBEDTLS_MD_MAX_SIZE];
213011fa71b9SJerome Forissier #if !defined(MBEDTLS_USE_PSA_CRYPTO)
213111fa71b9SJerome Forissier const mbedtls_md_info_t *md_info;
21323d3b0591SJens Wiklander md_info = mbedtls_md_info_from_type(child->sig_md);
213311fa71b9SJerome Forissier hash_len = mbedtls_md_get_size(md_info);
213411fa71b9SJerome Forissier
213511fa71b9SJerome Forissier /* Note: hash errors can happen only after an internal error */
213632b31808SJens Wiklander if (mbedtls_md(md_info, child->tbs.p, child->tbs.len, hash) != 0) {
213732b31808SJens Wiklander return -1;
213832b31808SJens Wiklander }
213911fa71b9SJerome Forissier #else
2140b0563631STom Van Eyck psa_algorithm_t hash_alg = mbedtls_md_psa_alg_from_type(child->sig_md);
214132b31808SJens Wiklander psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
214211fa71b9SJerome Forissier
214332b31808SJens Wiklander status = psa_hash_compute(hash_alg,
214432b31808SJens Wiklander child->tbs.p,
214532b31808SJens Wiklander child->tbs.len,
214632b31808SJens Wiklander hash,
214732b31808SJens Wiklander sizeof(hash),
214832b31808SJens Wiklander &hash_len);
214932b31808SJens Wiklander if (status != PSA_SUCCESS) {
215032b31808SJens Wiklander return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED;
2151817466cbSJens Wiklander }
2152817466cbSJens Wiklander
215311fa71b9SJerome Forissier #endif /* MBEDTLS_USE_PSA_CRYPTO */
21543d3b0591SJens Wiklander /* Skip expensive computation on obvious mismatch */
215532b31808SJens Wiklander if (!mbedtls_pk_can_do(&parent->pk, child->sig_pk)) {
215632b31808SJens Wiklander return -1;
215732b31808SJens Wiklander }
2158817466cbSJens Wiklander
21593d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
216032b31808SJens Wiklander if (rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA) {
216132b31808SJens Wiklander return mbedtls_pk_verify_restartable(&parent->pk,
216211fa71b9SJerome Forissier child->sig_md, hash, hash_len,
216332b31808SJens Wiklander child->sig.p, child->sig.len, &rs_ctx->pk);
2164817466cbSJens Wiklander }
21653d3b0591SJens Wiklander #else
21663d3b0591SJens Wiklander (void) rs_ctx;
21673d3b0591SJens Wiklander #endif
2168817466cbSJens Wiklander
216932b31808SJens Wiklander return mbedtls_pk_verify_ext(child->sig_pk, child->sig_opts, &parent->pk,
217011fa71b9SJerome Forissier child->sig_md, hash, hash_len,
217132b31808SJens Wiklander child->sig.p, child->sig.len);
2172817466cbSJens Wiklander }
2173817466cbSJens Wiklander
2174817466cbSJens Wiklander /*
2175817466cbSJens Wiklander * Check if 'parent' is a suitable parent (signing CA) for 'child'.
2176817466cbSJens Wiklander * Return 0 if yes, -1 if not.
2177817466cbSJens Wiklander *
2178817466cbSJens Wiklander * top means parent is a locally-trusted certificate
2179817466cbSJens Wiklander */
x509_crt_check_parent(const mbedtls_x509_crt * child,const mbedtls_x509_crt * parent,int top)2180817466cbSJens Wiklander static int x509_crt_check_parent(const mbedtls_x509_crt *child,
2181817466cbSJens Wiklander const mbedtls_x509_crt *parent,
21823d3b0591SJens Wiklander int top)
2183817466cbSJens Wiklander {
2184817466cbSJens Wiklander int need_ca_bit;
2185817466cbSJens Wiklander
2186817466cbSJens Wiklander /* Parent must be the issuer */
218732b31808SJens Wiklander if (x509_name_cmp(&child->issuer, &parent->subject) != 0) {
218832b31808SJens Wiklander return -1;
218932b31808SJens Wiklander }
2190817466cbSJens Wiklander
2191817466cbSJens Wiklander /* Parent must have the basicConstraints CA bit set as a general rule */
2192817466cbSJens Wiklander need_ca_bit = 1;
2193817466cbSJens Wiklander
2194817466cbSJens Wiklander /* Exception: v1/v2 certificates that are locally trusted. */
219532b31808SJens Wiklander if (top && parent->version < 3) {
2196817466cbSJens Wiklander need_ca_bit = 0;
2197817466cbSJens Wiklander }
2198817466cbSJens Wiklander
219932b31808SJens Wiklander if (need_ca_bit && !parent->ca_istrue) {
220032b31808SJens Wiklander return -1;
220132b31808SJens Wiklander }
220232b31808SJens Wiklander
220332b31808SJens Wiklander if (need_ca_bit &&
220432b31808SJens Wiklander mbedtls_x509_crt_check_key_usage(parent, MBEDTLS_X509_KU_KEY_CERT_SIGN) != 0) {
220532b31808SJens Wiklander return -1;
220632b31808SJens Wiklander }
220732b31808SJens Wiklander
220832b31808SJens Wiklander return 0;
2209817466cbSJens Wiklander }
2210817466cbSJens Wiklander
22113d3b0591SJens Wiklander /*
22123d3b0591SJens Wiklander * Find a suitable parent for child in candidates, or return NULL.
22133d3b0591SJens Wiklander *
22143d3b0591SJens Wiklander * Here suitable is defined as:
22153d3b0591SJens Wiklander * 1. subject name matches child's issuer
22163d3b0591SJens Wiklander * 2. if necessary, the CA bit is set and key usage allows signing certs
22173d3b0591SJens Wiklander * 3. for trusted roots, the signature is correct
22183d3b0591SJens Wiklander * (for intermediates, the signature is checked and the result reported)
22193d3b0591SJens Wiklander * 4. pathlen constraints are satisfied
22203d3b0591SJens Wiklander *
22213d3b0591SJens Wiklander * If there's a suitable candidate which is also time-valid, return the first
22223d3b0591SJens Wiklander * such. Otherwise, return the first suitable candidate (or NULL if there is
22233d3b0591SJens Wiklander * none).
22243d3b0591SJens Wiklander *
22253d3b0591SJens Wiklander * The rationale for this rule is that someone could have a list of trusted
22263d3b0591SJens Wiklander * roots with two versions on the same root with different validity periods.
22273d3b0591SJens Wiklander * (At least one user reported having such a list and wanted it to just work.)
22283d3b0591SJens Wiklander * The reason we don't just require time-validity is that generally there is
22293d3b0591SJens Wiklander * only one version, and if it's expired we want the flags to state that
22303d3b0591SJens Wiklander * rather than NOT_TRUSTED, as would be the case if we required it here.
22313d3b0591SJens Wiklander *
22323d3b0591SJens Wiklander * The rationale for rule 3 (signature for trusted roots) is that users might
22333d3b0591SJens Wiklander * have two versions of the same CA with different keys in their list, and the
22343d3b0591SJens Wiklander * way we select the correct one is by checking the signature (as we don't
22353d3b0591SJens Wiklander * rely on key identifier extensions). (This is one way users might choose to
22363d3b0591SJens Wiklander * handle key rollover, another relies on self-issued certs, see [SIRO].)
22373d3b0591SJens Wiklander *
22383d3b0591SJens Wiklander * Arguments:
22393d3b0591SJens Wiklander * - [in] child: certificate for which we're looking for a parent
22403d3b0591SJens Wiklander * - [in] candidates: chained list of potential parents
22413d3b0591SJens Wiklander * - [out] r_parent: parent found (or NULL)
22423d3b0591SJens Wiklander * - [out] r_signature_is_good: 1 if child signature by parent is valid, or 0
22433d3b0591SJens Wiklander * - [in] top: 1 if candidates consists of trusted roots, ie we're at the top
22443d3b0591SJens Wiklander * of the chain, 0 otherwise
22453d3b0591SJens Wiklander * - [in] path_cnt: number of intermediates seen so far
22463d3b0591SJens Wiklander * - [in] self_cnt: number of self-signed intermediates seen so far
22473d3b0591SJens Wiklander * (will never be greater than path_cnt)
22483d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations
22493d3b0591SJens Wiklander *
22503d3b0591SJens Wiklander * Return value:
22513d3b0591SJens Wiklander * - 0 on success
22523d3b0591SJens Wiklander * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise
22533d3b0591SJens Wiklander */
x509_crt_find_parent_in(mbedtls_x509_crt * child,mbedtls_x509_crt * candidates,mbedtls_x509_crt ** r_parent,int * r_signature_is_good,int top,unsigned path_cnt,unsigned self_cnt,mbedtls_x509_crt_restart_ctx * rs_ctx,const mbedtls_x509_time * now)22543d3b0591SJens Wiklander static int x509_crt_find_parent_in(
22553d3b0591SJens Wiklander mbedtls_x509_crt *child,
22563d3b0591SJens Wiklander mbedtls_x509_crt *candidates,
22573d3b0591SJens Wiklander mbedtls_x509_crt **r_parent,
22583d3b0591SJens Wiklander int *r_signature_is_good,
22593d3b0591SJens Wiklander int top,
22603d3b0591SJens Wiklander unsigned path_cnt,
22613d3b0591SJens Wiklander unsigned self_cnt,
2262b0563631STom Van Eyck mbedtls_x509_crt_restart_ctx *rs_ctx,
2263b0563631STom Van Eyck const mbedtls_x509_time *now)
2264817466cbSJens Wiklander {
226511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
22663d3b0591SJens Wiklander mbedtls_x509_crt *parent, *fallback_parent;
226711fa71b9SJerome Forissier int signature_is_good = 0, fallback_signature_is_good;
2268817466cbSJens Wiklander
22693d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
22703d3b0591SJens Wiklander /* did we have something in progress? */
227132b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->parent != NULL) {
22723d3b0591SJens Wiklander /* restore saved state */
22733d3b0591SJens Wiklander parent = rs_ctx->parent;
22743d3b0591SJens Wiklander fallback_parent = rs_ctx->fallback_parent;
22753d3b0591SJens Wiklander fallback_signature_is_good = rs_ctx->fallback_signature_is_good;
22763d3b0591SJens Wiklander
22773d3b0591SJens Wiklander /* clear saved state */
22783d3b0591SJens Wiklander rs_ctx->parent = NULL;
22793d3b0591SJens Wiklander rs_ctx->fallback_parent = NULL;
22803d3b0591SJens Wiklander rs_ctx->fallback_signature_is_good = 0;
22813d3b0591SJens Wiklander
22823d3b0591SJens Wiklander /* resume where we left */
22833d3b0591SJens Wiklander goto check_signature;
2284817466cbSJens Wiklander }
22853d3b0591SJens Wiklander #endif
2286817466cbSJens Wiklander
22873d3b0591SJens Wiklander fallback_parent = NULL;
22883d3b0591SJens Wiklander fallback_signature_is_good = 0;
22893d3b0591SJens Wiklander
229032b31808SJens Wiklander for (parent = candidates; parent != NULL; parent = parent->next) {
22913d3b0591SJens Wiklander /* basic parenting skills (name, CA bit, key usage) */
229232b31808SJens Wiklander if (x509_crt_check_parent(child, parent, top) != 0) {
2293817466cbSJens Wiklander continue;
229432b31808SJens Wiklander }
2295817466cbSJens Wiklander
22963d3b0591SJens Wiklander /* +1 because stored max_pathlen is 1 higher that the actual value */
22973d3b0591SJens Wiklander if (parent->max_pathlen > 0 &&
229832b31808SJens Wiklander (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt) {
2299817466cbSJens Wiklander continue;
2300817466cbSJens Wiklander }
2301817466cbSJens Wiklander
23023d3b0591SJens Wiklander /* Signature */
23033d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
23043d3b0591SJens Wiklander check_signature:
23053d3b0591SJens Wiklander #endif
23063d3b0591SJens Wiklander ret = x509_crt_check_signature(child, parent, rs_ctx);
2307817466cbSJens Wiklander
23083d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
230932b31808SJens Wiklander if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
23103d3b0591SJens Wiklander /* save state */
23113d3b0591SJens Wiklander rs_ctx->parent = parent;
23123d3b0591SJens Wiklander rs_ctx->fallback_parent = fallback_parent;
23133d3b0591SJens Wiklander rs_ctx->fallback_signature_is_good = fallback_signature_is_good;
23143d3b0591SJens Wiklander
231532b31808SJens Wiklander return ret;
23163d3b0591SJens Wiklander }
23173d3b0591SJens Wiklander #else
23183d3b0591SJens Wiklander (void) ret;
23193d3b0591SJens Wiklander #endif
23203d3b0591SJens Wiklander
23213d3b0591SJens Wiklander signature_is_good = ret == 0;
232232b31808SJens Wiklander if (top && !signature_is_good) {
23233d3b0591SJens Wiklander continue;
232432b31808SJens Wiklander }
23253d3b0591SJens Wiklander
2326b0563631STom Van Eyck #if defined(MBEDTLS_HAVE_TIME_DATE)
23273d3b0591SJens Wiklander /* optional time check */
2328b0563631STom Van Eyck if (mbedtls_x509_time_cmp(&parent->valid_to, now) < 0 || /* past */
2329b0563631STom Van Eyck mbedtls_x509_time_cmp(&parent->valid_from, now) > 0) { /* future */
233032b31808SJens Wiklander if (fallback_parent == NULL) {
23313d3b0591SJens Wiklander fallback_parent = parent;
23323d3b0591SJens Wiklander fallback_signature_is_good = signature_is_good;
23333d3b0591SJens Wiklander }
2334817466cbSJens Wiklander
2335817466cbSJens Wiklander continue;
2336817466cbSJens Wiklander }
2337b0563631STom Van Eyck #else
2338b0563631STom Van Eyck ((void) now);
2339b0563631STom Van Eyck #endif
2340817466cbSJens Wiklander
23415b25c76aSJerome Forissier *r_parent = parent;
23425b25c76aSJerome Forissier *r_signature_is_good = signature_is_good;
23435b25c76aSJerome Forissier
2344817466cbSJens Wiklander break;
2345817466cbSJens Wiklander }
2346817466cbSJens Wiklander
234732b31808SJens Wiklander if (parent == NULL) {
23483d3b0591SJens Wiklander *r_parent = fallback_parent;
23493d3b0591SJens Wiklander *r_signature_is_good = fallback_signature_is_good;
2350817466cbSJens Wiklander }
2351817466cbSJens Wiklander
235232b31808SJens Wiklander return 0;
2353817466cbSJens Wiklander }
2354817466cbSJens Wiklander
23553d3b0591SJens Wiklander /*
23563d3b0591SJens Wiklander * Find a parent in trusted CAs or the provided chain, or return NULL.
23573d3b0591SJens Wiklander *
23583d3b0591SJens Wiklander * Searches in trusted CAs first, and return the first suitable parent found
23593d3b0591SJens Wiklander * (see find_parent_in() for definition of suitable).
23603d3b0591SJens Wiklander *
23613d3b0591SJens Wiklander * Arguments:
23623d3b0591SJens Wiklander * - [in] child: certificate for which we're looking for a parent, followed
23633d3b0591SJens Wiklander * by a chain of possible intermediates
23643d3b0591SJens Wiklander * - [in] trust_ca: list of locally trusted certificates
23653d3b0591SJens Wiklander * - [out] parent: parent found (or NULL)
23663d3b0591SJens Wiklander * - [out] parent_is_trusted: 1 if returned `parent` is trusted, or 0
23673d3b0591SJens Wiklander * - [out] signature_is_good: 1 if child signature by parent is valid, or 0
23683d3b0591SJens Wiklander * - [in] path_cnt: number of links in the chain so far (EE -> ... -> child)
23693d3b0591SJens Wiklander * - [in] self_cnt: number of self-signed certs in the chain so far
23703d3b0591SJens Wiklander * (will always be no greater than path_cnt)
23713d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations
23723d3b0591SJens Wiklander *
23733d3b0591SJens Wiklander * Return value:
23743d3b0591SJens Wiklander * - 0 on success
23753d3b0591SJens Wiklander * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise
23763d3b0591SJens Wiklander */
x509_crt_find_parent(mbedtls_x509_crt * child,mbedtls_x509_crt * trust_ca,mbedtls_x509_crt ** parent,int * parent_is_trusted,int * signature_is_good,unsigned path_cnt,unsigned self_cnt,mbedtls_x509_crt_restart_ctx * rs_ctx,const mbedtls_x509_time * now)23773d3b0591SJens Wiklander static int x509_crt_find_parent(
23783d3b0591SJens Wiklander mbedtls_x509_crt *child,
23793d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca,
23803d3b0591SJens Wiklander mbedtls_x509_crt **parent,
23813d3b0591SJens Wiklander int *parent_is_trusted,
23823d3b0591SJens Wiklander int *signature_is_good,
23833d3b0591SJens Wiklander unsigned path_cnt,
23843d3b0591SJens Wiklander unsigned self_cnt,
2385b0563631STom Van Eyck mbedtls_x509_crt_restart_ctx *rs_ctx,
2386b0563631STom Van Eyck const mbedtls_x509_time *now)
2387817466cbSJens Wiklander {
238811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
23893d3b0591SJens Wiklander mbedtls_x509_crt *search_list;
2390817466cbSJens Wiklander
23913d3b0591SJens Wiklander *parent_is_trusted = 1;
2392817466cbSJens Wiklander
23933d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
23943d3b0591SJens Wiklander /* restore then clear saved state if we have some stored */
239532b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->parent_is_trusted != -1) {
23963d3b0591SJens Wiklander *parent_is_trusted = rs_ctx->parent_is_trusted;
23973d3b0591SJens Wiklander rs_ctx->parent_is_trusted = -1;
23983d3b0591SJens Wiklander }
23993d3b0591SJens Wiklander #endif
24003d3b0591SJens Wiklander
24013d3b0591SJens Wiklander while (1) {
24023d3b0591SJens Wiklander search_list = *parent_is_trusted ? trust_ca : child->next;
24033d3b0591SJens Wiklander
24043d3b0591SJens Wiklander ret = x509_crt_find_parent_in(child, search_list,
24053d3b0591SJens Wiklander parent, signature_is_good,
24063d3b0591SJens Wiklander *parent_is_trusted,
2407b0563631STom Van Eyck path_cnt, self_cnt, rs_ctx, now);
24083d3b0591SJens Wiklander
24093d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
241032b31808SJens Wiklander if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
24113d3b0591SJens Wiklander /* save state */
24123d3b0591SJens Wiklander rs_ctx->parent_is_trusted = *parent_is_trusted;
241332b31808SJens Wiklander return ret;
24143d3b0591SJens Wiklander }
24153d3b0591SJens Wiklander #else
24163d3b0591SJens Wiklander (void) ret;
24173d3b0591SJens Wiklander #endif
24183d3b0591SJens Wiklander
24193d3b0591SJens Wiklander /* stop here if found or already in second iteration */
242032b31808SJens Wiklander if (*parent != NULL || *parent_is_trusted == 0) {
24213d3b0591SJens Wiklander break;
242232b31808SJens Wiklander }
24233d3b0591SJens Wiklander
24243d3b0591SJens Wiklander /* prepare second iteration */
24253d3b0591SJens Wiklander *parent_is_trusted = 0;
2426817466cbSJens Wiklander }
2427817466cbSJens Wiklander
24283d3b0591SJens Wiklander /* extra precaution against mistakes in the caller */
242932b31808SJens Wiklander if (*parent == NULL) {
24303d3b0591SJens Wiklander *parent_is_trusted = 0;
24313d3b0591SJens Wiklander *signature_is_good = 0;
24323d3b0591SJens Wiklander }
24333d3b0591SJens Wiklander
243432b31808SJens Wiklander return 0;
24353d3b0591SJens Wiklander }
24363d3b0591SJens Wiklander
24373d3b0591SJens Wiklander /*
24383d3b0591SJens Wiklander * Check if an end-entity certificate is locally trusted
24393d3b0591SJens Wiklander *
24403d3b0591SJens Wiklander * Currently we require such certificates to be self-signed (actually only
24413d3b0591SJens Wiklander * check for self-issued as self-signatures are not checked)
24423d3b0591SJens Wiklander */
x509_crt_check_ee_locally_trusted(mbedtls_x509_crt * crt,mbedtls_x509_crt * trust_ca)24433d3b0591SJens Wiklander static int x509_crt_check_ee_locally_trusted(
24443d3b0591SJens Wiklander mbedtls_x509_crt *crt,
24453d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca)
24463d3b0591SJens Wiklander {
24473d3b0591SJens Wiklander mbedtls_x509_crt *cur;
24483d3b0591SJens Wiklander
24493d3b0591SJens Wiklander /* must be self-issued */
245032b31808SJens Wiklander if (x509_name_cmp(&crt->issuer, &crt->subject) != 0) {
245132b31808SJens Wiklander return -1;
245232b31808SJens Wiklander }
24533d3b0591SJens Wiklander
24543d3b0591SJens Wiklander /* look for an exact match with trusted cert */
245532b31808SJens Wiklander for (cur = trust_ca; cur != NULL; cur = cur->next) {
24563d3b0591SJens Wiklander if (crt->raw.len == cur->raw.len &&
245732b31808SJens Wiklander memcmp(crt->raw.p, cur->raw.p, crt->raw.len) == 0) {
245832b31808SJens Wiklander return 0;
24593d3b0591SJens Wiklander }
24603d3b0591SJens Wiklander }
24613d3b0591SJens Wiklander
24623d3b0591SJens Wiklander /* too bad */
246332b31808SJens Wiklander return -1;
24643d3b0591SJens Wiklander }
24653d3b0591SJens Wiklander
24663d3b0591SJens Wiklander /*
24673d3b0591SJens Wiklander * Build and verify a certificate chain
24683d3b0591SJens Wiklander *
24693d3b0591SJens Wiklander * Given a peer-provided list of certificates EE, C1, ..., Cn and
24703d3b0591SJens Wiklander * a list of trusted certs R1, ... Rp, try to build and verify a chain
24713d3b0591SJens Wiklander * EE, Ci1, ... Ciq [, Rj]
24723d3b0591SJens Wiklander * such that every cert in the chain is a child of the next one,
24733d3b0591SJens Wiklander * jumping to a trusted root as early as possible.
24743d3b0591SJens Wiklander *
24753d3b0591SJens Wiklander * Verify that chain and return it with flags for all issues found.
24763d3b0591SJens Wiklander *
24773d3b0591SJens Wiklander * Special cases:
24783d3b0591SJens Wiklander * - EE == Rj -> return a one-element list containing it
24793d3b0591SJens Wiklander * - EE, Ci1, ..., Ciq cannot be continued with a trusted root
24803d3b0591SJens Wiklander * -> return that chain with NOT_TRUSTED set on Ciq
24813d3b0591SJens Wiklander *
24823d3b0591SJens Wiklander * Tests for (aspects of) this function should include at least:
24833d3b0591SJens Wiklander * - trusted EE
24843d3b0591SJens Wiklander * - EE -> trusted root
24855b25c76aSJerome Forissier * - EE -> intermediate CA -> trusted root
24863d3b0591SJens Wiklander * - if relevant: EE untrusted
24873d3b0591SJens Wiklander * - if relevant: EE -> intermediate, untrusted
24883d3b0591SJens Wiklander * with the aspect under test checked at each relevant level (EE, int, root).
24893d3b0591SJens Wiklander * For some aspects longer chains are required, but usually length 2 is
24903d3b0591SJens Wiklander * enough (but length 1 is not in general).
24913d3b0591SJens Wiklander *
24923d3b0591SJens Wiklander * Arguments:
24933d3b0591SJens Wiklander * - [in] crt: the cert list EE, C1, ..., Cn
24943d3b0591SJens Wiklander * - [in] trust_ca: the trusted list R1, ..., Rp
24953d3b0591SJens Wiklander * - [in] ca_crl, profile: as in verify_with_profile()
24963d3b0591SJens Wiklander * - [out] ver_chain: the built and verified chain
24973d3b0591SJens Wiklander * Only valid when return value is 0, may contain garbage otherwise!
24983d3b0591SJens Wiklander * Restart note: need not be the same when calling again to resume.
24993d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations
25003d3b0591SJens Wiklander *
25013d3b0591SJens Wiklander * Return value:
25023d3b0591SJens Wiklander * - non-zero if the chain could not be fully built and examined
25033d3b0591SJens Wiklander * - 0 is the chain was successfully built and examined,
25043d3b0591SJens Wiklander * even if it was found to be invalid
25053d3b0591SJens Wiklander */
x509_crt_verify_chain(mbedtls_x509_crt * crt,mbedtls_x509_crt * trust_ca,mbedtls_x509_crl * ca_crl,mbedtls_x509_crt_ca_cb_t f_ca_cb,void * p_ca_cb,const mbedtls_x509_crt_profile * profile,mbedtls_x509_crt_verify_chain * ver_chain,mbedtls_x509_crt_restart_ctx * rs_ctx)25063d3b0591SJens Wiklander static int x509_crt_verify_chain(
25073d3b0591SJens Wiklander mbedtls_x509_crt *crt,
25083d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca,
25093d3b0591SJens Wiklander mbedtls_x509_crl *ca_crl,
251011fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb,
251111fa71b9SJerome Forissier void *p_ca_cb,
25123d3b0591SJens Wiklander const mbedtls_x509_crt_profile *profile,
25133d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain *ver_chain,
25143d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx)
25153d3b0591SJens Wiklander {
25163d3b0591SJens Wiklander /* Don't initialize any of those variables here, so that the compiler can
25173d3b0591SJens Wiklander * catch potential issues with jumping ahead when restarting */
251811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
25193d3b0591SJens Wiklander uint32_t *flags;
25203d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain_item *cur;
25213d3b0591SJens Wiklander mbedtls_x509_crt *child;
25223d3b0591SJens Wiklander mbedtls_x509_crt *parent;
25233d3b0591SJens Wiklander int parent_is_trusted;
25243d3b0591SJens Wiklander int child_is_trusted;
25253d3b0591SJens Wiklander int signature_is_good;
25263d3b0591SJens Wiklander unsigned self_cnt;
252711fa71b9SJerome Forissier mbedtls_x509_crt *cur_trust_ca = NULL;
2528b0563631STom Van Eyck mbedtls_x509_time now;
2529b0563631STom Van Eyck
2530b0563631STom Van Eyck #if defined(MBEDTLS_HAVE_TIME_DATE)
2531b0563631STom Van Eyck if (mbedtls_x509_time_gmtime(mbedtls_time(NULL), &now) != 0) {
2532b0563631STom Van Eyck return MBEDTLS_ERR_X509_FATAL_ERROR;
2533b0563631STom Van Eyck }
2534b0563631STom Van Eyck #endif
25353d3b0591SJens Wiklander
25363d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
25373d3b0591SJens Wiklander /* resume if we had an operation in progress */
253832b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->in_progress == x509_crt_rs_find_parent) {
25393d3b0591SJens Wiklander /* restore saved state */
25403d3b0591SJens Wiklander *ver_chain = rs_ctx->ver_chain; /* struct copy */
25413d3b0591SJens Wiklander self_cnt = rs_ctx->self_cnt;
25423d3b0591SJens Wiklander
25433d3b0591SJens Wiklander /* restore derived state */
25443d3b0591SJens Wiklander cur = &ver_chain->items[ver_chain->len - 1];
25453d3b0591SJens Wiklander child = cur->crt;
25463d3b0591SJens Wiklander flags = &cur->flags;
25473d3b0591SJens Wiklander
25483d3b0591SJens Wiklander goto find_parent;
25493d3b0591SJens Wiklander }
25503d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
25513d3b0591SJens Wiklander
25523d3b0591SJens Wiklander child = crt;
25533d3b0591SJens Wiklander self_cnt = 0;
25543d3b0591SJens Wiklander parent_is_trusted = 0;
25553d3b0591SJens Wiklander child_is_trusted = 0;
25563d3b0591SJens Wiklander
25573d3b0591SJens Wiklander while (1) {
25583d3b0591SJens Wiklander /* Add certificate to the verification chain */
25593d3b0591SJens Wiklander cur = &ver_chain->items[ver_chain->len];
25603d3b0591SJens Wiklander cur->crt = child;
25613d3b0591SJens Wiklander cur->flags = 0;
25623d3b0591SJens Wiklander ver_chain->len++;
25633d3b0591SJens Wiklander flags = &cur->flags;
25643d3b0591SJens Wiklander
2565b0563631STom Van Eyck #if defined(MBEDTLS_HAVE_TIME_DATE)
25663d3b0591SJens Wiklander /* Check time-validity (all certificates) */
2567b0563631STom Van Eyck if (mbedtls_x509_time_cmp(&child->valid_to, &now) < 0) {
2568817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_EXPIRED;
256932b31808SJens Wiklander }
2570817466cbSJens Wiklander
2571b0563631STom Van Eyck if (mbedtls_x509_time_cmp(&child->valid_from, &now) > 0) {
2572817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_FUTURE;
257332b31808SJens Wiklander }
2574b0563631STom Van Eyck #endif
2575817466cbSJens Wiklander
25763d3b0591SJens Wiklander /* Stop here for trusted roots (but not for trusted EE certs) */
257732b31808SJens Wiklander if (child_is_trusted) {
257832b31808SJens Wiklander return 0;
257932b31808SJens Wiklander }
25803d3b0591SJens Wiklander
25813d3b0591SJens Wiklander /* Check signature algorithm: MD & PK algs */
258232b31808SJens Wiklander if (x509_profile_check_md_alg(profile, child->sig_md) != 0) {
2583817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_MD;
258432b31808SJens Wiklander }
2585817466cbSJens Wiklander
258632b31808SJens Wiklander if (x509_profile_check_pk_alg(profile, child->sig_pk) != 0) {
2587817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_PK;
258832b31808SJens Wiklander }
2589817466cbSJens Wiklander
25903d3b0591SJens Wiklander /* Special case: EE certs that are locally trusted */
25913d3b0591SJens Wiklander if (ver_chain->len == 1 &&
259232b31808SJens Wiklander x509_crt_check_ee_locally_trusted(child, trust_ca) == 0) {
259332b31808SJens Wiklander return 0;
2594817466cbSJens Wiklander }
2595817466cbSJens Wiklander
25963d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
25973d3b0591SJens Wiklander find_parent:
25983d3b0591SJens Wiklander #endif
259911fa71b9SJerome Forissier
260011fa71b9SJerome Forissier /* Obtain list of potential trusted signers from CA callback,
260111fa71b9SJerome Forissier * or use statically provided list. */
260211fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
260332b31808SJens Wiklander if (f_ca_cb != NULL) {
260411fa71b9SJerome Forissier mbedtls_x509_crt_free(ver_chain->trust_ca_cb_result);
260511fa71b9SJerome Forissier mbedtls_free(ver_chain->trust_ca_cb_result);
260611fa71b9SJerome Forissier ver_chain->trust_ca_cb_result = NULL;
260711fa71b9SJerome Forissier
260811fa71b9SJerome Forissier ret = f_ca_cb(p_ca_cb, child, &ver_chain->trust_ca_cb_result);
260932b31808SJens Wiklander if (ret != 0) {
261032b31808SJens Wiklander return MBEDTLS_ERR_X509_FATAL_ERROR;
261132b31808SJens Wiklander }
261211fa71b9SJerome Forissier
261311fa71b9SJerome Forissier cur_trust_ca = ver_chain->trust_ca_cb_result;
261432b31808SJens Wiklander } else
261511fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
261611fa71b9SJerome Forissier {
261711fa71b9SJerome Forissier ((void) f_ca_cb);
261811fa71b9SJerome Forissier ((void) p_ca_cb);
261911fa71b9SJerome Forissier cur_trust_ca = trust_ca;
262011fa71b9SJerome Forissier }
262111fa71b9SJerome Forissier
26223d3b0591SJens Wiklander /* Look for a parent in trusted CAs or up the chain */
262311fa71b9SJerome Forissier ret = x509_crt_find_parent(child, cur_trust_ca, &parent,
26243d3b0591SJens Wiklander &parent_is_trusted, &signature_is_good,
2625b0563631STom Van Eyck ver_chain->len - 1, self_cnt, rs_ctx,
2626b0563631STom Van Eyck &now);
26273d3b0591SJens Wiklander
26283d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
262932b31808SJens Wiklander if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
26303d3b0591SJens Wiklander /* save state */
26313d3b0591SJens Wiklander rs_ctx->in_progress = x509_crt_rs_find_parent;
26323d3b0591SJens Wiklander rs_ctx->self_cnt = self_cnt;
26333d3b0591SJens Wiklander rs_ctx->ver_chain = *ver_chain; /* struct copy */
26343d3b0591SJens Wiklander
263532b31808SJens Wiklander return ret;
26363d3b0591SJens Wiklander }
26373d3b0591SJens Wiklander #else
26383d3b0591SJens Wiklander (void) ret;
26393d3b0591SJens Wiklander #endif
26403d3b0591SJens Wiklander
26413d3b0591SJens Wiklander /* No parent? We're done here */
264232b31808SJens Wiklander if (parent == NULL) {
26433d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
264432b31808SJens Wiklander return 0;
26453d3b0591SJens Wiklander }
26463d3b0591SJens Wiklander
26473d3b0591SJens Wiklander /* Count intermediate self-issued (not necessarily self-signed) certs.
26483d3b0591SJens Wiklander * These can occur with some strategies for key rollover, see [SIRO],
26493d3b0591SJens Wiklander * and should be excluded from max_pathlen checks. */
26503d3b0591SJens Wiklander if (ver_chain->len != 1 &&
265132b31808SJens Wiklander x509_name_cmp(&child->issuer, &child->subject) == 0) {
26523d3b0591SJens Wiklander self_cnt++;
26533d3b0591SJens Wiklander }
26543d3b0591SJens Wiklander
26553d3b0591SJens Wiklander /* path_cnt is 0 for the first intermediate CA,
26563d3b0591SJens Wiklander * and if parent is trusted it's not an intermediate CA */
26573d3b0591SJens Wiklander if (!parent_is_trusted &&
265832b31808SJens Wiklander ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA) {
26593d3b0591SJens Wiklander /* return immediately to avoid overflow the chain array */
266032b31808SJens Wiklander return MBEDTLS_ERR_X509_FATAL_ERROR;
26613d3b0591SJens Wiklander }
26623d3b0591SJens Wiklander
26633d3b0591SJens Wiklander /* signature was checked while searching parent */
266432b31808SJens Wiklander if (!signature_is_good) {
26653d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
266632b31808SJens Wiklander }
26673d3b0591SJens Wiklander
26683d3b0591SJens Wiklander /* check size of signing key */
266932b31808SJens Wiklander if (x509_profile_check_key(profile, &parent->pk) != 0) {
2670817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
267132b31808SJens Wiklander }
2672817466cbSJens Wiklander
2673817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C)
2674817466cbSJens Wiklander /* Check trusted CA's CRL for the given crt */
2675b0563631STom Van Eyck *flags |= x509_crt_verifycrl(child, parent, ca_crl, profile, &now);
26763d3b0591SJens Wiklander #else
26773d3b0591SJens Wiklander (void) ca_crl;
2678817466cbSJens Wiklander #endif
2679817466cbSJens Wiklander
26803d3b0591SJens Wiklander /* prepare for next iteration */
26813d3b0591SJens Wiklander child = parent;
26823d3b0591SJens Wiklander parent = NULL;
26833d3b0591SJens Wiklander child_is_trusted = parent_is_trusted;
26843d3b0591SJens Wiklander signature_is_good = 0;
26853d3b0591SJens Wiklander }
26863d3b0591SJens Wiklander }
26873d3b0591SJens Wiklander
2688b0563631STom Van Eyck #ifdef _WIN32
2689b0563631STom Van Eyck #ifdef _MSC_VER
2690b0563631STom Van Eyck #pragma comment(lib, "ws2_32.lib")
2691b0563631STom Van Eyck #include <winsock2.h>
2692b0563631STom Van Eyck #include <ws2tcpip.h>
2693b0563631STom Van Eyck #elif (defined(__MINGW32__) || defined(__MINGW64__)) && _WIN32_WINNT >= 0x0600
2694b0563631STom Van Eyck #include <winsock2.h>
2695b0563631STom Van Eyck #include <ws2tcpip.h>
2696b0563631STom Van Eyck #else
2697b0563631STom Van Eyck /* inet_pton() is not supported, fallback to software version */
2698b0563631STom Van Eyck #define MBEDTLS_TEST_SW_INET_PTON
2699b0563631STom Van Eyck #endif
2700b0563631STom Van Eyck #elif defined(__sun)
2701b0563631STom Van Eyck /* Solaris requires -lsocket -lnsl for inet_pton() */
2702b0563631STom Van Eyck #elif defined(__has_include)
2703b0563631STom Van Eyck #if __has_include(<sys/socket.h>)
2704b0563631STom Van Eyck #include <sys/socket.h>
2705b0563631STom Van Eyck #endif
2706b0563631STom Van Eyck #if __has_include(<arpa/inet.h>)
2707b0563631STom Van Eyck #include <arpa/inet.h>
2708b0563631STom Van Eyck #endif
2709b0563631STom Van Eyck #endif
2710b0563631STom Van Eyck
2711b0563631STom Van Eyck /* Use whether or not AF_INET6 is defined to indicate whether or not to use
2712b0563631STom Van Eyck * the platform inet_pton() or a local implementation (below). The local
2713b0563631STom Van Eyck * implementation may be used even in cases where the platform provides
2714b0563631STom Van Eyck * inet_pton(), e.g. when there are different includes required and/or the
2715b0563631STom Van Eyck * platform implementation requires dependencies on additional libraries.
2716b0563631STom Van Eyck * Specifically, Windows requires custom includes and additional link
2717b0563631STom Van Eyck * dependencies, and Solaris requires additional link dependencies.
2718b0563631STom Van Eyck * Also, as a coarse heuristic, use the local implementation if the compiler
2719b0563631STom Van Eyck * does not support __has_include(), or if the definition of AF_INET6 is not
2720b0563631STom Van Eyck * provided by headers included (or not) via __has_include() above.
2721b0563631STom Van Eyck * MBEDTLS_TEST_SW_INET_PTON is a bypass define to force testing of this code //no-check-names
2722b0563631STom Van Eyck * despite having a platform that has inet_pton. */
2723b0563631STom Van Eyck #if !defined(AF_INET6) || defined(MBEDTLS_TEST_SW_INET_PTON) //no-check-names
2724b0563631STom Van Eyck /* Definition located further below to possibly reduce compiler inlining */
2725b0563631STom Van Eyck static int x509_inet_pton_ipv4(const char *src, void *dst);
2726b0563631STom Van Eyck
2727b0563631STom Van Eyck #define li_cton(c, n) \
2728b0563631STom Van Eyck (((n) = (c) - '0') <= 9 || (((n) = ((c)&0xdf) - 'A') <= 5 ? ((n) += 10) : 0))
2729b0563631STom Van Eyck
x509_inet_pton_ipv6(const char * src,void * dst)2730b0563631STom Van Eyck static int x509_inet_pton_ipv6(const char *src, void *dst)
2731b0563631STom Van Eyck {
2732b0563631STom Van Eyck const unsigned char *p = (const unsigned char *) src;
2733b0563631STom Van Eyck int nonzero_groups = 0, num_digits, zero_group_start = -1;
2734b0563631STom Van Eyck uint16_t addr[8];
2735b0563631STom Van Eyck do {
2736b0563631STom Van Eyck /* note: allows excess leading 0's, e.g. 1:0002:3:... */
2737b0563631STom Van Eyck uint16_t group = num_digits = 0;
2738b0563631STom Van Eyck for (uint8_t digit; num_digits < 4; num_digits++) {
2739b0563631STom Van Eyck if (li_cton(*p, digit) == 0) {
2740b0563631STom Van Eyck break;
2741b0563631STom Van Eyck }
2742b0563631STom Van Eyck group = (group << 4) | digit;
2743b0563631STom Van Eyck p++;
2744b0563631STom Van Eyck }
2745b0563631STom Van Eyck if (num_digits != 0) {
2746b0563631STom Van Eyck MBEDTLS_PUT_UINT16_BE(group, addr, nonzero_groups);
2747b0563631STom Van Eyck nonzero_groups++;
2748b0563631STom Van Eyck if (*p == '\0') {
2749b0563631STom Van Eyck break;
2750b0563631STom Van Eyck } else if (*p == '.') {
2751b0563631STom Van Eyck /* Don't accept IPv4 too early or late */
2752b0563631STom Van Eyck if ((nonzero_groups == 0 && zero_group_start == -1) ||
2753b0563631STom Van Eyck nonzero_groups >= 7) {
2754b0563631STom Van Eyck break;
2755b0563631STom Van Eyck }
2756b0563631STom Van Eyck
2757b0563631STom Van Eyck /* Walk back to prior ':', then parse as IPv4-mapped */
2758b0563631STom Van Eyck int steps = 4;
2759b0563631STom Van Eyck do {
2760b0563631STom Van Eyck p--;
2761b0563631STom Van Eyck steps--;
2762b0563631STom Van Eyck } while (*p != ':' && steps > 0);
2763b0563631STom Van Eyck
2764b0563631STom Van Eyck if (*p != ':') {
2765b0563631STom Van Eyck break;
2766b0563631STom Van Eyck }
2767b0563631STom Van Eyck p++;
2768b0563631STom Van Eyck nonzero_groups--;
2769b0563631STom Van Eyck if (x509_inet_pton_ipv4((const char *) p,
2770b0563631STom Van Eyck addr + nonzero_groups) != 0) {
2771b0563631STom Van Eyck break;
2772b0563631STom Van Eyck }
2773b0563631STom Van Eyck
2774b0563631STom Van Eyck nonzero_groups += 2;
2775b0563631STom Van Eyck p = (const unsigned char *) "";
2776b0563631STom Van Eyck break;
2777b0563631STom Van Eyck } else if (*p != ':') {
2778b0563631STom Van Eyck return -1;
2779b0563631STom Van Eyck }
2780b0563631STom Van Eyck } else {
2781b0563631STom Van Eyck /* Don't accept a second zero group or an invalid delimiter */
2782b0563631STom Van Eyck if (zero_group_start != -1 || *p != ':') {
2783b0563631STom Van Eyck return -1;
2784b0563631STom Van Eyck }
2785b0563631STom Van Eyck zero_group_start = nonzero_groups;
2786b0563631STom Van Eyck
2787b0563631STom Van Eyck /* Accept a zero group at start, but it has to be a double colon */
2788b0563631STom Van Eyck if (zero_group_start == 0 && *++p != ':') {
2789b0563631STom Van Eyck return -1;
2790b0563631STom Van Eyck }
2791b0563631STom Van Eyck
2792b0563631STom Van Eyck if (p[1] == '\0') {
2793b0563631STom Van Eyck ++p;
2794b0563631STom Van Eyck break;
2795b0563631STom Van Eyck }
2796b0563631STom Van Eyck }
2797b0563631STom Van Eyck ++p;
2798b0563631STom Van Eyck } while (nonzero_groups < 8);
2799b0563631STom Van Eyck
2800b0563631STom Van Eyck if (*p != '\0') {
2801b0563631STom Van Eyck return -1;
2802b0563631STom Van Eyck }
2803b0563631STom Van Eyck
2804b0563631STom Van Eyck if (zero_group_start != -1) {
2805b0563631STom Van Eyck if (nonzero_groups > 6) {
2806b0563631STom Van Eyck return -1;
2807b0563631STom Van Eyck }
2808b0563631STom Van Eyck int zero_groups = 8 - nonzero_groups;
2809b0563631STom Van Eyck int groups_after_zero = nonzero_groups - zero_group_start;
2810b0563631STom Van Eyck
2811b0563631STom Van Eyck /* Move the non-zero part to after the zeroes */
2812b0563631STom Van Eyck if (groups_after_zero) {
2813b0563631STom Van Eyck memmove(addr + zero_group_start + zero_groups,
2814b0563631STom Van Eyck addr + zero_group_start,
2815b0563631STom Van Eyck groups_after_zero * sizeof(*addr));
2816b0563631STom Van Eyck }
2817b0563631STom Van Eyck memset(addr + zero_group_start, 0, zero_groups * sizeof(*addr));
2818b0563631STom Van Eyck } else {
2819b0563631STom Van Eyck if (nonzero_groups != 8) {
2820b0563631STom Van Eyck return -1;
2821b0563631STom Van Eyck }
2822b0563631STom Van Eyck }
2823b0563631STom Van Eyck memcpy(dst, addr, sizeof(addr));
2824b0563631STom Van Eyck return 0;
2825b0563631STom Van Eyck }
2826b0563631STom Van Eyck
x509_inet_pton_ipv4(const char * src,void * dst)2827b0563631STom Van Eyck static int x509_inet_pton_ipv4(const char *src, void *dst)
2828b0563631STom Van Eyck {
2829b0563631STom Van Eyck const unsigned char *p = (const unsigned char *) src;
2830b0563631STom Van Eyck uint8_t *res = (uint8_t *) dst;
2831b0563631STom Van Eyck uint8_t digit, num_digits = 0;
2832b0563631STom Van Eyck uint8_t num_octets = 0;
2833b0563631STom Van Eyck uint16_t octet;
2834b0563631STom Van Eyck
2835b0563631STom Van Eyck do {
2836b0563631STom Van Eyck octet = num_digits = 0;
2837b0563631STom Van Eyck do {
2838b0563631STom Van Eyck digit = *p - '0';
2839b0563631STom Van Eyck if (digit > 9) {
2840b0563631STom Van Eyck break;
2841b0563631STom Van Eyck }
2842b0563631STom Van Eyck
2843b0563631STom Van Eyck /* Don't allow leading zeroes. These might mean octal format,
2844b0563631STom Van Eyck * which this implementation does not support. */
2845b0563631STom Van Eyck if (octet == 0 && num_digits > 0) {
2846b0563631STom Van Eyck return -1;
2847b0563631STom Van Eyck }
2848b0563631STom Van Eyck
2849b0563631STom Van Eyck octet = octet * 10 + digit;
2850b0563631STom Van Eyck num_digits++;
2851b0563631STom Van Eyck p++;
2852b0563631STom Van Eyck } while (num_digits < 3);
2853b0563631STom Van Eyck
2854b0563631STom Van Eyck if (octet >= 256 || num_digits > 3 || num_digits == 0) {
2855b0563631STom Van Eyck return -1;
2856b0563631STom Van Eyck }
2857b0563631STom Van Eyck *res++ = (uint8_t) octet;
2858b0563631STom Van Eyck num_octets++;
2859b0563631STom Van Eyck } while (num_octets < 4 && *p++ == '.');
2860b0563631STom Van Eyck return num_octets == 4 && *p == '\0' ? 0 : -1;
2861b0563631STom Van Eyck }
2862b0563631STom Van Eyck
2863b0563631STom Van Eyck #else
2864b0563631STom Van Eyck
x509_inet_pton_ipv6(const char * src,void * dst)2865b0563631STom Van Eyck static int x509_inet_pton_ipv6(const char *src, void *dst)
2866b0563631STom Van Eyck {
2867b0563631STom Van Eyck return inet_pton(AF_INET6, src, dst) == 1 ? 0 : -1;
2868b0563631STom Van Eyck }
2869b0563631STom Van Eyck
x509_inet_pton_ipv4(const char * src,void * dst)2870b0563631STom Van Eyck static int x509_inet_pton_ipv4(const char *src, void *dst)
2871b0563631STom Van Eyck {
2872b0563631STom Van Eyck return inet_pton(AF_INET, src, dst) == 1 ? 0 : -1;
2873b0563631STom Van Eyck }
2874b0563631STom Van Eyck
2875b0563631STom Van Eyck #endif /* !AF_INET6 || MBEDTLS_TEST_SW_INET_PTON */ //no-check-names
2876b0563631STom Van Eyck
mbedtls_x509_crt_parse_cn_inet_pton(const char * cn,void * dst)2877b0563631STom Van Eyck size_t mbedtls_x509_crt_parse_cn_inet_pton(const char *cn, void *dst)
2878b0563631STom Van Eyck {
2879b0563631STom Van Eyck return strchr(cn, ':') == NULL
2880b0563631STom Van Eyck ? x509_inet_pton_ipv4(cn, dst) == 0 ? 4 : 0
2881b0563631STom Van Eyck : x509_inet_pton_ipv6(cn, dst) == 0 ? 16 : 0;
2882b0563631STom Van Eyck }
2883b0563631STom Van Eyck
28843d3b0591SJens Wiklander /*
28853d3b0591SJens Wiklander * Check for CN match
28863d3b0591SJens Wiklander */
x509_crt_check_cn(const mbedtls_x509_buf * name,const char * cn,size_t cn_len)28873d3b0591SJens Wiklander static int x509_crt_check_cn(const mbedtls_x509_buf *name,
28883d3b0591SJens Wiklander const char *cn, size_t cn_len)
2889817466cbSJens Wiklander {
28903d3b0591SJens Wiklander /* try exact match */
28913d3b0591SJens Wiklander if (name->len == cn_len &&
289232b31808SJens Wiklander x509_memcasecmp(cn, name->p, cn_len) == 0) {
289332b31808SJens Wiklander return 0;
28943d3b0591SJens Wiklander }
28953d3b0591SJens Wiklander
28963d3b0591SJens Wiklander /* try wildcard match */
289732b31808SJens Wiklander if (x509_check_wildcard(cn, name) == 0) {
289832b31808SJens Wiklander return 0;
28993d3b0591SJens Wiklander }
29003d3b0591SJens Wiklander
290132b31808SJens Wiklander return -1;
29023d3b0591SJens Wiklander }
29033d3b0591SJens Wiklander
x509_crt_check_san_ip(const mbedtls_x509_sequence * san,const char * cn,size_t cn_len)2904b0563631STom Van Eyck static int x509_crt_check_san_ip(const mbedtls_x509_sequence *san,
2905b0563631STom Van Eyck const char *cn, size_t cn_len)
2906b0563631STom Van Eyck {
2907b0563631STom Van Eyck uint32_t ip[4];
2908b0563631STom Van Eyck cn_len = mbedtls_x509_crt_parse_cn_inet_pton(cn, ip);
2909b0563631STom Van Eyck if (cn_len == 0) {
2910b0563631STom Van Eyck return -1;
2911b0563631STom Van Eyck }
2912b0563631STom Van Eyck
2913b0563631STom Van Eyck for (const mbedtls_x509_sequence *cur = san; cur != NULL; cur = cur->next) {
2914b0563631STom Van Eyck const unsigned char san_type = (unsigned char) cur->buf.tag &
2915b0563631STom Van Eyck MBEDTLS_ASN1_TAG_VALUE_MASK;
2916b0563631STom Van Eyck if (san_type == MBEDTLS_X509_SAN_IP_ADDRESS &&
2917b0563631STom Van Eyck cur->buf.len == cn_len && memcmp(cur->buf.p, ip, cn_len) == 0) {
2918b0563631STom Van Eyck return 0;
2919b0563631STom Van Eyck }
2920b0563631STom Van Eyck }
2921b0563631STom Van Eyck
2922b0563631STom Van Eyck return -1;
2923b0563631STom Van Eyck }
2924b0563631STom Van Eyck
x509_crt_check_san_uri(const mbedtls_x509_sequence * san,const char * cn,size_t cn_len)2925b0563631STom Van Eyck static int x509_crt_check_san_uri(const mbedtls_x509_sequence *san,
2926b0563631STom Van Eyck const char *cn, size_t cn_len)
2927b0563631STom Van Eyck {
2928b0563631STom Van Eyck for (const mbedtls_x509_sequence *cur = san; cur != NULL; cur = cur->next) {
2929b0563631STom Van Eyck const unsigned char san_type = (unsigned char) cur->buf.tag &
2930b0563631STom Van Eyck MBEDTLS_ASN1_TAG_VALUE_MASK;
2931b0563631STom Van Eyck if (san_type == MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER &&
2932b0563631STom Van Eyck cur->buf.len == cn_len && memcmp(cur->buf.p, cn, cn_len) == 0) {
2933b0563631STom Van Eyck return 0;
2934b0563631STom Van Eyck }
2935b0563631STom Van Eyck }
2936b0563631STom Van Eyck
2937b0563631STom Van Eyck return -1;
2938b0563631STom Van Eyck }
2939b0563631STom Van Eyck
29403d3b0591SJens Wiklander /*
29417901324dSJerome Forissier * Check for SAN match, see RFC 5280 Section 4.2.1.6
29427901324dSJerome Forissier */
x509_crt_check_san(const mbedtls_x509_sequence * san,const char * cn,size_t cn_len)2943b0563631STom Van Eyck static int x509_crt_check_san(const mbedtls_x509_sequence *san,
29447901324dSJerome Forissier const char *cn, size_t cn_len)
29457901324dSJerome Forissier {
2946b0563631STom Van Eyck int san_ip = 0;
2947b0563631STom Van Eyck int san_uri = 0;
2948b0563631STom Van Eyck /* Prioritize DNS name over other subtypes due to popularity */
2949b0563631STom Van Eyck for (const mbedtls_x509_sequence *cur = san; cur != NULL; cur = cur->next) {
2950b0563631STom Van Eyck switch ((unsigned char) cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) {
2951b0563631STom Van Eyck case MBEDTLS_X509_SAN_DNS_NAME:
2952b0563631STom Van Eyck if (x509_crt_check_cn(&cur->buf, cn, cn_len) == 0) {
2953b0563631STom Van Eyck return 0;
2954b0563631STom Van Eyck }
2955b0563631STom Van Eyck break;
2956b0563631STom Van Eyck case MBEDTLS_X509_SAN_IP_ADDRESS:
2957b0563631STom Van Eyck san_ip = 1;
2958b0563631STom Van Eyck break;
2959b0563631STom Van Eyck case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
2960b0563631STom Van Eyck san_uri = 1;
2961b0563631STom Van Eyck break;
2962b0563631STom Van Eyck /* (We may handle other types here later.) */
2963b0563631STom Van Eyck default: /* Unrecognized type */
2964b0563631STom Van Eyck break;
2965b0563631STom Van Eyck }
2966b0563631STom Van Eyck }
2967b0563631STom Van Eyck if (san_ip) {
2968b0563631STom Van Eyck if (x509_crt_check_san_ip(san, cn, cn_len) == 0) {
2969b0563631STom Van Eyck return 0;
2970b0563631STom Van Eyck }
2971b0563631STom Van Eyck }
2972b0563631STom Van Eyck if (san_uri) {
2973b0563631STom Van Eyck if (x509_crt_check_san_uri(san, cn, cn_len) == 0) {
2974b0563631STom Van Eyck return 0;
2975b0563631STom Van Eyck }
297632b31808SJens Wiklander }
29777901324dSJerome Forissier
297832b31808SJens Wiklander return -1;
29797901324dSJerome Forissier }
29807901324dSJerome Forissier
29817901324dSJerome Forissier /*
29823d3b0591SJens Wiklander * Verify the requested CN - only call this if cn is not NULL!
29833d3b0591SJens Wiklander */
x509_crt_verify_name(const mbedtls_x509_crt * crt,const char * cn,uint32_t * flags)29843d3b0591SJens Wiklander static void x509_crt_verify_name(const mbedtls_x509_crt *crt,
29853d3b0591SJens Wiklander const char *cn,
29863d3b0591SJens Wiklander uint32_t *flags)
29873d3b0591SJens Wiklander {
29883d3b0591SJens Wiklander const mbedtls_x509_name *name;
29893d3b0591SJens Wiklander size_t cn_len = strlen(cn);
29903d3b0591SJens Wiklander
299132b31808SJens Wiklander if (crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) {
2992b0563631STom Van Eyck if (x509_crt_check_san(&crt->subject_alt_names, cn, cn_len) == 0) {
2993b0563631STom Van Eyck return;
2994817466cbSJens Wiklander }
299532b31808SJens Wiklander } else {
299632b31808SJens Wiklander for (name = &crt->subject; name != NULL; name = name->next) {
29973d3b0591SJens Wiklander if (MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid) == 0 &&
299832b31808SJens Wiklander x509_crt_check_cn(&name->val, cn, cn_len) == 0) {
2999b0563631STom Van Eyck return;
3000817466cbSJens Wiklander }
3001817466cbSJens Wiklander }
30023d3b0591SJens Wiklander
3003b0563631STom Van Eyck }
3004b0563631STom Van Eyck
30053d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
3006817466cbSJens Wiklander }
3007817466cbSJens Wiklander
30083d3b0591SJens Wiklander /*
30093d3b0591SJens Wiklander * Merge the flags for all certs in the chain, after calling callback
30103d3b0591SJens Wiklander */
x509_crt_merge_flags_with_cb(uint32_t * flags,const mbedtls_x509_crt_verify_chain * ver_chain,int (* f_vrfy)(void *,mbedtls_x509_crt *,int,uint32_t *),void * p_vrfy)30113d3b0591SJens Wiklander static int x509_crt_merge_flags_with_cb(
30123d3b0591SJens Wiklander uint32_t *flags,
30133d3b0591SJens Wiklander const mbedtls_x509_crt_verify_chain *ver_chain,
30143d3b0591SJens Wiklander int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
30153d3b0591SJens Wiklander void *p_vrfy)
30163d3b0591SJens Wiklander {
301711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
30183d3b0591SJens Wiklander unsigned i;
30193d3b0591SJens Wiklander uint32_t cur_flags;
30203d3b0591SJens Wiklander const mbedtls_x509_crt_verify_chain_item *cur;
30213d3b0591SJens Wiklander
302232b31808SJens Wiklander for (i = ver_chain->len; i != 0; --i) {
30233d3b0591SJens Wiklander cur = &ver_chain->items[i-1];
30243d3b0591SJens Wiklander cur_flags = cur->flags;
30253d3b0591SJens Wiklander
302632b31808SJens Wiklander if (NULL != f_vrfy) {
302732b31808SJens Wiklander if ((ret = f_vrfy(p_vrfy, cur->crt, (int) i-1, &cur_flags)) != 0) {
302832b31808SJens Wiklander return ret;
302932b31808SJens Wiklander }
303032b31808SJens Wiklander }
3031817466cbSJens Wiklander
30323d3b0591SJens Wiklander *flags |= cur_flags;
30333d3b0591SJens Wiklander }
3034817466cbSJens Wiklander
303532b31808SJens Wiklander return 0;
3036817466cbSJens Wiklander }
3037817466cbSJens Wiklander
3038817466cbSJens Wiklander /*
30393d3b0591SJens Wiklander * Verify the certificate validity, with profile, restartable version
30403d3b0591SJens Wiklander *
30413d3b0591SJens Wiklander * This function:
30423d3b0591SJens Wiklander * - checks the requested CN (if any)
30433d3b0591SJens Wiklander * - checks the type and size of the EE cert's key,
30443d3b0591SJens Wiklander * as that isn't done as part of chain building/verification currently
30453d3b0591SJens Wiklander * - builds and verifies the chain
30463d3b0591SJens Wiklander * - then calls the callback and merges the flags
304711fa71b9SJerome Forissier *
304811fa71b9SJerome Forissier * The parameters pairs `trust_ca`, `ca_crl` and `f_ca_cb`, `p_ca_cb`
304911fa71b9SJerome Forissier * are mutually exclusive: If `f_ca_cb != NULL`, it will be used by the
305011fa71b9SJerome Forissier * verification routine to search for trusted signers, and CRLs will
305111fa71b9SJerome Forissier * be disabled. Otherwise, `trust_ca` will be used as the static list
305211fa71b9SJerome Forissier * of trusted signers, and `ca_crl` will be use as the static list
305311fa71b9SJerome Forissier * of CRLs.
30543d3b0591SJens Wiklander */
x509_crt_verify_restartable_ca_cb(mbedtls_x509_crt * crt,mbedtls_x509_crt * trust_ca,mbedtls_x509_crl * ca_crl,mbedtls_x509_crt_ca_cb_t f_ca_cb,void * p_ca_cb,const mbedtls_x509_crt_profile * profile,const char * cn,uint32_t * flags,int (* f_vrfy)(void *,mbedtls_x509_crt *,int,uint32_t *),void * p_vrfy,mbedtls_x509_crt_restart_ctx * rs_ctx)305511fa71b9SJerome Forissier static int x509_crt_verify_restartable_ca_cb(mbedtls_x509_crt *crt,
30563d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca,
30573d3b0591SJens Wiklander mbedtls_x509_crl *ca_crl,
305811fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb,
305911fa71b9SJerome Forissier void *p_ca_cb,
30603d3b0591SJens Wiklander const mbedtls_x509_crt_profile *profile,
30613d3b0591SJens Wiklander const char *cn, uint32_t *flags,
306232b31808SJens Wiklander int (*f_vrfy)(void *,
306332b31808SJens Wiklander mbedtls_x509_crt *,
306432b31808SJens Wiklander int,
306532b31808SJens Wiklander uint32_t *),
30663d3b0591SJens Wiklander void *p_vrfy,
30673d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx)
30683d3b0591SJens Wiklander {
306911fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
3070817466cbSJens Wiklander mbedtls_pk_type_t pk_type;
30713d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain ver_chain;
30723d3b0591SJens Wiklander uint32_t ee_flags;
3073817466cbSJens Wiklander
3074817466cbSJens Wiklander *flags = 0;
30753d3b0591SJens Wiklander ee_flags = 0;
30763d3b0591SJens Wiklander x509_crt_verify_chain_reset(&ver_chain);
3077817466cbSJens Wiklander
307832b31808SJens Wiklander if (profile == NULL) {
3079817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA;
3080817466cbSJens Wiklander goto exit;
3081817466cbSJens Wiklander }
3082817466cbSJens Wiklander
30833d3b0591SJens Wiklander /* check name if requested */
308432b31808SJens Wiklander if (cn != NULL) {
30853d3b0591SJens Wiklander x509_crt_verify_name(crt, cn, &ee_flags);
308632b31808SJens Wiklander }
3087817466cbSJens Wiklander
3088817466cbSJens Wiklander /* Check the type and size of the key */
3089817466cbSJens Wiklander pk_type = mbedtls_pk_get_type(&crt->pk);
3090817466cbSJens Wiklander
309132b31808SJens Wiklander if (x509_profile_check_pk_alg(profile, pk_type) != 0) {
30923d3b0591SJens Wiklander ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK;
309332b31808SJens Wiklander }
3094817466cbSJens Wiklander
309532b31808SJens Wiklander if (x509_profile_check_key(profile, &crt->pk) != 0) {
30963d3b0591SJens Wiklander ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
309732b31808SJens Wiklander }
3098817466cbSJens Wiklander
30993d3b0591SJens Wiklander /* Check the chain */
310011fa71b9SJerome Forissier ret = x509_crt_verify_chain(crt, trust_ca, ca_crl,
310111fa71b9SJerome Forissier f_ca_cb, p_ca_cb, profile,
31023d3b0591SJens Wiklander &ver_chain, rs_ctx);
3103817466cbSJens Wiklander
310432b31808SJens Wiklander if (ret != 0) {
3105817466cbSJens Wiklander goto exit;
310632b31808SJens Wiklander }
3107817466cbSJens Wiklander
31083d3b0591SJens Wiklander /* Merge end-entity flags */
31093d3b0591SJens Wiklander ver_chain.items[0].flags |= ee_flags;
31103d3b0591SJens Wiklander
31113d3b0591SJens Wiklander /* Build final flags, calling callback on the way if any */
31123d3b0591SJens Wiklander ret = x509_crt_merge_flags_with_cb(flags, &ver_chain, f_vrfy, p_vrfy);
3113817466cbSJens Wiklander
3114817466cbSJens Wiklander exit:
311511fa71b9SJerome Forissier
311611fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
311711fa71b9SJerome Forissier mbedtls_x509_crt_free(ver_chain.trust_ca_cb_result);
311811fa71b9SJerome Forissier mbedtls_free(ver_chain.trust_ca_cb_result);
311911fa71b9SJerome Forissier ver_chain.trust_ca_cb_result = NULL;
312011fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
312111fa71b9SJerome Forissier
31223d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
312332b31808SJens Wiklander if (rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS) {
31243d3b0591SJens Wiklander mbedtls_x509_crt_restart_free(rs_ctx);
312532b31808SJens Wiklander }
31263d3b0591SJens Wiklander #endif
31273d3b0591SJens Wiklander
3128817466cbSJens Wiklander /* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by
3129817466cbSJens Wiklander * the SSL module for authmode optional, but non-zero return from the
3130817466cbSJens Wiklander * callback means a fatal error so it shouldn't be ignored */
313132b31808SJens Wiklander if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
3132817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FATAL_ERROR;
3133817466cbSJens Wiklander }
3134817466cbSJens Wiklander
313532b31808SJens Wiklander if (ret != 0) {
313632b31808SJens Wiklander *flags = (uint32_t) -1;
313732b31808SJens Wiklander return ret;
313832b31808SJens Wiklander }
3139817466cbSJens Wiklander
314032b31808SJens Wiklander if (*flags != 0) {
314132b31808SJens Wiklander return MBEDTLS_ERR_X509_CERT_VERIFY_FAILED;
314232b31808SJens Wiklander }
314332b31808SJens Wiklander
314432b31808SJens Wiklander return 0;
3145817466cbSJens Wiklander }
3146817466cbSJens Wiklander
314711fa71b9SJerome Forissier
314811fa71b9SJerome Forissier /*
314911fa71b9SJerome Forissier * Verify the certificate validity (default profile, not restartable)
315011fa71b9SJerome Forissier */
mbedtls_x509_crt_verify(mbedtls_x509_crt * crt,mbedtls_x509_crt * trust_ca,mbedtls_x509_crl * ca_crl,const char * cn,uint32_t * flags,int (* f_vrfy)(void *,mbedtls_x509_crt *,int,uint32_t *),void * p_vrfy)315111fa71b9SJerome Forissier int mbedtls_x509_crt_verify(mbedtls_x509_crt *crt,
315211fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca,
315311fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl,
315411fa71b9SJerome Forissier const char *cn, uint32_t *flags,
315511fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
315611fa71b9SJerome Forissier void *p_vrfy)
315711fa71b9SJerome Forissier {
315832b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl,
315911fa71b9SJerome Forissier NULL, NULL,
316011fa71b9SJerome Forissier &mbedtls_x509_crt_profile_default,
316111fa71b9SJerome Forissier cn, flags,
316232b31808SJens Wiklander f_vrfy, p_vrfy, NULL);
316311fa71b9SJerome Forissier }
316411fa71b9SJerome Forissier
316511fa71b9SJerome Forissier /*
316611fa71b9SJerome Forissier * Verify the certificate validity (user-chosen profile, not restartable)
316711fa71b9SJerome Forissier */
mbedtls_x509_crt_verify_with_profile(mbedtls_x509_crt * crt,mbedtls_x509_crt * trust_ca,mbedtls_x509_crl * ca_crl,const mbedtls_x509_crt_profile * profile,const char * cn,uint32_t * flags,int (* f_vrfy)(void *,mbedtls_x509_crt *,int,uint32_t *),void * p_vrfy)316811fa71b9SJerome Forissier int mbedtls_x509_crt_verify_with_profile(mbedtls_x509_crt *crt,
316911fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca,
317011fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl,
317111fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile,
317211fa71b9SJerome Forissier const char *cn, uint32_t *flags,
317311fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
317411fa71b9SJerome Forissier void *p_vrfy)
317511fa71b9SJerome Forissier {
317632b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl,
317711fa71b9SJerome Forissier NULL, NULL,
317811fa71b9SJerome Forissier profile, cn, flags,
317932b31808SJens Wiklander f_vrfy, p_vrfy, NULL);
318011fa71b9SJerome Forissier }
318111fa71b9SJerome Forissier
318211fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
318311fa71b9SJerome Forissier /*
318411fa71b9SJerome Forissier * Verify the certificate validity (user-chosen profile, CA callback,
318511fa71b9SJerome Forissier * not restartable).
318611fa71b9SJerome Forissier */
mbedtls_x509_crt_verify_with_ca_cb(mbedtls_x509_crt * crt,mbedtls_x509_crt_ca_cb_t f_ca_cb,void * p_ca_cb,const mbedtls_x509_crt_profile * profile,const char * cn,uint32_t * flags,int (* f_vrfy)(void *,mbedtls_x509_crt *,int,uint32_t *),void * p_vrfy)318711fa71b9SJerome Forissier int mbedtls_x509_crt_verify_with_ca_cb(mbedtls_x509_crt *crt,
318811fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb,
318911fa71b9SJerome Forissier void *p_ca_cb,
319011fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile,
319111fa71b9SJerome Forissier const char *cn, uint32_t *flags,
319211fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
319311fa71b9SJerome Forissier void *p_vrfy)
319411fa71b9SJerome Forissier {
319532b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, NULL, NULL,
319611fa71b9SJerome Forissier f_ca_cb, p_ca_cb,
319711fa71b9SJerome Forissier profile, cn, flags,
319832b31808SJens Wiklander f_vrfy, p_vrfy, NULL);
319911fa71b9SJerome Forissier }
320011fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
320111fa71b9SJerome Forissier
mbedtls_x509_crt_verify_restartable(mbedtls_x509_crt * crt,mbedtls_x509_crt * trust_ca,mbedtls_x509_crl * ca_crl,const mbedtls_x509_crt_profile * profile,const char * cn,uint32_t * flags,int (* f_vrfy)(void *,mbedtls_x509_crt *,int,uint32_t *),void * p_vrfy,mbedtls_x509_crt_restart_ctx * rs_ctx)320211fa71b9SJerome Forissier int mbedtls_x509_crt_verify_restartable(mbedtls_x509_crt *crt,
320311fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca,
320411fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl,
320511fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile,
320611fa71b9SJerome Forissier const char *cn, uint32_t *flags,
320711fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
320811fa71b9SJerome Forissier void *p_vrfy,
320911fa71b9SJerome Forissier mbedtls_x509_crt_restart_ctx *rs_ctx)
321011fa71b9SJerome Forissier {
321132b31808SJens Wiklander return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl,
321211fa71b9SJerome Forissier NULL, NULL,
321311fa71b9SJerome Forissier profile, cn, flags,
321432b31808SJens Wiklander f_vrfy, p_vrfy, rs_ctx);
321511fa71b9SJerome Forissier }
321611fa71b9SJerome Forissier
321711fa71b9SJerome Forissier
3218817466cbSJens Wiklander /*
3219817466cbSJens Wiklander * Initialize a certificate chain
3220817466cbSJens Wiklander */
mbedtls_x509_crt_init(mbedtls_x509_crt * crt)3221817466cbSJens Wiklander void mbedtls_x509_crt_init(mbedtls_x509_crt *crt)
3222817466cbSJens Wiklander {
3223817466cbSJens Wiklander memset(crt, 0, sizeof(mbedtls_x509_crt));
3224817466cbSJens Wiklander }
3225817466cbSJens Wiklander
3226817466cbSJens Wiklander /*
3227817466cbSJens Wiklander * Unallocate all certificate data
3228817466cbSJens Wiklander */
mbedtls_x509_crt_free(mbedtls_x509_crt * crt)3229817466cbSJens Wiklander void mbedtls_x509_crt_free(mbedtls_x509_crt *crt)
3230817466cbSJens Wiklander {
3231817466cbSJens Wiklander mbedtls_x509_crt *cert_cur = crt;
3232817466cbSJens Wiklander mbedtls_x509_crt *cert_prv;
3233817466cbSJens Wiklander
323432b31808SJens Wiklander while (cert_cur != NULL) {
3235817466cbSJens Wiklander mbedtls_pk_free(&cert_cur->pk);
3236817466cbSJens Wiklander
3237817466cbSJens Wiklander #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
3238817466cbSJens Wiklander mbedtls_free(cert_cur->sig_opts);
3239817466cbSJens Wiklander #endif
3240817466cbSJens Wiklander
324132b31808SJens Wiklander mbedtls_asn1_free_named_data_list_shallow(cert_cur->issuer.next);
324232b31808SJens Wiklander mbedtls_asn1_free_named_data_list_shallow(cert_cur->subject.next);
324332b31808SJens Wiklander mbedtls_asn1_sequence_free(cert_cur->ext_key_usage.next);
324432b31808SJens Wiklander mbedtls_asn1_sequence_free(cert_cur->subject_alt_names.next);
324532b31808SJens Wiklander mbedtls_asn1_sequence_free(cert_cur->certificate_policies.next);
3246b0563631STom Van Eyck mbedtls_asn1_sequence_free(cert_cur->authority_key_id.authorityCertIssuer.next);
3247817466cbSJens Wiklander
324832b31808SJens Wiklander if (cert_cur->raw.p != NULL && cert_cur->own_buffer) {
3249b0563631STom Van Eyck mbedtls_zeroize_and_free(cert_cur->raw.p, cert_cur->raw.len);
3250817466cbSJens Wiklander }
3251817466cbSJens Wiklander
3252817466cbSJens Wiklander cert_prv = cert_cur;
3253817466cbSJens Wiklander cert_cur = cert_cur->next;
3254817466cbSJens Wiklander
32553d3b0591SJens Wiklander mbedtls_platform_zeroize(cert_prv, sizeof(mbedtls_x509_crt));
325632b31808SJens Wiklander if (cert_prv != crt) {
3257817466cbSJens Wiklander mbedtls_free(cert_prv);
3258817466cbSJens Wiklander }
325932b31808SJens Wiklander }
3260817466cbSJens Wiklander }
3261817466cbSJens Wiklander
32623d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
32633d3b0591SJens Wiklander /*
32643d3b0591SJens Wiklander * Initialize a restart context
32653d3b0591SJens Wiklander */
mbedtls_x509_crt_restart_init(mbedtls_x509_crt_restart_ctx * ctx)32663d3b0591SJens Wiklander void mbedtls_x509_crt_restart_init(mbedtls_x509_crt_restart_ctx *ctx)
32673d3b0591SJens Wiklander {
32683d3b0591SJens Wiklander mbedtls_pk_restart_init(&ctx->pk);
32693d3b0591SJens Wiklander
32703d3b0591SJens Wiklander ctx->parent = NULL;
32713d3b0591SJens Wiklander ctx->fallback_parent = NULL;
32723d3b0591SJens Wiklander ctx->fallback_signature_is_good = 0;
32733d3b0591SJens Wiklander
32743d3b0591SJens Wiklander ctx->parent_is_trusted = -1;
32753d3b0591SJens Wiklander
32763d3b0591SJens Wiklander ctx->in_progress = x509_crt_rs_none;
32773d3b0591SJens Wiklander ctx->self_cnt = 0;
32783d3b0591SJens Wiklander x509_crt_verify_chain_reset(&ctx->ver_chain);
32793d3b0591SJens Wiklander }
32803d3b0591SJens Wiklander
32813d3b0591SJens Wiklander /*
32823d3b0591SJens Wiklander * Free the components of a restart context
32833d3b0591SJens Wiklander */
mbedtls_x509_crt_restart_free(mbedtls_x509_crt_restart_ctx * ctx)32843d3b0591SJens Wiklander void mbedtls_x509_crt_restart_free(mbedtls_x509_crt_restart_ctx *ctx)
32853d3b0591SJens Wiklander {
328632b31808SJens Wiklander if (ctx == NULL) {
32873d3b0591SJens Wiklander return;
328832b31808SJens Wiklander }
32893d3b0591SJens Wiklander
32903d3b0591SJens Wiklander mbedtls_pk_restart_free(&ctx->pk);
32913d3b0591SJens Wiklander mbedtls_x509_crt_restart_init(ctx);
32923d3b0591SJens Wiklander }
32933d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
32943d3b0591SJens Wiklander
mbedtls_x509_crt_get_ca_istrue(const mbedtls_x509_crt * crt)3295b0563631STom Van Eyck int mbedtls_x509_crt_get_ca_istrue(const mbedtls_x509_crt *crt)
3296b0563631STom Van Eyck {
3297b0563631STom Van Eyck if ((crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS) != 0) {
3298b0563631STom Van Eyck return crt->MBEDTLS_PRIVATE(ca_istrue);
3299b0563631STom Van Eyck }
3300b0563631STom Van Eyck return MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
3301b0563631STom Van Eyck }
3302b0563631STom Van Eyck
3303817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRT_PARSE_C */
3304