diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libcrypto/x509/x509_internal.h | 5 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_verify.c | 146 |
2 files changed, 135 insertions, 16 deletions
diff --git a/src/lib/libcrypto/x509/x509_internal.h b/src/lib/libcrypto/x509/x509_internal.h index fe40351228..7160053a8a 100644 --- a/src/lib/libcrypto/x509/x509_internal.h +++ b/src/lib/libcrypto/x509/x509_internal.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_internal.h,v 1.7 2021/03/12 15:53:38 tb Exp $ */ | 1 | /* $OpenBSD: x509_internal.h,v 1.8 2021/07/10 15:52:59 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> | 3 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> |
4 | * | 4 | * |
@@ -65,6 +65,9 @@ struct x509_verify_chain { | |||
65 | struct x509_verify_ctx { | 65 | struct x509_verify_ctx { |
66 | X509_STORE_CTX *xsc; | 66 | X509_STORE_CTX *xsc; |
67 | struct x509_verify_chain **chains; /* Validated chains */ | 67 | struct x509_verify_chain **chains; /* Validated chains */ |
68 | STACK_OF(X509) *saved_error_chain; | ||
69 | int saved_error; | ||
70 | int saved_error_depth; | ||
68 | size_t chains_count; | 71 | size_t chains_count; |
69 | int dump_chain; /* Dump current chain without erroring */ | 72 | int dump_chain; /* Dump current chain without erroring */ |
70 | STACK_OF(X509) *roots; /* Trusted roots for this validation */ | 73 | STACK_OF(X509) *roots; /* Trusted roots for this validation */ |
diff --git a/src/lib/libcrypto/x509/x509_verify.c b/src/lib/libcrypto/x509/x509_verify.c index 57c52aa240..21b391c76c 100644 --- a/src/lib/libcrypto/x509/x509_verify.c +++ b/src/lib/libcrypto/x509/x509_verify.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_verify.c,v 1.37 2021/04/28 17:53:34 tb Exp $ */ | 1 | /* $OpenBSD: x509_verify.c,v 1.38 2021/07/10 15:52:59 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org> | 3 | * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org> |
4 | * | 4 | * |
@@ -33,7 +33,7 @@ | |||
33 | static int x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert, | 33 | static int x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert, |
34 | struct x509_verify_chain *current_chain); | 34 | struct x509_verify_chain *current_chain); |
35 | static void x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | 35 | static void x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, |
36 | struct x509_verify_chain *current_chain); | 36 | struct x509_verify_chain *current_chain, int full_chain); |
37 | static int x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, | 37 | static int x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, |
38 | size_t depth, int error, int ok); | 38 | size_t depth, int error, int ok); |
39 | static void x509_verify_chain_free(struct x509_verify_chain *chain); | 39 | static void x509_verify_chain_free(struct x509_verify_chain *chain); |
@@ -166,6 +166,9 @@ x509_verify_ctx_reset(struct x509_verify_ctx *ctx) | |||
166 | 166 | ||
167 | for (i = 0; i < ctx->chains_count; i++) | 167 | for (i = 0; i < ctx->chains_count; i++) |
168 | x509_verify_chain_free(ctx->chains[i]); | 168 | x509_verify_chain_free(ctx->chains[i]); |
169 | sk_X509_pop_free(ctx->saved_error_chain, X509_free); | ||
170 | ctx->saved_error = 0; | ||
171 | ctx->saved_error_depth = 0; | ||
169 | ctx->error = 0; | 172 | ctx->error = 0; |
170 | ctx->error_depth = 0; | 173 | ctx->error_depth = 0; |
171 | ctx->chains_count = 0; | 174 | ctx->chains_count = 0; |
@@ -183,14 +186,42 @@ x509_verify_ctx_clear(struct x509_verify_ctx *ctx) | |||
183 | } | 186 | } |
184 | 187 | ||
185 | static int | 188 | static int |
186 | x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert) | 189 | x509_verify_cert_cache_extensions(X509 *cert) { |
190 | if (!(cert->ex_flags & EXFLAG_SET)) { | ||
191 | CRYPTO_w_lock(CRYPTO_LOCK_X509); | ||
192 | x509v3_cache_extensions(cert); | ||
193 | CRYPTO_w_unlock(CRYPTO_LOCK_X509); | ||
194 | } | ||
195 | if (cert->ex_flags & EXFLAG_INVALID) | ||
196 | return 0; | ||
197 | return (cert->ex_flags & EXFLAG_SET); | ||
198 | } | ||
199 | |||
200 | static int | ||
201 | x509_verify_cert_self_signed(X509 *cert) | ||
202 | { | ||
203 | return (cert->ex_flags & EXFLAG_SS) ? 1 : 0; | ||
204 | } | ||
205 | |||
206 | static int | ||
207 | x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert, | ||
208 | int full_chain) | ||
187 | { | 209 | { |
188 | int i; | 210 | int i; |
189 | 211 | ||
212 | if (!x509_verify_cert_cache_extensions(cert)) | ||
213 | return 0; | ||
214 | |||
190 | for (i = 0; i < sk_X509_num(ctx->roots); i++) { | 215 | for (i = 0; i < sk_X509_num(ctx->roots); i++) { |
191 | if (X509_cmp(sk_X509_value(ctx->roots, i), cert) == 0) | 216 | if (X509_cmp(sk_X509_value(ctx->roots, i), cert) == 0) |
192 | return 1; | 217 | return !full_chain || |
218 | x509_verify_cert_self_signed(cert); | ||
193 | } | 219 | } |
220 | /* | ||
221 | * XXX what if this is a by_dir thing? this currently isn't | ||
222 | * handled so this case is a bit messed up for loonix with | ||
223 | * by directory trust bundles... | ||
224 | */ | ||
194 | return 0; | 225 | return 0; |
195 | } | 226 | } |
196 | 227 | ||
@@ -236,6 +267,46 @@ x509_verify_ctx_set_xsc_chain(struct x509_verify_ctx *ctx, | |||
236 | return 1; | 267 | return 1; |
237 | } | 268 | } |
238 | 269 | ||
270 | |||
271 | /* | ||
272 | * Save the error state and unvalidated chain off of the xsc for | ||
273 | * later. | ||
274 | */ | ||
275 | static int | ||
276 | x509_verify_ctx_save_xsc_error(struct x509_verify_ctx *ctx) | ||
277 | { | ||
278 | if (ctx->xsc != NULL && ctx->xsc->chain != NULL) { | ||
279 | sk_X509_pop_free(ctx->saved_error_chain, X509_free); | ||
280 | ctx->saved_error_chain = X509_chain_up_ref(ctx->xsc->chain); | ||
281 | if (ctx->saved_error_chain == NULL) | ||
282 | return x509_verify_cert_error(ctx, NULL, 0, | ||
283 | X509_V_ERR_OUT_OF_MEM, 0); | ||
284 | ctx->saved_error = ctx->xsc->error; | ||
285 | ctx->saved_error_depth = ctx->xsc->error_depth; | ||
286 | } | ||
287 | return 1; | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * Restore the saved error state and unvalidated chain to the xsc | ||
292 | * if we do not have a validated chain. | ||
293 | */ | ||
294 | static int | ||
295 | x509_verify_ctx_restore_xsc_error(struct x509_verify_ctx *ctx) | ||
296 | { | ||
297 | if (ctx->xsc != NULL && ctx->chains_count == 0 && | ||
298 | ctx->saved_error_chain != NULL) { | ||
299 | sk_X509_pop_free(ctx->xsc->chain, X509_free); | ||
300 | ctx->xsc->chain = X509_chain_up_ref(ctx->saved_error_chain); | ||
301 | if (ctx->xsc->chain == NULL) | ||
302 | return x509_verify_cert_error(ctx, NULL, 0, | ||
303 | X509_V_ERR_OUT_OF_MEM, 0); | ||
304 | ctx->xsc->error = ctx->saved_error; | ||
305 | ctx->xsc->error_depth = ctx->saved_error_depth; | ||
306 | } | ||
307 | return 1; | ||
308 | } | ||
309 | |||
239 | /* Add a validated chain to our list of valid chains */ | 310 | /* Add a validated chain to our list of valid chains */ |
240 | static int | 311 | static int |
241 | x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx, | 312 | x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx, |
@@ -331,6 +402,8 @@ static int | |||
331 | x509_verify_potential_parent(struct x509_verify_ctx *ctx, X509 *parent, | 402 | x509_verify_potential_parent(struct x509_verify_ctx *ctx, X509 *parent, |
332 | X509 *child) | 403 | X509 *child) |
333 | { | 404 | { |
405 | if (!x509_verify_cert_cache_extensions(parent)) | ||
406 | return 0; | ||
334 | if (ctx->xsc != NULL) | 407 | if (ctx->xsc != NULL) |
335 | return (ctx->xsc->check_issued(ctx->xsc, child, parent)); | 408 | return (ctx->xsc->check_issued(ctx->xsc, child, parent)); |
336 | 409 | ||
@@ -378,7 +451,7 @@ x509_verify_parent_signature(X509 *parent, X509 *child, | |||
378 | static int | 451 | static int |
379 | x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, | 452 | x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, |
380 | unsigned char *cert_md, int is_root_cert, X509 *candidate, | 453 | unsigned char *cert_md, int is_root_cert, X509 *candidate, |
381 | struct x509_verify_chain *current_chain) | 454 | struct x509_verify_chain *current_chain, int full_chain) |
382 | { | 455 | { |
383 | int depth = sk_X509_num(current_chain->certs); | 456 | int depth = sk_X509_num(current_chain->certs); |
384 | struct x509_verify_chain *new_chain; | 457 | struct x509_verify_chain *new_chain; |
@@ -446,7 +519,7 @@ x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, | |||
446 | } | 519 | } |
447 | } | 520 | } |
448 | 521 | ||
449 | x509_verify_build_chains(ctx, candidate, new_chain); | 522 | x509_verify_build_chains(ctx, candidate, new_chain, full_chain); |
450 | 523 | ||
451 | done: | 524 | done: |
452 | x509_verify_chain_free(new_chain); | 525 | x509_verify_chain_free(new_chain); |
@@ -470,11 +543,11 @@ x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, size_t depth, | |||
470 | 543 | ||
471 | static void | 544 | static void |
472 | x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | 545 | x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, |
473 | struct x509_verify_chain *current_chain) | 546 | struct x509_verify_chain *current_chain, int full_chain) |
474 | { | 547 | { |
475 | unsigned char cert_md[EVP_MAX_MD_SIZE] = { 0 }; | 548 | unsigned char cert_md[EVP_MAX_MD_SIZE] = { 0 }; |
476 | X509 *candidate; | 549 | X509 *candidate; |
477 | int i, depth, count, ret; | 550 | int i, depth, count, ret, is_root; |
478 | 551 | ||
479 | /* | 552 | /* |
480 | * If we are finding chains with an xsc, just stop after we have | 553 | * If we are finding chains with an xsc, just stop after we have |
@@ -519,8 +592,11 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | |||
519 | for (i = 0; i < sk_X509_num(ctx->roots); i++) { | 592 | for (i = 0; i < sk_X509_num(ctx->roots); i++) { |
520 | candidate = sk_X509_value(ctx->roots, i); | 593 | candidate = sk_X509_value(ctx->roots, i); |
521 | if (x509_verify_potential_parent(ctx, candidate, cert)) { | 594 | if (x509_verify_potential_parent(ctx, candidate, cert)) { |
595 | is_root = !full_chain || | ||
596 | x509_verify_cert_self_signed(candidate); | ||
522 | x509_verify_consider_candidate(ctx, cert, | 597 | x509_verify_consider_candidate(ctx, cert, |
523 | cert_md, 1, candidate, current_chain); | 598 | cert_md, is_root, candidate, current_chain, |
599 | full_chain); | ||
524 | } | 600 | } |
525 | } | 601 | } |
526 | /* Check for legacy mode roots */ | 602 | /* Check for legacy mode roots */ |
@@ -532,8 +608,11 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | |||
532 | } | 608 | } |
533 | if (ret > 0) { | 609 | if (ret > 0) { |
534 | if (x509_verify_potential_parent(ctx, candidate, cert)) { | 610 | if (x509_verify_potential_parent(ctx, candidate, cert)) { |
611 | is_root = !full_chain || | ||
612 | x509_verify_cert_self_signed(candidate); | ||
535 | x509_verify_consider_candidate(ctx, cert, | 613 | x509_verify_consider_candidate(ctx, cert, |
536 | cert_md, 1, candidate, current_chain); | 614 | cert_md, is_root, candidate, current_chain, |
615 | full_chain); | ||
537 | } | 616 | } |
538 | X509_free(candidate); | 617 | X509_free(candidate); |
539 | } | 618 | } |
@@ -545,7 +624,8 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert, | |||
545 | candidate = sk_X509_value(ctx->intermediates, i); | 624 | candidate = sk_X509_value(ctx->intermediates, i); |
546 | if (x509_verify_potential_parent(ctx, candidate, cert)) { | 625 | if (x509_verify_potential_parent(ctx, candidate, cert)) { |
547 | x509_verify_consider_candidate(ctx, cert, | 626 | x509_verify_consider_candidate(ctx, cert, |
548 | cert_md, 0, candidate, current_chain); | 627 | cert_md, 0, candidate, current_chain, |
628 | full_chain); | ||
549 | } | 629 | } |
550 | } | 630 | } |
551 | } | 631 | } |
@@ -973,6 +1053,7 @@ size_t | |||
973 | x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name) | 1053 | x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name) |
974 | { | 1054 | { |
975 | struct x509_verify_chain *current_chain; | 1055 | struct x509_verify_chain *current_chain; |
1056 | int retry_chain_build, full_chain = 0; | ||
976 | 1057 | ||
977 | if (ctx->roots == NULL || ctx->max_depth == 0) { | 1058 | if (ctx->roots == NULL || ctx->max_depth == 0) { |
978 | ctx->error = X509_V_ERR_INVALID_CALL; | 1059 | ctx->error = X509_V_ERR_INVALID_CALL; |
@@ -986,6 +1067,10 @@ x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name) | |||
986 | } | 1067 | } |
987 | leaf = ctx->xsc->cert; | 1068 | leaf = ctx->xsc->cert; |
988 | 1069 | ||
1070 | /* XXX */ | ||
1071 | full_chain = 1; | ||
1072 | if (ctx->xsc->param->flags & X509_V_FLAG_PARTIAL_CHAIN) | ||
1073 | full_chain = 0; | ||
989 | /* | 1074 | /* |
990 | * XXX | 1075 | * XXX |
991 | * The legacy code expects the top level cert to be | 1076 | * The legacy code expects the top level cert to be |
@@ -1024,14 +1109,45 @@ x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name) | |||
1024 | x509_verify_chain_free(current_chain); | 1109 | x509_verify_chain_free(current_chain); |
1025 | goto err; | 1110 | goto err; |
1026 | } | 1111 | } |
1027 | if (x509_verify_ctx_cert_is_root(ctx, leaf)) | 1112 | do { |
1028 | x509_verify_ctx_add_chain(ctx, current_chain); | 1113 | retry_chain_build = 0; |
1029 | else | 1114 | if (x509_verify_ctx_cert_is_root(ctx, leaf, full_chain)) |
1030 | x509_verify_build_chains(ctx, leaf, current_chain); | 1115 | x509_verify_ctx_add_chain(ctx, current_chain); |
1116 | else { | ||
1117 | x509_verify_build_chains(ctx, leaf, current_chain, | ||
1118 | full_chain); | ||
1119 | if (full_chain && ctx->chains_count == 0) { | ||
1120 | /* | ||
1121 | * Save the error state from the xsc | ||
1122 | * at this point to put back on the | ||
1123 | * xsc in case we do not find a chain | ||
1124 | * that is trusted but not a full | ||
1125 | * chain to a self signed root. This | ||
1126 | * is because the unvalidated chain is | ||
1127 | * used by the autochain batshittery | ||
1128 | * on failure and will be needed for | ||
1129 | * that. | ||
1130 | */ | ||
1131 | if (!x509_verify_ctx_save_xsc_error(ctx)) { | ||
1132 | x509_verify_chain_free(current_chain); | ||
1133 | goto err; | ||
1134 | } | ||
1135 | full_chain = 0; | ||
1136 | retry_chain_build = 1; | ||
1137 | } | ||
1138 | } | ||
1139 | } while (retry_chain_build); | ||
1031 | 1140 | ||
1032 | x509_verify_chain_free(current_chain); | 1141 | x509_verify_chain_free(current_chain); |
1033 | 1142 | ||
1034 | /* | 1143 | /* |
1144 | * Bring back the failure case we wanted to the xsc if | ||
1145 | * we saved one. | ||
1146 | */ | ||
1147 | if (!x509_verify_ctx_restore_xsc_error(ctx)) | ||
1148 | goto err; | ||
1149 | |||
1150 | /* | ||
1035 | * Safety net: | 1151 | * Safety net: |
1036 | * We could not find a validated chain, and for some reason do not | 1152 | * We could not find a validated chain, and for some reason do not |
1037 | * have an error set. | 1153 | * have an error set. |