Add option -i to allow oscpcheck to be used to validate an on-disk staple
authorbeck <beck@openbsd.org>
Tue, 28 Nov 2017 23:32:00 +0000 (23:32 +0000)
committerbeck <beck@openbsd.org>
Tue, 28 Nov 2017 23:32:00 +0000 (23:32 +0000)
ok claudio@ benno@

usr.sbin/ocspcheck/ocspcheck.8
usr.sbin/ocspcheck/ocspcheck.c

index dabac38..2a3f2d6 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ocspcheck.8,v 1.7 2017/10/17 22:47:58 schwarze Exp $
+.\"    $OpenBSD: ocspcheck.8,v 1.8 2017/11/28 23:32:00 beck Exp $
 .\"
 .\" Copyright (c) 2017 Bob Beck <beck@openbsd.org>
 .\"
@@ -14,7 +14,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: October 17 2017 $
+.Dd $Mdocdate: November 28 2017 $
 .Dt OCSPCHECK 8
 .Os
 .Sh NAME
@@ -45,10 +45,18 @@ By default no certificates are used beyond those in the
 certificate chain provided by the
 .Ar file
 argument.
+.It Fl i Ar staplefile
+Specify an input filename from which a DER encoded OCSP response
+will be read instead of fetching it from the OCSP server.
+A filename
+of
+.Sq -
+will read the response from standard input.
 .It Fl N
 Do not use a nonce value in the OCSP request, or validate that the
 nonce was returned in the OCSP response.
-By default a nonce is always used and validated.
+By default a nonce is always used and validated when retrieving
+a response from an OCSP server. 
 The use of this flag is a security risk as it will allow OCSP
 responses to be replayed.
 It should not be used unless the OCSP server does not support the
index df14265..6038f88 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ocspcheck.c,v 1.21 2017/05/08 20:15:34 beck Exp $ */
+/* $OpenBSD: ocspcheck.c,v 1.22 2017/11/28 23:32:00 beck Exp $ */
 
 /*
  * Copyright (c) 2017 Bob Beck <beck@openbsd.org>
@@ -40,6 +40,7 @@
 
 #define MAXAGE_SEC (14*24*60*60)
 #define JITTER_SEC (60)
+#define OCSP_MAX_RESPONSE_SIZE (20480)
 
 typedef struct ocsp_request {
        STACK_OF(X509) *fullchain;
@@ -505,19 +506,19 @@ int
 main(int argc, char **argv)
 {
        char *host = NULL, *path = "/", *certfile = NULL, *outfile = NULL,
-           *cafile = NULL;
+           *cafile = NULL, *instaple = NULL, *infile = NULL;
        struct addr addrs[MAX_SERVERS_DNS] = {{0}};
        struct source sources[MAX_SERVERS_DNS];
-       int i, ch, staplefd = -1, nonce = 1;
+       int i, ch, staplefd = -1, infd = -1, nonce = 1;
        ocsp_request *request = NULL;
-       size_t rescount, httphsz;
-       struct httphead *httph;
+       size_t rescount, httphsz = 0, instaplesz = 0;
+       struct httphead *httph = NULL;
        struct httpget *hget;
        X509_STORE *castore;
        ssize_t written, w;
        short port;
 
-       while ((ch = getopt(argc, argv, "C:No:v")) != -1) {
+       while ((ch = getopt(argc, argv, "C:i:No:v")) != -1) {
                switch (ch) {
                case 'C':
                        cafile = optarg;
@@ -528,6 +529,9 @@ main(int argc, char **argv)
                case 'o':
                        outfile = optarg;
                        break;
+               case 'i':
+                       infile = optarg;
+                       break;
                case 'v':
                        verbose++;
                        break;
@@ -551,6 +555,16 @@ main(int argc, char **argv)
                        err(1, "Unable to open output file %s", outfile);
        }
 
+       if (infile != NULL) {
+               if (strcmp(infile, "-") == 0)
+                       infd = STDIN_FILENO;
+               else
+                       infd = open(infile, O_RDONLY);
+               if (infd < 0)
+                       err(1, "Unable to open input file %s", infile);
+               nonce = 0; /* Can't validate a nonce on a saved reply */
+       }
+
        if (pledge("stdio inet rpath dns", NULL) == -1)
                err(1, "pledge");
 
@@ -571,50 +585,82 @@ main(int argc, char **argv)
                    certfile);
        if (*path == '\0')
                path = "/";
