diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libcrypto/x509/x509_internal.h | 3 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_verify.c | 88 |
2 files changed, 79 insertions, 12 deletions
diff --git a/src/lib/libcrypto/x509/x509_internal.h b/src/lib/libcrypto/x509/x509_internal.h index 9d69055afa..f6887be5fb 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.3 2020/09/15 11:55:14 beck Exp $ */ | 1 | /* $OpenBSD: x509_internal.h,v 1.4 2020/11/11 18:49:34 jsing Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> | 3 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> |
4 | * | 4 | * |
@@ -57,6 +57,7 @@ struct x509_constraints_names { | |||
57 | 57 | ||
58 | struct x509_verify_chain { | 58 | struct x509_verify_chain { |
59 | STACK_OF(X509) *certs; /* Kept in chain order, includes leaf */ | 59 | STACK_OF(X509) *certs; /* Kept in chain order, includes leaf */ |
60 | int *cert_errors; /* Verify error for each cert in chain. */ | ||
60 | struct x509_constraints_names *names; /* All names from all certs */ | 61 | struct x509_constraints_names *names; /* All names from all certs */ |
61 | }; | 62 | }; |
62 | 63 | ||
diff --git a/src/lib/libcrypto/x509/x509_verify.c b/src/lib/libcrypto/x509/x509_verify.c index c3923a88d5..c76a5e103e 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.18 2020/11/03 17:43:01 jsing Exp $ */ | 1 | /* $OpenBSD: x509_verify.c,v 1.19 2020/11/11 18:49:34 jsing Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> | 3 | * Copyright (c) 2020 Bob Beck <beck@openbsd.org> |
4 | * | 4 | * |
@@ -15,7 +15,7 @@ | |||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | /* x509_verify - inspired by golang's crypto/x509/Verify */ | 18 | /* x509_verify - inspired by golang's crypto/x509.Verify */ |
19 | 19 | ||
20 | #include <errno.h> | 20 | #include <errno.h> |
21 | #include <stdio.h> | 21 | #include <stdio.h> |
@@ -49,6 +49,9 @@ x509_verify_chain_new(void) | |||
49 | goto err; | 49 | goto err; |
50 | if ((chain->certs = sk_X509_new_null()) == NULL) | 50 | if ((chain->certs = sk_X509_new_null()) == NULL) |
51 | goto err; | 51 | goto err; |
52 | if ((chain->cert_errors = calloc(X509_VERIFY_MAX_CHAIN_CERTS, | ||
53 | sizeof(int))) == NULL) | ||
54 | goto err; | ||
52 | if ((chain->names = x509_constraints_names_new()) == NULL) | 55 | if ((chain->names = x509_constraints_names_new()) == NULL) |
53 | goto err; | 56 | goto err; |
54 | 57 | ||
@@ -63,6 +66,8 @@ x509_verify_chain_clear(struct x509_verify_chain *chain) | |||
63 | { | 66 | { |
64 | sk_X509_pop_free(chain->certs, X509_free); | 67 | sk_X509_pop_free(chain->certs, X509_free); |
65 | chain->certs = NULL; | 68 | chain->certs = NULL; |
69 | free(chain->cert_errors); | ||
70 | chain->cert_errors = NULL; | ||
66 | x509_constraints_names_free(chain->names); | 71 | x509_constraints_names_free(chain->names); |
67 | chain->names = NULL; | 72 | chain->names = NULL; |
68 | } | 73 | } |
@@ -85,6 +90,11 @@ x509_verify_chain_dup(struct x509_verify_chain *chain) | |||
85 | goto err; | 90 | goto err; |
86 | if ((new_chain->certs = X509_chain_up_ref(chain->certs)) == NULL) | 91 | if ((new_chain->certs = X509_chain_up_ref(chain->certs)) == NULL) |
87 | goto err; | 92 | goto err; |
93 | if ((new_chain->cert_errors = calloc(X509_VERIFY_MAX_CHAIN_CERTS, | ||
94 | sizeof(int))) == NULL) | ||
95 | goto err; | ||
96 | memcpy(new_chain->cert_errors, chain->cert_errors, | ||
97 | X509_VERIFY_MAX_CHAIN_CERTS * sizeof(int)); | ||
88 | if ((new_chain->names = | 98 | if ((new_chain->names = |
89 | x509_constraints_names_dup(chain->names)) == NULL) | 99 | x509_constraints_names_dup(chain->names)) == NULL) |
90 | goto err; | 100 | goto err; |
@@ -99,18 +109,32 @@ x509_verify_chain_append(struct x509_verify_chain *chain, X509 *cert, | |||
99 | int *error) | 109 | int *error) |
100 | { | 110 | { |
101 | int verify_err = X509_V_ERR_UNSPECIFIED; | 111 | int verify_err = X509_V_ERR_UNSPECIFIED; |
112 | size_t idx; | ||
102 | 113 | ||
103 | if (!x509_constraints_extract_names(chain->names, cert, | 114 | if (!x509_constraints_extract_names(chain->names, cert, |
104 | sk_X509_num(chain->certs) == 0, &verify_err)) { | 115 | sk_X509_num(chain->certs) == 0, &verify_err)) { |
105 | *error = verify_err; | 116 | *error = verify_err; |
106 | return 0; | 117 | return 0; |
107 | } | 118 | } |
119 | |||
108 | X509_up_ref(cert); | 120 | X509_up_ref(cert); |
109 | if (!sk_X509_push(chain->certs, cert)) { | 121 | if (!sk_X509_push(chain->certs, cert)) { |
110 | X509_free(cert); | 122 | X509_free(cert); |
111 | *error = X509_V_ERR_OUT_OF_MEM; | 123 | *error = X509_V_ERR_OUT_OF_MEM; |
112 | return 0; | 124 | return 0; |
113 | } | 125 | } |
126 | |||
127 | idx = sk_X509_num(chain->certs) - 1; | ||
128 | chain->cert_errors[idx] = *error; | ||
129 | |||
130 | /* | ||
131 | * We've just added the issuer for the previous certificate, | ||
132 | * clear its error if appropriate. | ||
133 | */ | ||
134 | if (idx > 1 && chain->cert_errors[idx - 1] == | ||
135 | X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) | ||
136 | chain->cert_errors[idx - 1] = X509_V_OK; | ||
137 | |||
114 | return 1; | 138 | return 1; |
115 | } | 139 | } |
116 | 140 | ||
@@ -171,10 +195,11 @@ x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert) | |||
171 | 195 | ||
172 | static int | 196 | static int |
173 | x509_verify_ctx_set_xsc_chain(struct x509_verify_ctx *ctx, | 197 | x509_verify_ctx_set_xsc_chain(struct x509_verify_ctx *ctx, |
174 | struct x509_verify_chain *chain) | 198 | struct x509_verify_chain *chain, int set_error) |
175 | { | 199 | { |
176 | size_t depth; | ||
177 | X509 *last = x509_verify_chain_last(chain); | 200 | X509 *last = x509_verify_chain_last(chain); |
201 | size_t depth; | ||
202 | int i; | ||
178 | 203 | ||
179 | if (ctx->xsc == NULL) | 204 | if (ctx->xsc == NULL) |
180 | return 1; | 205 | return 1; |
@@ -189,6 +214,19 @@ x509_verify_ctx_set_xsc_chain(struct x509_verify_ctx *ctx, | |||
189 | if (ctx->xsc->chain == NULL) | 214 | if (ctx->xsc->chain == NULL) |
190 | return x509_verify_cert_error(ctx, last, depth, | 215 | return x509_verify_cert_error(ctx, last, depth, |
191 | X509_V_ERR_OUT_OF_MEM, 0); | 216 | X509_V_ERR_OUT_OF_MEM, 0); |
217 | |||
218 | if (set_error) { | ||
219 | ctx->xsc->error = X509_V_OK; | ||
220 | ctx->xsc->error_depth = 0; | ||
221 | for (i = 0; i < sk_X509_num(chain->certs); i++) { | ||
222 | if (chain->cert_errors[i] != X509_V_OK) { | ||
223 | ctx->xsc->error = chain->cert_errors[i]; | ||
224 | ctx->xsc->error_depth = i; | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
192 | return 1; | 230 | return 1; |
193 | } | 231 | } |
194 | 232 | ||
@@ -208,6 +246,11 @@ x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx, | |||
208 | return x509_verify_cert_error(ctx, last, depth, | 246 | return x509_verify_cert_error(ctx, last, depth, |
209 | X509_V_ERR_CERT_CHAIN_TOO_LONG, 0); | 247 | X509_V_ERR_CERT_CHAIN_TOO_LONG, 0); |
210 | 248 | ||
249 | /* Clear a get issuer failure for a root certificate. */ | ||
250 | if (chain->cert_errors[depth] == | ||
251 | X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) | ||
252 | chain->cert_errors[depth] = X509_V_OK; | ||
253 | |||
211 | /* | 254 | /* |
212 | * If we have a legacy xsc, choose a validated chain, | 255 | * If we have a legacy xsc, choose a validated chain, |
213 | * and apply the extensions, revocation, and policy checks | 256 | * and apply the extensions, revocation, and policy checks |
@@ -217,7 +260,11 @@ x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx, | |||
217 | * knobs that are there for the fiddling. | 260 | * knobs that are there for the fiddling. |
218 | */ | 261 | */ |
219 | if (ctx->xsc != NULL) { | 262 | if (ctx->xsc != NULL) { |
220 | if (!x509_verify_ctx_set_xsc_chain(ctx, chain)) | 263 | /* These may be set in one of the following calls. */ |
264 | ctx->xsc->error = X509_V_OK; | ||
265 | ctx->xsc->error_depth = 0; | ||
266 | |||
267 | if (!x509_verify_ctx_set_xsc_chain(ctx, chain, 0)) | ||
221 | return 0; | 268 | return 0; |
222 | 269 | ||
223 | /* | 270 | /* |
@@ -241,6 +288,18 @@ x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx, | |||
241 | 288 | ||
242 | if (!x509_vfy_check_policy(ctx->xsc)) | 289 | if (!x509_vfy_check_policy(ctx->xsc)) |
243 | return 0; | 290 | return 0; |
291 | |||
292 | /* | ||
293 | * The above checks may have set ctx->xsc->error and | ||
294 | * ctx->xsc->error_depth - save these for later on. | ||
295 | */ | ||
296 | if (ctx->xsc->error != X509_V_OK) { | ||
297 | if (ctx->xsc->error_depth < 0 || | ||
298 | ctx->xsc->error_depth >= X509_VERIFY_MAX_CHAIN_CERTS) | ||
299 | return 0; | ||
300 | chain->cert_errors[ctx->xsc->error_depth] = | ||
301 | ctx->xsc->error; | ||
302 | } | ||
244 | } | 303 | } |
245 | /* | 304 | /* |
246 | * no xsc means we are being called from the non-legacy API, | 305 | * no xsc means we are being called from the non-legacy API, |
@@ -350,8 +409,7 @@ x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, | |||
350 | return 0; | 409 | return 0; |
351 | } | 410 | } |
352 | if (!x509_verify_chain_append(new_chain, candidate, &ctx->error)) { | 411 | if (!x509_verify_chain_append(new_chain, candidate, &ctx->error)) { |
353 | x509_verify_cert_error(ctx, candidate, depth, | 412 | x509_verify_cert_error(ctx, candidate, depth, ctx->error, 0); |
354 | ctx->error, 0); | ||
355 | x509_verify_chain_free(new_chain); | 413 | x509_verify_chain_free(new_chain); |
356 | return 0; | 414 | return 0; |
357 | } | 415 | } |
@@ -362,7 +420,7 @@ x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert, | |||
362 | * give up. | 420 | * give up. |
363 | */ | 421 | */ |
364 | if (is_root_cert) { | 422 | if (is_root_cert) { |
365 | if (!x509_verify_ctx_set_xsc_chain(ctx, new_chain)) { | 423 | if (!x509_verify_ctx_set_xsc_chain(ctx, new_chain, 0)) { |
366 | x509_verify_chain_free(new_chain); | 424 | x509_verify_chain_free(new_chain); |
367 | return 0; | 425 | return 0; |
368 | } | 426 | } |
@@ -931,16 +989,24 @@ x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name) | |||
931 | * We could not find a validated chain, and for some reason do not | 989 | * We could not find a validated chain, and for some reason do not |
932 | * have an error set. | 990 | * have an error set. |
933 | */ | 991 | */ |
934 | if (ctx->chains_count == 0 && ctx->error == 0) | 992 | if (ctx->chains_count == 0 && ctx->error == 0) { |
935 | ctx->error = X509_V_ERR_UNSPECIFIED; | 993 | ctx->error = X509_V_ERR_UNSPECIFIED; |
994 | if (ctx->xsc != NULL && ctx->xsc->error != 0) | ||
995 | ctx->error = ctx->xsc->error; | ||
996 | |||
997 | } | ||
936 | 998 | ||
937 | /* Clear whatever errors happened if we have any validated chain */ | 999 | /* Clear whatever errors happened if we have any validated chain */ |
938 | if (ctx->chains_count > 0) | 1000 | if (ctx->chains_count > 0) |
939 | ctx->error = X509_V_OK; | 1001 | ctx->error = X509_V_OK; |
940 | 1002 | ||
941 | if (ctx->xsc != NULL) { | 1003 | if (ctx->xsc != NULL) { |
942 | ctx->xsc->error = ctx->error; | 1004 | /* Take the first chain we found. */ |
943 | return ctx->xsc->verify_cb(ctx->chains_count, ctx->xsc); | 1005 | if (ctx->chains_count > 0) { |
1006 | if (!x509_verify_ctx_set_xsc_chain(ctx, ctx->chains[0], 1)) | ||
1007 | goto err; | ||
1008 | } | ||
1009 | return ctx->xsc->verify_cb(ctx->chains_count > 0, ctx->xsc); | ||
944 | } | 1010 | } |
945 | return (ctx->chains_count); | 1011 | return (ctx->chains_count); |
946 | 1012 | ||