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