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