-       vspew("Using %s to host %s, port %d, path %s\n",
-           port == 443 ? "https" : "http", host, port, path);
 
-       rescount = host_dns(host, addrs);
-       for (i = 0; i < rescount; i++) {
-               sources[i].ip = addrs[i].ip;
-               sources[i].family = addrs[i].family;
-       }
+       if (infd == -1) {
+               /* Get a new OCSP response from the indicated server */
 
-       /*
-        * Do an HTTP post to send our request to the OCSP
-        * server, and hopefully get an answer back
-        */
-       hget = http_get(sources, rescount, host, port, path,
-           request->data, request->size);
-       if (hget == NULL)
-               errx(1, "http_get");
+               vspew("Using %s to host %s, port %d, path %s\n",
+                   port == 443 ? "https" : "http", host, port, path);
 
-       /*
-        * Pledge minimally before fiddling with libcrypto init
-        * routines and parsing untrusted input from someone's OCSP
-        * server.
-        */
-       if (pledge("stdio", NULL) == -1)
-               err(1, "pledge");
-
-       httph = http_head_parse(hget->http, hget->xfer, &httphsz);
-       dspew("Server at %s returns:\n", host);
-       for (i = 0; i < httphsz; i++)
-               dspew("   [%s]=[%s]\n", httph[i].key, httph[i].val);
-       dspew("   [Body]=[%zu bytes]\n", hget->bodypartsz);
-       if (hget->bodypartsz <= 0)
-               errx(1, "No body in reply from %s", host);
-
-       if (hget->code != 200)
-               errx(1, "http reply code %d from %s", hget->code, host);
+               rescount = host_dns(host, addrs);
+               for (i = 0; i < rescount; i++) {
+                       sources[i].ip = addrs[i].ip;
+                       sources[i].family = addrs[i].family;
+               }
 
-       /*
-        * Validate the OCSP response we got back
-        */
-       OPENSSL_add_all_algorithms_noconf();
-       if (!validate_response(hget->bodypart, hget->bodypartsz,
-           request, castore, host, certfile))
-               exit(1);
+               /*
+                * Do an HTTP post to send our request to the OCSP
+                * server, and hopefully get an answer back
+                */
+               hget = http_get(sources, rescount, host, port, path,
+                   request->data, request->size);
+               if (hget == NULL)
+                       errx(1, "http_get");
+               /*
+                * Pledge minimally before fiddling with libcrypto init
+                * routines and parsing untrusted input from someone's OCSP
+                * server.
+                */
+               if (pledge("stdio", NULL) == -1)
+                       err(1, "pledge");
+
+               dspew("Server at %s returns:\n", host);
+               for (i = 0; i < httphsz; i++)
+                       dspew("   [%s]=[%s]\n", httph[i].key, httph[i].val);
+               dspew("   [Body]=[%zu bytes]\n", hget->bodypartsz);
+               if (hget->bodypartsz <= 0)
+                       errx(1, "No body in reply from %s", host);
+
+               if (hget->code != 200)
+                       errx(1, "http reply code %d from %s", hget->code, host);
+
+               /*
+                * Validate the OCSP response we got back
+                */
+               OPENSSL_add_all_algorithms_noconf();
+               if (!validate_response(hget->bodypart, hget->bodypartsz,
+                       request, castore, host, certfile))
+                       exit(1);
+       } else {
+               size_t nr = 0;
+               instaplesz = 0;
+
+               /*
+                * Pledge minimally before fiddling with libcrypto init
+                */
+               if (pledge("stdio", NULL) == -1)
+                       err(1, "pledge");
+
+               dspew("Using ocsp response saved in %s:\n", infile);
+
+               /* Use the existing OCSP response saved in infd */
+               instaple = calloc(OCSP_MAX_RESPONSE_SIZE, 1);
+               if (instaple) {
+                       while ((nr = read(infd, instaple + instaplesz,
+                           OCSP_MAX_RESPONSE_SIZE - instaplesz)) != -1 &&
+                           nr != 0)
+                               instaplesz += nr;
+               }
+               if (instaplesz == 0)
+                       exit(1);
+               /*
+                * Validate the OCSP staple we read in.
+                */
+               OPENSSL_add_all_algorithms_noconf();
+               if (!validate_response(instaple, instaplesz,
+                       request, castore, host, certfile))
+                       exit(1);
+       }
 
        /*
         * If we have been given a place to save a staple,