summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbeck <>2017-11-28 23:32:00 +0000
committerbeck <>2017-11-28 23:32:00 +0000
commitaa9c99e53a08fd5b5178e337b1082d178fb34c07 (patch)
treeb61427f044550d21a63392cc8723dfb4fd807aa3
parent8e3da22d9e96b1f66fa86b077a8226eff4b85e17 (diff)
downloadopenbsd-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.814
-rw-r--r--src/usr.sbin/ocspcheck/ocspcheck.c138
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
45certificate chain provided by the 45certificate chain provided by the
46.Ar file 46.Ar file
47argument. 47argument.
48.It Fl i Ar staplefile
49Specify an input filename from which a DER encoded OCSP response
50will be read instead of fetching it from the OCSP server.
51A filename
52of
53.Sq -
54will read the response from standard input.
48.It Fl N 55.It Fl N
49Do not use a nonce value in the OCSP request, or validate that the 56Do not use a nonce value in the OCSP request, or validate that the
50nonce was returned in the OCSP response. 57nonce was returned in the OCSP response.
51By default a nonce is always used and validated. 58By default a nonce is always used and validated when retrieving
59a response from an OCSP server.
52The use of this flag is a security risk as it will allow OCSP 60The use of this flag is a security risk as it will allow OCSP
53responses to be replayed. 61responses to be replayed.
54It should not be used unless the OCSP server does not support the 62It 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
44typedef struct ocsp_request { 45typedef struct ocsp_request {
45 STACK_OF(X509) *fullchain; 46 STACK_OF(X509) *fullchain;
@@ -505,19 +506,19 @@ int
505main(int argc, char **argv) 506main(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,