diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2017-11-28 23:32:01 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2017-11-28 23:32:01 +0000 |
commit | 6322eed1014b2454587bd5d2fe8e51ebb1be832c (patch) | |
tree | aee39f4e663ed1060aa528b5a47a351d8587b29b | |
parent | 1d3a52c99d52ce45a54223243ee2d65360baf947 (diff) |
Add option -i to allow oscpcheck to be used to validate an on-disk staple
ok claudio@ benno@
-rw-r--r-- | usr.sbin/ocspcheck/ocspcheck.8 | 14 | ||||
-rw-r--r-- | usr.sbin/ocspcheck/ocspcheck.c | 138 |
2 files changed, 103 insertions, 49 deletions
diff --git a/usr.sbin/ocspcheck/ocspcheck.8 b/usr.sbin/ocspcheck/ocspcheck.8 index dabac38a65b..2a3f2d61871 100644 --- a/usr.sbin/ocspcheck/ocspcheck.8 +++ b/usr.sbin/ocspcheck/ocspcheck.8 @@ -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 diff --git a/usr.sbin/ocspcheck/ocspcheck.c b/usr.sbin/ocspcheck/ocspcheck.c index df142653702..6038f8817d1 100644 --- a/usr.sbin/ocspcheck/ocspcheck.c +++ b/usr.sbin/ocspcheck/ocspcheck.c @@ -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, |