xref: /optee_os/lib/libmbedtls/mbedtls/library/x509_crt.c (revision cb03400251f98aed22a2664509e3ed9e183800b0)
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