diff options
author | beck <> | 2018-04-06 07:08:20 +0000 |
---|---|---|
committer | beck <> | 2018-04-06 07:08:20 +0000 |
commit | cbd1d6a8808038e6f357e956a343f70ecaf110f4 (patch) | |
tree | 3f536dd9c6701ce8c8c9a5fa0d5c883caa5222e2 /src | |
parent | a0522cf10ae4b806e95c44e85e22fae53f9228d6 (diff) | |
download | openbsd-cbd1d6a8808038e6f357e956a343f70ecaf110f4.tar.gz openbsd-cbd1d6a8808038e6f357e956a343f70ecaf110f4.tar.bz2 openbsd-cbd1d6a8808038e6f357e956a343f70ecaf110f4.zip |
poison for X509_VERIFY_PARAM's
Tighten up checks for various X509_VERIFY_PARAM functions, and
allow for the verify param to be poisoned (preculding future
successful cert validation) if the setting of host, ip, or email
for certificate validation fails. (since many callers do not
check the return code in the wild and blunder along anyway)
Inspired by some discussions with Adam Langley.
ok jsing@
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libcrypto/man/X509_VERIFY_PARAM_set_flags.3 | 67 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/vpm_int.h | 3 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_vfy.c | 13 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_vpm.c | 69 |
4 files changed, 107 insertions, 45 deletions
diff --git a/src/lib/libcrypto/man/X509_VERIFY_PARAM_set_flags.3 b/src/lib/libcrypto/man/X509_VERIFY_PARAM_set_flags.3 index 4f3261c975..9c0150700d 100644 --- a/src/lib/libcrypto/man/X509_VERIFY_PARAM_set_flags.3 +++ b/src/lib/libcrypto/man/X509_VERIFY_PARAM_set_flags.3 | |||
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: X509_VERIFY_PARAM_set_flags.3,v 1.12 2018/03/23 14:26:40 schwarze Exp $ | 1 | .\" $OpenBSD: X509_VERIFY_PARAM_set_flags.3,v 1.13 2018/04/06 07:08:20 beck Exp $ |
2 | .\" full merge up to: OpenSSL d33def66 Feb 9 14:17:13 2016 -0500 | 2 | .\" full merge up to: OpenSSL d33def66 Feb 9 14:17:13 2016 -0500 |
3 | .\" selective merge up to: OpenSSL 48e5119a Jan 19 10:49:22 2018 +0100 | 3 | .\" selective merge up to: OpenSSL 48e5119a Jan 19 10:49:22 2018 +0100 |
4 | .\" | 4 | .\" |
@@ -68,7 +68,7 @@ | |||
68 | .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | 68 | .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
69 | .\" OF THE POSSIBILITY OF SUCH DAMAGE. | 69 | .\" OF THE POSSIBILITY OF SUCH DAMAGE. |
70 | .\" | 70 | .\" |
71 | .Dd $Mdocdate: March 23 2018 $ | 71 | .Dd $Mdocdate: April 6 2018 $ |
72 | .Dt X509_VERIFY_PARAM_SET_FLAGS 3 | 72 | .Dt X509_VERIFY_PARAM_SET_FLAGS 3 |
73 | .Os | 73 | .Os |
74 | .Sh NAME | 74 | .Sh NAME |
@@ -344,14 +344,14 @@ is | |||
344 | .Dv NULL | 344 | .Dv NULL |
345 | or empty, the list of hostnames is cleared, and name checks are not | 345 | or empty, the list of hostnames is cleared, and name checks are not |
346 | performed on the peer certificate. | 346 | performed on the peer certificate. |
347 | If | 347 | .Fa namelen |
348 | should be set to the length of | ||
349 | .Fa name . | ||
350 | For historical compatibility, if | ||
348 | .Fa name | 351 | .Fa name |
349 | is NUL-terminated, | 352 | is NUL-terminated, |
350 | .Fa namelen | 353 | .Fa namelen |
351 | may be zero, otherwise | 354 | may be specified as zero. |
352 | .Fa namelen | ||
353 | must be set to the length of | ||
354 | .Fa name . | ||
355 | When a hostname is specified, certificate verification automatically | 355 | When a hostname is specified, certificate verification automatically |
356 | invokes | 356 | invokes |
357 | .Xr X509_check_host 3 | 357 | .Xr X509_check_host 3 |
@@ -360,6 +360,10 @@ with flags equal to the | |||
360 | argument given to | 360 | argument given to |
361 | .Fn X509_VERIFY_PARAM_set_hostflags | 361 | .Fn X509_VERIFY_PARAM_set_hostflags |
362 | (default zero). | 362 | (default zero). |
363 | .Fn X509_VERIFY_PARAM_set1_host | ||
364 | will fail if | ||
365 | .Fa name | ||
366 | contains any embedded 0 bytes. | ||
363 | .Pp | 367 | .Pp |
364 | .Fn X509_VERIFY_PARAM_add1_host | 368 | .Fn X509_VERIFY_PARAM_add1_host |
365 | adds | 369 | adds |
@@ -376,6 +380,18 @@ No change is made if | |||
376 | is | 380 | is |
377 | .Dv NULL | 381 | .Dv NULL |
378 | or empty. | 382 | or empty. |
383 | .Fa namelen | ||
384 | should be set to the length of | ||
385 | .Fa name . | ||
386 | For historical compatibility, if | ||
387 | .Fa name | ||
388 | is NUL-terminated, | ||
389 | .Fa namelen | ||
390 | may be specified as zero. | ||
391 | .Fn X509_VERIFY_PARAM_add1_host | ||
392 | will fail if | ||
393 | .Fa name | ||
394 | contains any embedded 0 bytes. | ||
379 | When multiple names are configured, the peer is considered verified when | 395 | When multiple names are configured, the peer is considered verified when |
380 | any name matches. | 396 | any name matches. |
381 | .Pp | 397 | .Pp |
@@ -390,14 +406,18 @@ identifier respectively. | |||
390 | .Fn X509_VERIFY_PARAM_set1_email | 406 | .Fn X509_VERIFY_PARAM_set1_email |
391 | sets the expected RFC822 email address to | 407 | sets the expected RFC822 email address to |
392 | .Fa email . | 408 | .Fa email . |
393 | If | 409 | .Fa emaillen |
410 | should be set to the length of | ||
411 | .Fa email . | ||
412 | For historical compatibility, if | ||
394 | .Fa email | 413 | .Fa email |
395 | is NUL-terminated, | 414 | is NUL-terminated, |
396 | .Fa emaillen | 415 | .Fa emaillen |
397 | may be zero, otherwise | 416 | may be specified as zero, |
398 | .Fa emaillen | 417 | .Fn X509_VERIFY_PARAM_set1_email |
399 | must be set to the length of | 418 | will fail if |
400 | .Fa email . | 419 | .Fa email |
420 | is NULL, an empty string, or contains embedded 0 bytes. | ||
401 | When an email address is specified, certificate verification | 421 | When an email address is specified, certificate verification |
402 | automatically invokes | 422 | automatically invokes |
403 | .Xr X509_check_email 3 . | 423 | .Xr X509_check_email 3 . |
@@ -410,6 +430,12 @@ The | |||
410 | argument is in binary format, in network byte-order, and | 430 | argument is in binary format, in network byte-order, and |
411 | .Fa iplen | 431 | .Fa iplen |
412 | must be set to 4 for IPv4 and 16 for IPv6. | 432 | must be set to 4 for IPv4 and 16 for IPv6. |
433 | .Fn X509_VERIFY_PARAM_set1_ip | ||
434 | will fail if | ||
435 | .Fa ip | ||
436 | is NULL or if | ||
437 | .Fa iplen | ||
438 | is not 4 or 16. | ||
413 | When an IP address is specified, | 439 | When an IP address is specified, |
414 | certificate verification automatically invokes | 440 | certificate verification automatically invokes |
415 | .Xr X509_check_ip 3 . | 441 | .Xr X509_check_ip 3 . |
@@ -422,6 +448,10 @@ The | |||
422 | argument is a NUL-terminal ASCII string: | 448 | argument is a NUL-terminal ASCII string: |
423 | dotted decimal quad for IPv4 and colon-separated hexadecimal for IPv6. | 449 | dotted decimal quad for IPv4 and colon-separated hexadecimal for IPv6. |
424 | The condensed "::" notation is supported for IPv6 addresses. | 450 | The condensed "::" notation is supported for IPv6 addresses. |
451 | .Fn X509_VERIFY_PARAM_set1_ip_asc | ||
452 | will fail if | ||
453 | .Fa ipasc | ||
454 | is unparsable. | ||
425 | .Pp | 455 | .Pp |
426 | .Fn X509_VERIFY_PARAM_add0_table | 456 | .Fn X509_VERIFY_PARAM_add0_table |
427 | adds | 457 | adds |
@@ -476,14 +506,23 @@ on allocation failure. | |||
476 | .Fn X509_VERIFY_PARAM_set_trust , | 506 | .Fn X509_VERIFY_PARAM_set_trust , |
477 | .Fn X509_VERIFY_PARAM_add0_policy , | 507 | .Fn X509_VERIFY_PARAM_add0_policy , |
478 | .Fn X509_VERIFY_PARAM_set1_policies , | 508 | .Fn X509_VERIFY_PARAM_set1_policies , |
509 | and | ||
510 | .Fn X509_VERIFY_PARAM_add0_table | ||
511 | return 1 for success or 0 for failure. | ||
512 | .Pp | ||
479 | .Fn X509_VERIFY_PARAM_set1_host , | 513 | .Fn X509_VERIFY_PARAM_set1_host , |
480 | .Fn X509_VERIFY_PARAM_add1_host , | 514 | .Fn X509_VERIFY_PARAM_add1_host , |
481 | .Fn X509_VERIFY_PARAM_set1_email , | 515 | .Fn X509_VERIFY_PARAM_set1_email , |
482 | .Fn X509_VERIFY_PARAM_set1_ip , | 516 | .Fn X509_VERIFY_PARAM_set1_ip , |
483 | .Fn X509_VERIFY_PARAM_set1_ip_asc , | ||
484 | and | 517 | and |
485 | .Fn X509_VERIFY_PARAM_add0_table | 518 | .Fn X509_VERIFY_PARAM_set1_ip_asc , |
486 | return 1 for success or 0 for failure. | 519 | return 1 for success or 0 for failure. |
520 | A failure from these routines will poison | ||
521 | the | ||
522 | .Vt X509_VERIFY_PARAM | ||
523 | object so that future calls to | ||
524 | .Xr X509_verify_cert | ||
525 | using the poisoned object will fail. | ||
487 | .Pp | 526 | .Pp |
488 | .Fn X509_VERIFY_PARAM_get_flags | 527 | .Fn X509_VERIFY_PARAM_get_flags |
489 | returns the current verification flags. | 528 | returns the current verification flags. |
diff --git a/src/lib/libcrypto/x509/vpm_int.h b/src/lib/libcrypto/x509/vpm_int.h index 6c8061c847..7fc9fef761 100644 --- a/src/lib/libcrypto/x509/vpm_int.h +++ b/src/lib/libcrypto/x509/vpm_int.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: vpm_int.h,v 1.3 2016/12/21 15:49:29 jsing Exp $ */ | 1 | /* $OpenBSD: vpm_int.h,v 1.4 2018/04/06 07:08:20 beck Exp $ */ |
2 | /* | 2 | /* |
3 | * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project | 3 | * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project |
4 | * 2013. | 4 | * 2013. |
@@ -69,6 +69,7 @@ struct X509_VERIFY_PARAM_ID_st { | |||
69 | size_t emaillen; | 69 | size_t emaillen; |
70 | unsigned char *ip; /* If not NULL IP address to match */ | 70 | unsigned char *ip; /* If not NULL IP address to match */ |
71 | size_t iplen; /* Length of IP address */ | 71 | size_t iplen; /* Length of IP address */ |
72 | int poisoned; | ||
72 | }; | 73 | }; |
73 | 74 | ||
74 | __END_HIDDEN_DECLS | 75 | __END_HIDDEN_DECLS |
diff --git a/src/lib/libcrypto/x509/x509_vfy.c b/src/lib/libcrypto/x509/x509_vfy.c index c8ccae5029..8392f509e7 100644 --- a/src/lib/libcrypto/x509/x509_vfy.c +++ b/src/lib/libcrypto/x509/x509_vfy.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_vfy.c,v 1.68 2018/02/22 17:11:30 jsing Exp $ */ | 1 | /* $OpenBSD: x509_vfy.c,v 1.69 2018/04/06 07:08:20 beck Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -182,10 +182,13 @@ check_id_error(X509_STORE_CTX *ctx, int errcode) | |||
182 | static int | 182 | static int |
183 | check_hosts(X509 *x, X509_VERIFY_PARAM_ID *id) | 183 | check_hosts(X509 *x, X509_VERIFY_PARAM_ID *id) |
184 | { | 184 | { |
185 | size_t i; | 185 | size_t i, n; |
186 | size_t n = sk_OPENSSL_STRING_num(id->hosts); | ||
187 | char *name; | 186 | char *name; |
188 | 187 | ||
188 | if (id->poisoned) | ||
189 | return 0; | ||
190 | |||
191 | n = sk_OPENSSL_STRING_num(id->hosts); | ||
189 | free(id->peername); | 192 | free(id->peername); |
190 | id->peername = NULL; | 193 | id->peername = NULL; |
191 | 194 | ||
@@ -205,6 +208,10 @@ check_id(X509_STORE_CTX *ctx) | |||
205 | X509_VERIFY_PARAM_ID *id = vpm->id; | 208 | X509_VERIFY_PARAM_ID *id = vpm->id; |
206 | X509 *x = ctx->cert; | 209 | X509 *x = ctx->cert; |
207 | 210 | ||
211 | if (id->poisoned) | ||
212 | if (!check_id_error(ctx, X509_V_ERR_INVALID_CALL)) | ||
213 | return 0; | ||
214 | |||
208 | if (id->hosts && check_hosts(x, id) <= 0) { | 215 | if (id->hosts && check_hosts(x, id) <= 0) { |
209 | if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH)) | 216 | if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH)) |
210 | return 0; | 217 | return 0; |
diff --git a/src/lib/libcrypto/x509/x509_vpm.c b/src/lib/libcrypto/x509/x509_vpm.c index 0897137697..baebcf7bca 100644 --- a/src/lib/libcrypto/x509/x509_vpm.c +++ b/src/lib/libcrypto/x509/x509_vpm.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_vpm.c,v 1.17 2018/03/22 15:54:46 beck Exp $ */ | 1 | /* $OpenBSD: x509_vpm.c,v 1.18 2018/04/06 07:08:20 beck Exp $ */ |
2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
3 | * project 2004. | 3 | * project 2004. |
4 | */ | 4 | */ |
@@ -125,7 +125,7 @@ sk_deep_copy(void *sk_void, void *copy_func_void, void *free_func_void) | |||
125 | } | 125 | } |
126 | 126 | ||
127 | static int | 127 | static int |
128 | int_x509_param_set_hosts(X509_VERIFY_PARAM_ID *id, int mode, | 128 | x509_param_set_hosts_internal(X509_VERIFY_PARAM_ID *id, int mode, |
129 | const char *name, size_t namelen) | 129 | const char *name, size_t namelen) |
130 | { | 130 | { |
131 | char *copy; | 131 | char *copy; |
@@ -134,7 +134,6 @@ int_x509_param_set_hosts(X509_VERIFY_PARAM_ID *id, int mode, | |||
134 | namelen = strlen(name); | 134 | namelen = strlen(name); |
135 | /* | 135 | /* |
136 | * Refuse names with embedded NUL bytes. | 136 | * Refuse names with embedded NUL bytes. |
137 | * XXX: Do we need to push an error onto the error stack? | ||
138 | */ | 137 | */ |
139 | if (name && memchr(name, '\0', namelen)) | 138 | if (name && memchr(name, '\0', namelen)) |
140 | return 0; | 139 | return 0; |
@@ -197,6 +196,7 @@ x509_verify_param_zero(X509_VERIFY_PARAM *param) | |||
197 | free(paramid->ip); | 196 | free(paramid->ip); |
198 | paramid->ip = NULL; | 197 | paramid->ip = NULL; |
199 | paramid->iplen = 0; | 198 | paramid->iplen = 0; |
199 | paramid->poisoned = 0; | ||
200 | } | 200 | } |
201 | 201 | ||
202 | X509_VERIFY_PARAM * | 202 | X509_VERIFY_PARAM * |
@@ -367,24 +367,28 @@ X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, const X509_VERIFY_PARAM *from) | |||
367 | } | 367 | } |
368 | 368 | ||
369 | static int | 369 | static int |
370 | int_x509_param_set1(char **pdest, size_t *pdestlen, const char *src, | 370 | x509_param_set1_internal(char **pdest, size_t *pdestlen, const char *src, |
371 | size_t srclen) | 371 | size_t srclen, int nonul) |
372 | { | 372 | { |
373 | char *tmp; | 373 | char *tmp; |
374 | if (src) { | 374 | |
375 | if (srclen == 0) { | 375 | if (src == NULL) |
376 | if ((tmp = strdup(src)) == NULL) | 376 | return 0; |
377 | return 0; | 377 | |
378 | srclen = strlen(src); | 378 | if (srclen == 0) { |
379 | } else { | 379 | srclen = strlen(src); |
380 | if ((tmp = malloc(srclen)) == NULL) | 380 | if (srclen == 0) |
381 | return 0; | 381 | return 0; |
382 | memcpy(tmp, src, srclen); | 382 | if ((tmp = strdup(src)) == NULL) |
383 | } | 383 | return 0; |
384 | } else { | 384 | } else { |
385 | tmp = NULL; | 385 | if (nonul && memchr(src, '\0', srclen)) |
386 | srclen = 0; | 386 | return 0; |
387 | if ((tmp = malloc(srclen)) == NULL) | ||
388 | return 0; | ||
389 | memcpy(tmp, src, srclen); | ||
387 | } | 390 | } |
391 | |||
388 | if (*pdest) | 392 | if (*pdest) |
389 | free(*pdest); | 393 | free(*pdest); |
390 | *pdest = tmp; | 394 | *pdest = tmp; |
@@ -505,14 +509,20 @@ int | |||
505 | X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, | 509 | X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, |
506 | const char *name, size_t namelen) | 510 | const char *name, size_t namelen) |
507 | { | 511 | { |
508 | return int_x509_param_set_hosts(param->id, SET_HOST, name, namelen); | 512 | if (x509_param_set_hosts_internal(param->id, SET_HOST, name, namelen)) |
513 | return 1; | ||
514 | param->id->poisoned = 1; | ||
515 | return 0; | ||
509 | } | 516 | } |
510 | 517 | ||
511 | int | 518 | int |
512 | X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, | 519 | X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, |
513 | const char *name, size_t namelen) | 520 | const char *name, size_t namelen) |
514 | { | 521 | { |
515 | return int_x509_param_set_hosts(param->id, ADD_HOST, name, namelen); | 522 | if (x509_param_set_hosts_internal(param->id, ADD_HOST, name, namelen)) |
523 | return 1; | ||
524 | param->id->poisoned = 1; | ||
525 | return 0; | ||
516 | } | 526 | } |
517 | 527 | ||
518 | void | 528 | void |
@@ -531,18 +541,25 @@ int | |||
531 | X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, const char *email, | 541 | X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, const char *email, |
532 | size_t emaillen) | 542 | size_t emaillen) |
533 | { | 543 | { |
534 | return int_x509_param_set1(¶m->id->email, ¶m->id->emaillen, | 544 | if (x509_param_set1_internal(¶m->id->email, ¶m->id->emaillen, |
535 | email, emaillen); | 545 | email, emaillen, 1)) |
546 | return 1; | ||
547 | param->id->poisoned = 1; | ||
548 | return 0; | ||
536 | } | 549 | } |
537 | 550 | ||
538 | int | 551 | int |
539 | X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, const unsigned char *ip, | 552 | X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, const unsigned char *ip, |
540 | size_t iplen) | 553 | size_t iplen) |
541 | { | 554 | { |
542 | if (iplen != 0 && iplen != 4 && iplen != 16) | 555 | if (iplen != 4 && iplen != 16) |
543 | return 0; | 556 | goto err; |
544 | return int_x509_param_set1((char **)¶m->id->ip, ¶m->id->iplen, | 557 | if (x509_param_set1_internal((char **)¶m->id->ip, ¶m->id->iplen, |
545 | (char *)ip, iplen); | 558 | (char *)ip, iplen, 0)) |
559 | return 1; | ||
560 | err: | ||
561 | param->id->poisoned = 1; | ||
562 | return 0; | ||
546 | } | 563 | } |
547 | 564 | ||
548 | int | 565 | int |
@@ -552,8 +569,6 @@ X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc) | |||
552 | size_t iplen; | 569 | size_t iplen; |
553 | 570 | ||
554 | iplen = (size_t)a2i_ipadd(ipout, ipasc); | 571 | iplen = (size_t)a2i_ipadd(ipout, ipasc); |
555 | if (iplen == 0) | ||
556 | return 0; | ||
557 | return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen); | 572 | return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen); |
558 | } | 573 | } |
559 | 574 | ||