diff options
author | beck <> | 2020-09-13 15:06:17 +0000 |
---|---|---|
committer | beck <> | 2020-09-13 15:06:17 +0000 |
commit | a328631fddec2556ad8af08ce4de240790c537c9 (patch) | |
tree | 4e2deda0db62092481ad6901c374736e60f249a2 /src/lib/libcrypto/x509/x509_verify.c | |
parent | 4f04d3f588f91c98b4b1cdfcffe028a036c96283 (diff) | |
download | openbsd-a328631fddec2556ad8af08ce4de240790c537c9.tar.gz openbsd-a328631fddec2556ad8af08ce4de240790c537c9.tar.bz2 openbsd-a328631fddec2556ad8af08ce4de240790c537c9.zip |
Add new x509 certificate chain validator in x509_verify.c
The new validator finds multiple validated chains to handle the modern
PKI cases which may frequently have multiple paths via different
intermediates to different roots. It is loosely based on golang's x509
validator
This includes integration so that the new validator can be used via
X509_verify_cert() as well as a new api x509_verify() which will
return multiple chains (similar to go).
The new validator is not enabled by default with this commit, this
will be changed in a follow on commit.
The new public API is not yet exposed, and will be finalized and
exposed with a man page and a library minor bump later.
ok tb@ inoguchi@ jsing@
Diffstat (limited to 'src/lib/libcrypto/x509/x509_verify.c')
-rw-r--r-- | src/lib/libcrypto/x509/x509_verify.c | 914 |
1 files changed, 914 insertions, 0 deletions
diff --git a/src/lib/libcrypto/x509/x509_verify.c b/src/lib/libcrypto/x509/x509_verify.c new file mode 100644 index 0000000000..5f5070c122 --- /dev/null +++ b/src/lib/libcrypto/x509/x509_verify.c | |||
@@ -0,0 +1,914 @@ | |||
1 | /* $OpenBSD: x509_verify.c,v 1.1 2020/09/13 15:06:17 beck Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | /* x509_verify - inspired by golang's crypto/x509/Verify */ | ||
19 | |||
20 | #include <errno.h> | ||
21 | #include <stdio.h> | ||
22 | #include <string.h> | ||
23 | #include <time.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #include <openssl/safestack.h> | ||
27 | #include <openssl/x509.h> | ||
28 | #include <openssl/x509v3.h> | ||
29 | |||
30 | #include "x509_internal.h" | ||
31 | #include "x509_issuer_cache.h" | ||
32 | |||
33 | static int x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert, | ||
34 | struct x509_verify_chain *current_chain); | ||
35 | static void x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | ||
36 | struct x509_verify_chain *current_chain); | ||
37 | static int x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, | ||
38 | size_t depth, int error, int ok); | ||
39 | static void x509_verify_chain_free(struct x509_verify_chain *chain); | ||
40 | |||
41 | #define X509_VERIFY_CERT_HASH (EVP_sha512()) | ||
42 | |||
43 | struct x509_verify_chain * | ||
44 | x509_verify_chain_new(void) | ||
45 | { | ||
46 | struct x509_verify_chain *chain; | ||
47 | |||
48 | if ((chain = calloc(1, sizeof(*chain))) == NULL) | ||
49 | goto err; | ||
50 | if ((chain->certs = sk_X509_new_null()) == NULL) | ||
51 | goto err; | ||
52 | if ((chain->names = x509_constraints_names_new()) == NULL) | ||
53 | goto err; | ||
54 | |||
55 | return chain; | ||
56 | err: | ||
57 | x509_verify_chain_free(chain); | ||
58 | return NULL; | ||
59 | } | ||
60 | |||
61 | static void | ||
62 | x509_verify_chain_clear(struct x509_verify_chain *chain) | ||
63 | { | ||
64 | sk_X509_pop_free(chain->certs, X509_free); | ||
65 | chain->certs = NULL; | ||
66 | x509_constraints_names_free(chain->names); | ||
67 | chain->names = NULL; | ||
68 | } | ||
69 | |||
70 | static void | ||
71 | x509_verify_chain_free(struct x509_verify_chain *chain) | ||
72 | { | ||
73 | if (chain == NULL) | ||
74 | return; | ||
75 | x509_verify_chain_clear(chain); | ||
76 | free(chain); | ||
77 | } | ||
78 | |||
79 | static struct x509_verify_chain * | ||
80 | x509_verify_chain_dup(struct x509_verify_chain *chain) | ||
81 | { | ||
82 | struct x509_verify_chain *new_chain; | ||
83 | |||
84 | if ((new_chain = x509_verify_chain_new()) == NULL) | ||
85 | goto err; | ||
86 | if ((new_chain->certs = X509_chain_up_ref(chain->certs)) == NULL) | ||
87 | goto err; | ||
88 | if ((new_chain->names = | ||
89 | x509_constraints_names_dup(chain->names)) == NULL) | ||
90 | goto err; | ||
91 | return(new_chain); | ||
92 | err: | ||
93 | x509_verify_chain_free(new_chain); | ||
94 | return NULL; | ||
95 | } | ||
96 | |||
97 | static int | ||
98 | x509_verify_chain_append(struct x509_verify_chain *chain, X509 *cert, | ||
99 | int *error) | ||
100 | { | ||
101 | int verify_err = X509_V_ERR_UNSPECIFIED; | ||
102 | |||
103 | if (!x509_constraints_extract_names(chain->names, cert, | ||
104 | sk_X509_num(chain->certs) == 0, &verify_err)) { | ||
105 | *error = verify_err; | ||
106 | return 0; | ||
107 | } | ||
108 | X509_up_ref(cert); | ||
109 | if (!sk_X509_push(chain->certs, cert)) { | ||
110 | X509_free(cert); | ||
111 | *error = X509_V_ERR_UNSPECIFIED; | ||
112 | return 0; | ||
113 | } | ||
114 | return 1; | ||
115 | } | ||
116 | |||
117 | static X509 * | ||
118 | x509_verify_chain_last(struct x509_verify_chain *chain) | ||
119 | { | ||
120 | int last; | ||
121 | |||
122 | if (chain->certs == NULL) | ||
123 | return NULL; | ||
124 | if ((last = sk_X509_num(chain->certs) - 1) < 0) | ||
125 | return NULL; | ||
126 | return sk_X509_value(chain->certs, last); | ||
127 | } | ||
128 | |||
129 | X509 * | ||
130 | x509_verify_chain_leaf(struct x509_verify_chain *chain) | ||
131 | { | ||
132 | if (chain->certs == NULL) | ||
133 | return NULL; | ||
134 | return sk_X509_value(chain->certs, 0); | ||
135 | } | ||
136 | |||
137 | static void | ||
138 | x509_verify_ctx_reset(struct x509_verify_ctx *ctx) | ||
139 | { | ||
140 | size_t i; | ||
141 | |||
142 | for (i = 0; i < ctx->chains_count; i++) | ||
143 | x509_verify_chain_free(ctx->chains[i]); | ||
144 | ctx->error = 0; | ||
145 | ctx->error_depth = 0; | ||
146 | ctx->chains_count = 0; | ||
147 | ctx->sig_checks = 0; | ||
148 | ctx->check_time = NULL; | ||
149 | } | ||
150 | |||
151 | static void | ||
152 | x509_verify_ctx_clear(struct x509_verify_ctx *ctx) | ||
153 | { | ||
154 | x509_verify_ctx_reset(ctx); | ||
155 | sk_X509_pop_free(ctx->intermediates, X509_free); | ||
156 | sk_X509_pop_free(ctx->roots, X509_free); | ||
157 | free(ctx->chains); | ||
158 | memset(ctx, 0, sizeof(*ctx)); | ||
159 | } | ||
160 | |||
161 | static int | ||
162 | x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert) | ||
163 | { | ||
164 | int i; | ||
165 | |||
166 | for (i = 0; i < sk_X509_num(ctx->roots); i++) { | ||
167 | if (X509_cmp(sk_X509_value(ctx->roots, i), cert) == 0) | ||
168 | return 1; | ||
169 | } | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | /* Add a validated chain to our list of valid chains */ | ||
174 | static int | ||
175 | x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx, | ||
176 | struct x509_verify_chain *chain) | ||
177 | { | ||
178 | size_t depth; | ||
179 | X509 *last = x509_verify_chain_last(chain); | ||
180 | |||
181 | depth = sk_X509_num(chain->certs); | ||
182 | if (depth > 0) | ||
183 | depth--; | ||
184 | |||
185 | if (ctx->chains_count >= ctx->max_chains) | ||
186 | return x509_verify_cert_error(ctx, last, depth, | ||
187 | X509_V_ERR_CERT_CHAIN_TOO_LONG, 0); | ||
188 | |||
189 | /* | ||
190 | * If we have a legacy xsc, choose a validated chain, | ||
191 | * and apply the extensions, revocation, and policy checks | ||
192 | * just like the legacy code did. We do this here instead | ||
193 | * of as building the chains to more easily support the | ||
194 | * callback and the bewildering array of VERIFY_PARAM | ||
195 | * knobs that are there for the fiddling. | ||
196 | */ | ||
197 | if (ctx->xsc != NULL) { | ||
198 | ctx->xsc->last_untrusted = depth ? depth - 1 : 0; | ||
199 | sk_X509_pop_free(ctx->xsc->chain, X509_free); | ||
200 | ctx->xsc->chain = X509_chain_up_ref(chain->certs); | ||
201 | if (ctx->xsc->chain == NULL) | ||
202 | return x509_verify_cert_error(ctx, last, depth, | ||
203 | X509_V_ERR_OUT_OF_MEM, 0); | ||
204 | |||
205 | /* | ||
206 | * XXX currently this duplicates some work done | ||
207 | * in chain build, but we keep it here until | ||
208 | * we have feature parity | ||
209 | */ | ||
210 | if (!x509_vfy_check_chain_extensions(ctx->xsc)) | ||
211 | return 0; | ||
212 | |||
213 | if (!x509_constraints_chain(ctx->xsc->chain, | ||
214 | &ctx->xsc->error, &ctx->xsc->error_depth)) { | ||
215 | X509 *cert = sk_X509_value(ctx->xsc->chain, depth); | ||
216 | if (!x509_verify_cert_error(ctx, cert, | ||
217 | ctx->xsc->error_depth, ctx->xsc->error, 0)) | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | if (!x509_vfy_check_revocation(ctx->xsc)) | ||
222 | return 0; | ||
223 | |||
224 | if (!x509_vfy_check_policy(ctx->xsc)) | ||
225 | return 0; | ||
226 | } | ||
227 | /* | ||
228 | * no xsc means we are being called from the non-legacy API, | ||
229 | * extensions and purpose are dealt with as the chain is built. | ||
230 | * | ||
231 | * The non-legacy api returns multiple chains but does not do | ||
232 | * any revocation checking (it must be done by the caller on | ||
233 | * any chain they wish to use) | ||
234 | */ | ||
235 | |||
236 | if ((ctx->chains[ctx->chains_count] = x509_verify_chain_dup(chain)) == | ||
237 | NULL) { | ||
238 | return x509_verify_cert_error(ctx, last, depth, | ||
239 | X509_V_ERR_OUT_OF_MEM, 0); | ||
240 | } | ||
241 | ctx->chains_count++; | ||
242 | ctx->error = X509_V_OK; | ||
243 | ctx->error_depth = depth; | ||
244 | return 1; | ||
245 | } | ||
246 | |||
247 | static int | ||
248 | x509_verify_potential_parent(struct x509_verify_ctx *ctx, X509 *parent, | ||
249 | X509 *child) | ||
250 | { | ||
251 | if (ctx->xsc != NULL) | ||
252 | return (ctx->xsc->check_issued(ctx->xsc, child, parent)); | ||
253 | |||
254 | /* XXX key usage */ | ||
255 | return X509_check_issued(child, parent) != X509_V_OK; | ||
256 | } | ||
257 | |||
258 | static int | ||
259 | x509_verify_parent_signature(X509 *parent, X509 *child, | ||
260 | unsigned char *child_md, int *error) | ||
261 | { | ||
262 | unsigned char parent_md[EVP_MAX_MD_SIZE] = { 0 }; | ||
263 | EVP_PKEY *pkey; | ||
264 | int cached; | ||
265 | int ret = 0; | ||
266 | |||
267 | /* Use cached value if we have it */ | ||
268 | if (child_md != NULL) { | ||
269 | if (!X509_digest(parent, X509_VERIFY_CERT_HASH, parent_md, | ||
270 | NULL)) | ||
271 | return 0; | ||
272 | if ((cached = x509_issuer_cache_find(parent_md, child_md)) >= 0) | ||
273 | return cached; | ||
274 | } | ||
275 | |||
276 | /* Check signature. Did parent sign child? */ | ||
277 | if ((pkey = X509_get_pubkey(parent)) == NULL) { | ||
278 | *error = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; | ||
279 | return 0; | ||
280 | } | ||
281 | if (X509_verify(child, pkey) <= 0) | ||
282 | *error = X509_V_ERR_CERT_SIGNATURE_FAILURE; | ||
283 | else | ||
284 | ret = 1; | ||
285 | |||
286 | /* Add result to cache */ | ||
287 | if (child_md != NULL) | ||
288 | x509_issuer_cache_add(parent_md, child_md, ret); | ||
289 | |||
290 | EVP_PKEY_free(pkey); | ||
291 | |||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | static int | ||
296 | x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, | ||
297 | unsigned char *cert_md, int is_root_cert, X509 *candidate, | ||
298 | struct x509_verify_chain *current_chain) | ||
299 | { | ||
300 | int depth = sk_X509_num(current_chain->certs); | ||
301 | struct x509_verify_chain *new_chain; | ||
302 | int i; | ||
303 | |||
304 | /* Fail if the certificate is already in the chain */ | ||
305 | for (i = 0; i < sk_X509_num(current_chain->certs); i++) { | ||
306 | if (X509_cmp(sk_X509_value(current_chain->certs, i), | ||
307 | candidate) == 0) | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | if (ctx->sig_checks++ > X509_VERIFY_MAX_SIGCHECKS) { | ||
312 | /* don't allow callback to override safety check */ | ||
313 | (void) x509_verify_cert_error(ctx, candidate, depth, | ||
314 | X509_V_ERR_CERT_CHAIN_TOO_LONG, 0); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | |||
319 | if (!x509_verify_parent_signature(candidate, cert, cert_md, | ||
320 | &ctx->error)) { | ||
321 | if (!x509_verify_cert_error(ctx, candidate, depth, | ||
322 | ctx->error, 0)) | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | if (!x509_verify_cert_valid(ctx, candidate, current_chain)) | ||
327 | return 0; | ||
328 | |||
329 | /* candidate is good, add it to a copy of the current chain */ | ||
330 | if ((new_chain = x509_verify_chain_dup(current_chain)) == NULL) { | ||
331 | x509_verify_cert_error(ctx, candidate, depth, | ||
332 | X509_V_ERR_OUT_OF_MEM, 0); | ||
333 | return 0; | ||
334 | } | ||
335 | if (!x509_verify_chain_append(new_chain, candidate, &ctx->error)) { | ||
336 | x509_verify_cert_error(ctx, candidate, depth, | ||
337 | ctx->error, 0); | ||
338 | x509_verify_chain_free(new_chain); | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * If candidate is a trusted root, we have a validated chain, | ||
344 | * so we save it. Otherwise, recurse until we find a root or | ||
345 | * give up. | ||
346 | */ | ||
347 | if (is_root_cert && | ||
348 | x509_verify_cert_error(ctx, candidate, depth, X509_V_OK, 1)) | ||
349 | (void) x509_verify_ctx_add_chain(ctx, new_chain); | ||
350 | else | ||
351 | x509_verify_build_chains(ctx, candidate, new_chain); | ||
352 | |||
353 | x509_verify_chain_free(new_chain); | ||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | static int | ||
358 | x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, size_t depth, | ||
359 | int error, int ok) | ||
360 | { | ||
361 | ctx->error = error; | ||
362 | ctx->error_depth = depth; | ||
363 | if (ctx->xsc != NULL) { | ||
364 | ctx->xsc->error = error; | ||
365 | ctx->xsc->error_depth = depth; | ||
366 | ctx->xsc->current_cert = cert; | ||
367 | return ctx->xsc->verify_cb(ok, ctx->xsc); | ||
368 | } | ||
369 | return ok; | ||
370 | } | ||
371 | |||
372 | static void | ||
373 | x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | ||
374 | struct x509_verify_chain *current_chain) | ||
375 | { | ||
376 | unsigned char cert_md[EVP_MAX_MD_SIZE] = { 0 }; | ||
377 | X509 *candidate; | ||
378 | int i, depth, count; | ||
379 | |||
380 | depth = sk_X509_num(current_chain->certs); | ||
381 | if (depth > 0) | ||
382 | depth--; | ||
383 | |||
384 | if (depth >= ctx->max_depth && | ||
385 | !x509_verify_cert_error(ctx, cert, depth, | ||
386 | X509_V_ERR_CERT_CHAIN_TOO_LONG, 0)) | ||
387 | return; | ||
388 | |||
389 | if (!X509_digest(cert, X509_VERIFY_CERT_HASH, cert_md, NULL) && | ||
390 | !x509_verify_cert_error(ctx, cert, depth, | ||
391 | X509_V_ERR_UNSPECIFIED, 0)) | ||
392 | return; | ||
393 | |||
394 | count = ctx->chains_count; | ||
395 | ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; | ||
396 | ctx->error_depth = depth; | ||
397 | |||
398 | for (i = 0; i < sk_X509_num(ctx->roots); i++) { | ||
399 | candidate = sk_X509_value(ctx->roots, i); | ||
400 | if (x509_verify_potential_parent(ctx, candidate, cert)) { | ||
401 | x509_verify_consider_candidate(ctx, cert, | ||
402 | cert_md, 1, candidate, current_chain); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | if (ctx->intermediates != NULL) { | ||
407 | for (i = 0; i < sk_X509_num(ctx->intermediates); i++) { | ||
408 | candidate = sk_X509_value(ctx->intermediates, i); | ||
409 | if (x509_verify_potential_parent(ctx, candidate, cert)) { | ||
410 | x509_verify_consider_candidate(ctx, cert, | ||
411 | cert_md, 0, candidate, current_chain); | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | if (ctx->chains_count > count) { | ||
416 | if (ctx->xsc != NULL) { | ||
417 | ctx->xsc->error = X509_V_OK; | ||
418 | ctx->xsc->error_depth = depth; | ||
419 | ctx->xsc->current_cert = cert; | ||
420 | (void) ctx->xsc->verify_cb(1, ctx->xsc); | ||
421 | } | ||
422 | } else if (ctx->error_depth == depth) { | ||
423 | (void) x509_verify_cert_error(ctx, cert, depth, | ||
424 | ctx->error, 0); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | static int | ||
429 | x509_verify_cert_hostname(struct x509_verify_ctx *ctx, X509 *cert, char *name) | ||
430 | { | ||
431 | char *candidate; | ||
432 | size_t len; | ||
433 | |||
434 | if (name == NULL) { | ||
435 | if (ctx->xsc != NULL) | ||
436 | return x509_vfy_check_id(ctx->xsc); | ||
437 | return 1; | ||
438 | } | ||
439 | if ((candidate = strdup(name)) == NULL) { | ||
440 | ctx->error = X509_V_ERR_OUT_OF_MEM; | ||
441 | goto err; | ||
442 | } | ||
443 | if ((len = strlen(candidate)) < 1) { | ||
444 | ctx->error = X509_V_ERR_UNSPECIFIED; /* XXX */ | ||
445 | goto err; | ||
446 | } | ||
447 | |||
448 | /* IP addresses may be written in [ ]. */ | ||
449 | if (candidate[0] == '[' && candidate[len - 1] == ']') { | ||
450 | candidate[len - 1] = '\0'; | ||
451 | if (X509_check_ip_asc(cert, candidate + 1, 0) <= 0) { | ||
452 | ctx->error = X509_V_ERR_IP_ADDRESS_MISMATCH; | ||
453 | goto err; | ||
454 | } | ||
455 | } else { | ||
456 | int flags = 0; | ||
457 | |||
458 | if (ctx->xsc == NULL) | ||
459 | flags = X509_CHECK_FLAG_NEVER_CHECK_SUBJECT; | ||
460 | |||
461 | if (X509_check_host(cert, candidate, len, flags, NULL) <= 0) { | ||
462 | ctx->error = X509_V_ERR_HOSTNAME_MISMATCH; | ||
463 | goto err; | ||
464 | } | ||
465 | } | ||
466 | free(candidate); | ||
467 | return 1; | ||
468 | err: | ||
469 | free(candidate); | ||
470 | return x509_verify_cert_error(ctx, cert, 0, ctx->error, 0); | ||
471 | } | ||
472 | |||
473 | static int | ||
474 | x509_verify_set_check_time(struct x509_verify_ctx *ctx) { | ||
475 | if (ctx->xsc != NULL) { | ||
476 | if (ctx->xsc->param->flags & X509_V_FLAG_USE_CHECK_TIME) { | ||
477 | ctx->check_time = &ctx->xsc->param->check_time; | ||
478 | return 1; | ||
479 | } | ||
480 | if (ctx->xsc->param->flags & X509_V_FLAG_NO_CHECK_TIME) | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | ctx->check_time = NULL; | ||
485 | return 1; | ||
486 | } | ||
487 | |||
488 | static int | ||
489 | x509_verify_asn1_time_to_tm(const ASN1_TIME *atime, struct tm *tm, int notafter) | ||
490 | { | ||
491 | time_t time; | ||
492 | int type; | ||
493 | |||
494 | memset(tm, 0, sizeof(*tm)); | ||
495 | |||
496 | type = ASN1_time_parse(atime->data, atime->length, tm, atime->type); | ||
497 | if (type == -1) | ||
498 | return 0; | ||
499 | |||
500 | /* RFC 5280 section 4.1.2.5 */ | ||
501 | if (tm->tm_year < 150 && type != V_ASN1_UTCTIME) | ||
502 | return 0; | ||
503 | if (tm->tm_year >= 150 && type != V_ASN1_GENERALIZEDTIME) | ||
504 | return 0; | ||
505 | |||
506 | if (notafter) { | ||
507 | /* | ||
508 | * If we are a completely broken operating system with a | ||
509 | * 32 bit time_t, and we have been told this is a notafter | ||
510 | * date, limit the date to a 32 bit representable value. | ||
511 | */ | ||
512 | if (!ASN1_time_tm_clamp_notafter(tm)) | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | /* | ||
517 | * Defensively fail if the time string is not representable as | ||
518 | * a time_t. A time_t must be sane if you care about times after | ||
519 | * Jan 19 2038. | ||
520 | */ | ||
521 | if ((time = timegm(tm)) == -1) | ||
522 | return 0; | ||
523 | |||
524 | return 1; | ||
525 | } | ||
526 | |||
527 | static int | ||
528 | x509_verify_cert_time(int is_notafter, const ASN1_TIME *cert_asn1, | ||
529 | time_t *cmp_time, int *error) | ||
530 | { | ||
531 | struct tm cert_tm, when_tm; | ||
532 | time_t when; | ||
533 | |||
534 | if (cmp_time == NULL) | ||
535 | when = time(NULL); | ||
536 | else | ||
537 | when = *cmp_time; | ||
538 | |||
539 | if (!x509_verify_asn1_time_to_tm(cert_asn1, &cert_tm, | ||
540 | is_notafter)) { | ||
541 | *error = is_notafter ? | ||
542 | X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD : | ||
543 | X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD; | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | if (gmtime_r(&when, &when_tm) == NULL) { | ||
548 | *error = X509_V_ERR_UNSPECIFIED; | ||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | if (is_notafter) { | ||
553 | if (ASN1_time_tm_cmp(&cert_tm, &when_tm) == -1) { | ||
554 | *error = X509_V_ERR_CERT_HAS_EXPIRED; | ||
555 | return 0; | ||
556 | } | ||
557 | } else { | ||
558 | if (ASN1_time_tm_cmp(&cert_tm, &when_tm) == 1) { | ||
559 | *error = X509_V_ERR_CERT_NOT_YET_VALID; | ||
560 | return 0; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | return 1; | ||
565 | } | ||
566 | |||
567 | static int | ||
568 | x509_verify_validate_constraints(X509 *cert, | ||
569 | struct x509_verify_chain *current_chain, int *error) | ||
570 | { | ||
571 | struct x509_constraints_names *excluded = NULL; | ||
572 | struct x509_constraints_names *permitted = NULL; | ||
573 | int err = X509_V_ERR_UNSPECIFIED; | ||
574 | |||
575 | if (current_chain == NULL) | ||
576 | return 1; | ||
577 | |||
578 | if (cert->nc != NULL) { | ||
579 | if ((permitted = x509_constraints_names_new()) == NULL) { | ||
580 | err = X509_V_ERR_OUT_OF_MEM; | ||
581 | goto err; | ||
582 | } | ||
583 | if ((excluded = x509_constraints_names_new()) == NULL) { | ||
584 | err = X509_V_ERR_OUT_OF_MEM; | ||
585 | goto err; | ||
586 | } | ||
587 | if (!x509_constraints_extract_constraints(cert, | ||
588 | permitted, excluded, &err)) | ||
589 | goto err; | ||
590 | if (!x509_constraints_check(current_chain->names, | ||
591 | permitted, excluded, &err)) | ||
592 | goto err; | ||
593 | x509_constraints_names_free(excluded); | ||
594 | x509_constraints_names_free(permitted); | ||
595 | } | ||
596 | |||
597 | return 1; | ||
598 | err: | ||
599 | *error = err; | ||
600 | x509_constraints_names_free(excluded); | ||
601 | x509_constraints_names_free(permitted); | ||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | static int | ||
606 | x509_verify_cert_extensions(struct x509_verify_ctx *ctx, X509 *cert, int need_ca) | ||
607 | { | ||
608 | if (!(cert->ex_flags & EXFLAG_SET)) { | ||
609 | CRYPTO_w_lock(CRYPTO_LOCK_X509); | ||
610 | x509v3_cache_extensions(cert); | ||
611 | CRYPTO_w_unlock(CRYPTO_LOCK_X509); | ||
612 | } | ||
613 | |||
614 | if (ctx->xsc != NULL) | ||
615 | return 1; /* legacy is checked after chain is built */ | ||
616 | |||
617 | if (cert->ex_flags & EXFLAG_CRITICAL) { | ||
618 | ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION; | ||
619 | return 0; | ||
620 | } | ||
621 | /* No we don't care about v1, netscape, and other ancient silliness */ | ||
622 | if (need_ca && (!(cert->ex_flags & EXFLAG_BCONS) && | ||
623 | (cert->ex_flags & EXFLAG_CA))) { | ||
624 | ctx->error = X509_V_ERR_INVALID_CA; | ||
625 | return 0; | ||
626 | } | ||
627 | if (ctx->purpose > 0 && X509_check_purpose(cert, ctx->purpose, need_ca)) { | ||
628 | ctx->error = X509_V_ERR_INVALID_PURPOSE; | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | /* XXX support proxy certs later in new api */ | ||
633 | if (ctx->xsc == NULL && cert->ex_flags & EXFLAG_PROXY) { | ||
634 | ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED; | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | return 1; | ||
639 | } | ||
640 | |||
641 | /* Validate that cert is a possible candidate to append to current_chain */ | ||
642 | static int | ||
643 | x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert, | ||
644 | struct x509_verify_chain *current_chain) | ||
645 | { | ||
646 | X509 *issuer_candidate; | ||
647 | int should_be_ca = current_chain != NULL; | ||
648 | size_t depth = 0; | ||
649 | |||
650 | if (!should_be_ca) | ||
651 | depth = sk_X509_num(current_chain->certs); | ||
652 | |||
653 | if (!x509_verify_cert_extensions(ctx, cert, should_be_ca)) | ||
654 | return 0; | ||
655 | |||
656 | if (should_be_ca) { | ||
657 | issuer_candidate = x509_verify_chain_last(current_chain); | ||
658 | if (issuer_candidate != NULL && | ||
659 | !X509_check_issued(issuer_candidate, cert)) | ||
660 | if (!x509_verify_cert_error(ctx, cert, depth, | ||
661 | X509_V_ERR_SUBJECT_ISSUER_MISMATCH, 0)) | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | if (x509_verify_set_check_time(ctx)) { | ||
666 | if (!x509_verify_cert_time(0, X509_get_notBefore(cert), | ||
667 | ctx->check_time, &ctx->error)) { | ||
668 | if (!x509_verify_cert_error(ctx, cert, depth, | ||
669 | ctx->error, 0)) | ||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | if (!x509_verify_cert_time(1, X509_get_notAfter(cert), | ||
674 | ctx->check_time, &ctx->error)) { | ||
675 | if (!x509_verify_cert_error(ctx, cert, depth, | ||
676 | ctx->error, 0)) | ||
677 | return 0; | ||
678 | } | ||
679 | } | ||
680 | |||
681 | if (!x509_verify_validate_constraints(cert, current_chain, | ||
682 | &ctx->error) && !x509_verify_cert_error(ctx, cert, depth, | ||
683 | ctx->error, 0)) | ||
684 | return 0; | ||
685 | |||
686 | return 1; | ||
687 | } | ||
688 | |||
689 | struct x509_verify_ctx * | ||
690 | x509_verify_ctx_new_from_xsc(X509_STORE_CTX *xsc, STACK_OF(X509) *roots) | ||
691 | { | ||
692 | struct x509_verify_ctx *ctx; | ||
693 | |||
694 | if (xsc == NULL) | ||
695 | return NULL; | ||
696 | |||
697 | if ((ctx = calloc(1, sizeof(struct x509_verify_ctx))) == NULL) | ||
698 | return NULL; | ||
699 | |||
700 | ctx->xsc = xsc; | ||
701 | |||
702 | if ((ctx->roots = X509_chain_up_ref(roots)) == NULL) | ||
703 | goto err; | ||
704 | |||
705 | if (xsc->untrusted && | ||
706 | (ctx->intermediates = X509_chain_up_ref(xsc->untrusted)) == NULL) | ||
707 | goto err; | ||
708 | |||
709 | ctx->max_depth = xsc->param->depth; | ||
710 | if (ctx->max_depth == 0 || ctx->max_depth > X509_VERIFY_MAX_CHAIN_CERTS) | ||
711 | ctx->max_depth = X509_VERIFY_MAX_CHAIN_CERTS; | ||
712 | |||
713 | ctx->max_chains = X509_VERIFY_MAX_CHAINS; | ||
714 | ctx->max_sigs = X509_VERIFY_MAX_SIGCHECKS; | ||
715 | |||
716 | if ((ctx->chains = calloc(X509_VERIFY_MAX_CHAINS, sizeof(*ctx->chains))) == | ||
717 | NULL) | ||
718 | goto err; | ||
719 | |||
720 | return ctx; | ||
721 | err: | ||
722 | x509_verify_ctx_free(ctx); | ||
723 | return NULL; | ||
724 | } | ||
725 | |||
726 | /* Public API */ | ||
727 | |||
728 | struct x509_verify_ctx * | ||
729 | x509_verify_ctx_new(STACK_OF(X509) *roots) | ||
730 | { | ||
731 | struct x509_verify_ctx *ctx; | ||
732 | |||
733 | if (roots == NULL) | ||
734 | return NULL; | ||
735 | |||
736 | if ((ctx = calloc(1, sizeof(struct x509_verify_ctx))) == NULL) | ||
737 | return NULL; | ||
738 | |||
739 | if ((ctx->roots = X509_chain_up_ref(roots)) == NULL) | ||
740 | goto err; | ||
741 | |||
742 | ctx->max_depth = X509_VERIFY_MAX_CHAIN_CERTS; | ||
743 | ctx->max_chains = X509_VERIFY_MAX_CHAINS; | ||
744 | ctx->max_sigs = X509_VERIFY_MAX_SIGCHECKS; | ||
745 | |||
746 | if ((ctx->chains = calloc(X509_VERIFY_MAX_CHAINS, | ||
747 | sizeof(*ctx->chains))) == NULL) | ||
748 | goto err; | ||
749 | |||
750 | return ctx; | ||
751 | err: | ||
752 | x509_verify_ctx_free(ctx); | ||
753 | return NULL; | ||
754 | } | ||
755 | |||
756 | void | ||
757 | x509_verify_ctx_free(struct x509_verify_ctx *ctx) | ||
758 | { | ||
759 | if (ctx == NULL) | ||
760 | return; | ||
761 | sk_X509_pop_free(ctx->roots, X509_free); | ||
762 | x509_verify_ctx_clear(ctx); | ||
763 | free(ctx); | ||
764 | } | ||
765 | |||
766 | int | ||
767 | x509_verify_ctx_set_max_depth(struct x509_verify_ctx *ctx, size_t max) | ||
768 | { | ||
769 | if (max < 1 || max > X509_VERIFY_MAX_CHAIN_CERTS) | ||
770 | return 0; | ||
771 | ctx->max_depth = max; | ||
772 | return 1; | ||
773 | } | ||
774 | |||
775 | int | ||
776 | x509_verify_ctx_set_max_chains(struct x509_verify_ctx *ctx, size_t max) | ||
777 | { | ||
778 | if (max < 1 || max > X509_VERIFY_MAX_CHAINS) | ||
779 | return 0; | ||
780 | ctx->max_chains = max; | ||
781 | return 1; | ||
782 | } | ||
783 | |||
784 | int | ||
785 | x509_verify_ctx_set_max_signatures(struct x509_verify_ctx *ctx, size_t max) | ||
786 | { | ||
787 | if (max < 1) | ||
788 | return 0; | ||
789 | if (max > 100000) | ||
790 | return 0; | ||
791 | ctx->max_sigs = max; | ||
792 | return 1; | ||
793 | } | ||
794 | |||
795 | int | ||
796 | x509_verify_ctx_set_purpose(struct x509_verify_ctx *ctx, int purpose) | ||
797 | { | ||
798 | if (purpose < X509_PURPOSE_MIN || purpose > X509_PURPOSE_MAX) | ||
799 | return 0; | ||
800 | ctx->purpose = purpose; | ||
801 | return 1; | ||
802 | } | ||
803 | |||
804 | int | ||
805 | x509_verify_ctx_set_intermediates(struct x509_verify_ctx *ctx, | ||
806 | STACK_OF(X509) *intermediates) | ||
807 | { | ||
808 | if ((ctx->intermediates = X509_chain_up_ref(intermediates)) == NULL) | ||
809 | return 0; | ||
810 | return 1; | ||
811 | } | ||
812 | |||
813 | const char * | ||
814 | x509_verify_ctx_error_string(struct x509_verify_ctx *ctx) | ||
815 | { | ||
816 | return X509_verify_cert_error_string(ctx->error); | ||
817 | } | ||
818 | |||
819 | size_t | ||
820 | x509_verify_ctx_error_depth(struct x509_verify_ctx *ctx) | ||
821 | { | ||
822 | return ctx->error_depth; | ||
823 | } | ||
824 | |||
825 | STACK_OF(X509) * | ||
826 | x509_verify_ctx_chain(struct x509_verify_ctx *ctx, size_t i) | ||
827 | { | ||
828 | if (i >= ctx->chains_count) | ||
829 | return NULL; | ||
830 | return ctx->chains[i]->certs; | ||
831 | } | ||
832 | |||
833 | size_t | ||
834 | x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name) | ||
835 | { | ||
836 | struct x509_verify_chain *current_chain; | ||
837 | |||
838 | if (ctx == NULL) | ||
839 | return 0; | ||
840 | if (ctx->roots == NULL || ctx->max_depth == 0) { | ||
841 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
842 | return 0; | ||
843 | } | ||
844 | |||
845 | if (ctx->xsc != NULL) { | ||
846 | if (leaf != NULL || name != NULL) { | ||
847 | ctx->error = X509_V_ERR_INVALID_CALL; | ||
848 | return 0; | ||
849 | } | ||
850 | leaf = ctx->xsc->cert; | ||
851 | } | ||
852 | |||
853 | if (!x509_verify_cert_valid(ctx, leaf, NULL)) | ||
854 | return 0; | ||
855 | |||
856 | if (!x509_verify_cert_hostname(ctx, leaf, name)) | ||
857 | return 0; | ||
858 | |||
859 | if (ctx->xsc != NULL) { | ||
860 | /* | ||
861 | * XXX | ||
862 | * The legacy code expects the top level cert to be | ||
863 | * there, even if we didn't find a chain. So put it | ||
864 | * there, we will clobber it later if we find a valid | ||
865 | * chain. | ||
866 | */ | ||
867 | if ((ctx->xsc->chain = sk_X509_new_null()) == NULL) { | ||
868 | ctx->error = X509_V_ERR_OUT_OF_MEM; | ||
869 | return 0; | ||
870 | } | ||
871 | if (!X509_up_ref(leaf)) { | ||
872 | ctx->error = X509_V_ERR_OUT_OF_MEM; | ||
873 | return 0; | ||
874 | } | ||
875 | if (!sk_X509_push(ctx->xsc->chain, leaf)) { | ||
876 | X509_free(leaf); | ||
877 | ctx->error = X509_V_ERR_OUT_OF_MEM; | ||
878 | return 0; | ||
879 | } | ||
880 | } | ||
881 | |||
882 | if ((current_chain = x509_verify_chain_new()) == NULL) { | ||
883 | ctx->error = X509_V_ERR_OUT_OF_MEM; | ||
884 | return 0; | ||
885 | } | ||
886 | if (!x509_verify_chain_append(current_chain, leaf, &ctx->error)) { | ||
887 | x509_verify_chain_free(current_chain); | ||
888 | return 0; | ||
889 | } | ||
890 | if (x509_verify_ctx_cert_is_root(ctx, leaf)) | ||
891 | x509_verify_ctx_add_chain(ctx, current_chain); | ||
892 | else | ||
893 | x509_verify_build_chains(ctx, leaf, current_chain); | ||
894 | |||
895 | x509_verify_chain_free(current_chain); | ||
896 | |||
897 | /* | ||
898 | * Safety net: | ||
899 | * We could not find a validated chain, and for some reason do not | ||
900 | * have an error set. | ||
901 | */ | ||
902 | if (ctx->chains_count == 0 && ctx->error == 0) | ||
903 | ctx->error = X509_V_ERR_UNSPECIFIED; | ||
904 | |||
905 | /* Clear whatever errors happened if we have any validated chain */ | ||
906 | if (ctx->chains_count > 0) | ||
907 | ctx->error = X509_V_OK; | ||
908 | |||
909 | if (ctx->xsc != NULL) { | ||
910 | ctx->xsc->error = ctx->error; | ||
911 | return ctx->xsc->verify_cb(ctx->chains_count, ctx->xsc); | ||
912 | } | ||
913 | return (ctx->chains_count); | ||
914 | } | ||