diff options
Diffstat (limited to '')
| -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 | ||
