diff options
author | beck <> | 2017-11-28 23:32:00 +0000 |
---|---|---|
committer | beck <> | 2017-11-28 23:32:00 +0000 |
commit | aa9c99e53a08fd5b5178e337b1082d178fb34c07 (patch) | |
tree | b61427f044550d21a63392cc8723dfb4fd807aa3 | |
parent | 8e3da22d9e96b1f66fa86b077a8226eff4b85e17 (diff) | |
download | openbsd-aa9c99e53a08fd5b5178e337b1082d178fb34c07.tar.gz openbsd-aa9c99e53a08fd5b5178e337b1082d178fb34c07.tar.bz2 openbsd-aa9c99e53a08fd5b5178e337b1082d178fb34c07.zip |
Add option -i to allow oscpcheck to be used to validate an on-disk staple
ok claudio@ benno@
-rw-r--r-- | src/usr.sbin/ocspcheck/ocspcheck.8 | 14 | ||||
-rw-r--r-- | src/usr.sbin/ocspcheck/ocspcheck.c | 138 |
2 files changed, 103 insertions, 49 deletions
diff --git a/src/usr.sbin/ocspcheck/ocspcheck.8 b/src/usr.sbin/ocspcheck/ocspcheck.8 index dabac38a65..2a3f2d6187 100644 --- a/src/usr.sbin/ocspcheck/ocspcheck.8 +++ b/src/usr.sbin/ocspcheck/ocspcheck.8 | |||
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: ocspcheck.8,v 1.7 2017/10/17 22:47:58 schwarze Exp $ | 1 | .\" $OpenBSD: ocspcheck.8,v 1.8 2017/11/28 23:32:00 beck Exp $ |
2 | .\" | 2 | .\" |
3 | .\" Copyright (c) 2017 Bob Beck <beck@openbsd.org> | 3 | .\" Copyright (c) 2017 Bob Beck <beck@openbsd.org> |
4 | .\" | 4 | .\" |
@@ -14,7 +14,7 @@ | |||
14 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 14 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
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 | .Dd $Mdocdate: October 17 2017 $ | 17 | .Dd $Mdocdate: November 28 2017 $ |
18 | .Dt OCSPCHECK 8 | 18 | .Dt OCSPCHECK 8 |
19 | .Os | 19 | .Os |
20 | .Sh NAME | 20 | .Sh NAME |
@@ -45,10 +45,18 @@ By default no certificates are used beyond those in the | |||
45 | certificate chain provided by the | 45 | certificate chain provided by the |
46 | .Ar file | 46 | .Ar file |
47 | argument. | 47 | argument. |
48 | .It Fl i Ar staplefile | ||
49 | Specify an input filename from which a DER encoded OCSP response | ||
50 | will be read instead of fetching it from the OCSP server. | ||
51 | A filename | ||
52 | of | ||
53 | .Sq - | ||
54 | will read the response from standard input. | ||
48 | .It Fl N | 55 | .It Fl N |
49 | Do not use a nonce value in the OCSP request, or validate that the | 56 | Do not use a nonce value in the OCSP request, or validate that the |
50 | nonce was returned in the OCSP response. | 57 | nonce was returned in the OCSP response. |
51 | By default a nonce is always used and validated. | 58 | By default a nonce is always used and validated when retrieving |
59 | a response from an OCSP server. | ||
52 | The use of this flag is a security risk as it will allow OCSP | 60 | The use of this flag is a security risk as it will allow OCSP |
53 | responses to be replayed. | 61 | responses to be replayed. |
54 | It should not be used unless the OCSP server does not support the | 62 | It should not be used unless the OCSP server does not support the |
diff --git a/src/usr.sbin/ocspcheck/ocspcheck.c b/src/usr.sbin/ocspcheck/ocspcheck.c index df14265370..6038f8817d 100644 --- a/src/usr.sbin/ocspcheck/ocspcheck.c +++ b/src/usr.sbin/ocspcheck/ocspcheck.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ocspcheck.c,v 1.21 2017/05/08 20:15:34 beck Exp $ */ | 1 | /* $OpenBSD: ocspcheck.c,v 1.22 2017/11/28 23:32:00 beck Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2017 Bob Beck <beck@openbsd.org> | 4 | * Copyright (c) 2017 Bob Beck <beck@openbsd.org> |
@@ -40,6 +40,7 @@ | |||
40 | 40 | ||
41 | #define MAXAGE_SEC (14*24*60*60) | 41 | #define MAXAGE_SEC (14*24*60*60) |
42 | #define JITTER_SEC (60) | 42 | #define JITTER_SEC (60) |
43 | #define OCSP_MAX_RESPONSE_SIZE (20480) | ||
43 | 44 | ||
44 | typedef struct ocsp_request { | 45 | typedef struct ocsp_request { |
45 | STACK_OF(X509) *fullchain; | 46 | STACK_OF(X509) *fullchain; |
@@ -505,19 +506,19 @@ int | |||
505 | main(int argc, char **argv) | 506 | main(int argc, char **argv) |
506 | { | 507 | { |
507 | char *host = NULL, *path = "/", *certfile = NULL, *outfile = NULL, | 508 | char *host = NULL, *path = "/", *certfile = NULL, *outfile = NULL, |
508 | *cafile = NULL; | 509 | *cafile = NULL, *instaple = NULL, *infile = NULL; |
509 | struct addr addrs[MAX_SERVERS_DNS] = {{0}}; | 510 | struct addr addrs[MAX_SERVERS_DNS] = {{0}}; |
510 | struct source sources[MAX_SERVERS_DNS]; | 511 | struct source sources[MAX_SERVERS_DNS]; |
511 | int i, ch, staplefd = -1, nonce = 1; | 512 | int i, ch, staplefd = -1, infd = -1, nonce = 1; |
512 | ocsp_request *request = NULL; | 513 | ocsp_request *request = NULL; |
513 | size_t rescount, httphsz; | 514 | size_t rescount, httphsz = 0, instaplesz = 0; |
514 | struct httphead *httph; | 515 | struct httphead *httph = NULL; |
515 | struct httpget *hget; | 516 | struct httpget *hget; |
516 | X509_STORE *castore; | 517 | X509_STORE *castore; |
517 | ssize_t written, w; | 518 | ssize_t written, w; |
518 | short port; | 519 | short port; |
519 | 520 | ||
520 | while ((ch = getopt(argc, argv, "C:No:v")) != -1) { | 521 | while ((ch = getopt(argc, argv, "C:i:No:v")) != -1) { |
521 | switch (ch) { | 522 | switch (ch) { |
522 | case 'C': | 523 | case 'C': |
523 | cafile = optarg; | 524 | cafile = optarg; |
@@ -528,6 +529,9 @@ main(int argc, char **argv) | |||
528 | case 'o': | 529 | case 'o': |
529 | outfile = optarg; | 530 | outfile = optarg; |
530 | break; | 531 | break; |
532 | case 'i': | ||
533 | infile = optarg; | ||
534 | break; | ||
531 | case 'v': | 535 | case 'v': |
532 | verbose++; | 536 | verbose++; |
533 | break; | 537 | break; |
@@ -551,6 +555,16 @@ main(int argc, char **argv) | |||
551 | err(1, "Unable to open output file %s", outfile); | 555 | err(1, "Unable to open output file %s", outfile); |
552 | } | 556 | } |
553 | 557 | ||
558 | if (infile != NULL) { | ||
559 | if (strcmp(infile, "-") == 0) | ||
560 | infd = STDIN_FILENO; | ||
561 | else | ||
562 | infd = open(infile, O_RDONLY); | ||
563 | if (infd < 0) | ||
564 | err(1, "Unable to open input file %s", infile); | ||
565 | nonce = 0; /* Can't validate a nonce on a saved reply */ | ||
566 | } | ||
567 | |||
554 | if (pledge("stdio inet rpath dns", NULL) == -1) | 568 | if (pledge("stdio inet rpath dns", NULL) == -1) |
555 | err(1, "pledge"); | 569 | err(1, "pledge"); |
556 | 570 | ||
@@ -571,50 +585,82 @@ main(int argc, char **argv) | |||
571 | certfile); | 585 | certfile); |
572 | if (*path == '\0') | 586 | if (*path == '\0') |
573 | path = "/"; | 587 | path = "/"; |
574 | vspew("Using %s to host %s, port %d, path %s\n", | ||
575 | port == 443 ? "https" : "http", host, port, path); | ||
576 | 588 | ||
577 | rescount = host_dns(host, addrs); | 589 | if (infd == -1) { |
578 | for (i = 0; i < rescount; i++) { | 590 | /* Get a new OCSP response from the indicated server */ |
579 | sources[i].ip = addrs[i].ip; | ||
580 | sources[i].family = addrs[i].family; | ||
581 | } | ||
582 | 591 | ||
583 | /* | 592 | vspew("Using %s to host %s, port %d, path %s\n", |
584 | * Do an HTTP post to send our request to the OCSP | 593 | port == 443 ? "https" : "http", host, port, path); |
585 | * server, and hopefully get an answer back | ||
586 | */ | ||
587 | hget = http_get(sources, rescount, host, port, path, | ||
588 | request->data, request->size); | ||
589 | if (hget == NULL) | ||
590 | errx(1, "http_get"); | ||
591 | 594 | ||
592 | /* | 595 | rescount = host_dns(host, addrs); |
593 | * Pledge minimally before fiddling with libcrypto init | 596 | for (i = 0; i < rescount; i++) { |
594 | * routines and parsing untrusted input from someone's OCSP | 597 | sources[i].ip = addrs[i].ip; |
595 | * server. | 598 | sources[i].family = addrs[i].family; |
596 | */ | 599 | } |
597 | if (pledge("stdio", NULL) == -1) | ||
598 | err(1, "pledge"); | ||
599 | |||
600 | httph = http_head_parse(hget->http, hget->xfer, &httphsz); | ||
601 | dspew("Server at %s returns:\n", host); | ||
602 | for (i = 0; i < httphsz; i++) | ||
603 | dspew(" [%s]=[%s]\n", httph[i].key, httph[i].val); | ||
604 | dspew(" [Body]=[%zu bytes]\n", hget->bodypartsz); | ||
605 | if (hget->bodypartsz <= 0) | ||
606 | errx(1, "No body in reply from %s", host); | ||
607 | |||
608 | if (hget->code != 200) | ||
609 | errx(1, "http reply code %d from %s", hget->code, host); | ||
610 | 600 | ||
611 | /* | 601 | /* |
612 | * Validate the OCSP response we got back | 602 | * Do an HTTP post to send our request to the OCSP |
613 | */ | 603 | * server, and hopefully get an answer back |
614 | OPENSSL_add_all_algorithms_noconf(); | 604 | */ |
615 | if (!validate_response(hget->bodypart, hget->bodypartsz, | 605 | hget = http_get(sources, rescount, host, port, path, |
616 | request, castore, host, certfile)) | 606 | request->data, request->size); |
617 | exit(1); | 607 | if (hget == NULL) |
608 | errx(1, "http_get"); | ||
609 | /* | ||
610 | * Pledge minimally before fiddling with libcrypto init | ||
611 | * routines and parsing untrusted input from someone's OCSP | ||
612 | * server. | ||
613 | */ | ||
614 | if (pledge("stdio", NULL) == -1) | ||
615 | err(1, "pledge"); | ||
616 | |||
617 | dspew("Server at %s returns:\n", host); | ||
618 | for (i = 0; i < httphsz; i++) | ||
619 | dspew(" [%s]=[%s]\n", httph[i].key, httph[i].val); | ||
620 | dspew(" [Body]=[%zu bytes]\n", hget->bodypartsz); | ||
621 | if (hget->bodypartsz <= 0) | ||
622 | errx(1, "No body in reply from %s", host); | ||
623 | |||
624 | if (hget->code != 200) | ||
625 | errx(1, "http reply code %d from %s", hget->code, host); | ||
626 | |||
627 | /* | ||
628 | * Validate the OCSP response we got back | ||
629 | */ | ||
630 | OPENSSL_add_all_algorithms_noconf(); | ||
631 | if (!validate_response(hget->bodypart, hget->bodypartsz, | ||
632 | request, castore, host, certfile)) | ||
633 | exit(1); | ||
634 | } else { | ||
635 | size_t nr = 0; | ||
636 | instaplesz = 0; | ||
637 | |||
638 | /* | ||
639 | * Pledge minimally before fiddling with libcrypto init | ||
640 | */ | ||
641 | if (pledge("stdio", NULL) == -1) | ||
642 | err(1, "pledge"); | ||
643 | |||
644 | dspew("Using ocsp response saved in %s:\n", infile); | ||
645 | |||
646 | /* Use the existing OCSP response saved in infd */ | ||
647 | instaple = calloc(OCSP_MAX_RESPONSE_SIZE, 1); | ||
648 | if (instaple) { | ||
649 | while ((nr = read(infd, instaple + instaplesz, | ||
650 | OCSP_MAX_RESPONSE_SIZE - instaplesz)) != -1 && | ||
651 | nr != 0) | ||
652 | instaplesz += nr; | ||
653 | } | ||
654 | if (instaplesz == 0) | ||
655 | exit(1); | ||
656 | /* | ||
657 | * Validate the OCSP staple we read in. | ||
658 | */ | ||
659 | OPENSSL_add_all_algorithms_noconf(); | ||
660 | if (!validate_response(instaple, instaplesz, | ||
661 | request, castore, host, certfile)) | ||
662 | exit(1); | ||
663 | } | ||
618 | 664 | ||
619 | /* | 665 | /* |
620 | * If we have been given a place to save a staple, | 666 | * If we have been given a place to save a staple, |