X-Git-Url: https://git.openssl.org/?a=blobdiff_plain;f=apps%2Focsp.c;h=1886504880deb5fc64a8bfd70ba041948666daa5;hb=7569362ebb3fcc3a0d417978d36dd26f69194d33;hp=840e506a5cec1078c664caf371c9587e17ab6856;hpb=7e1b7485706c2b11091b5fa897fe496a2faa56cc;p=openssl.git diff --git a/apps/ocsp.c b/apps/ocsp.c index 840e506a5c..1886504880 100644 --- a/apps/ocsp.c +++ b/apps/ocsp.c @@ -1,62 +1,17 @@ /* - * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project - * 2000. - */ -/* ==================================================================== - * Copyright (c) 1999 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * licensing@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). + * Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved. * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html */ -#ifndef OPENSSL_NO_OCSP +#include + +#ifdef OPENSSL_NO_OCSP +NON_EMPTY_TRANSLATION_UNIT +#else # ifdef OPENSSL_SYS_VMS # define _XOPEN_SOURCE_EXTENDED/* So fd_set and friends get properly defined * on OpenVMS */ @@ -68,8 +23,10 @@ # include # include # include -# include "apps.h" /* needs to be included before the openssl - * headers! */ +# include + +/* Needs to be included before the openssl headers */ +# include "apps.h" # include # include # include @@ -114,12 +71,15 @@ static void make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser); static BIO *init_responder(const char *port); -static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, - const char *port); +static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio); static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp); -static OCSP_RESPONSE *query_responder(BIO *cbio, const char *path, + +# ifndef OPENSSL_NO_SOCK +static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host, + const char *path, const STACK_OF(CONF_VALUE) *headers, OCSP_REQUEST *req, int req_timeout); +# endif typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, @@ -130,9 +90,9 @@ typedef enum OPTION_choice { OPT_NO_CERT_CHECKS, OPT_NO_EXPLICIT, OPT_TRUST_OTHER, OPT_NO_INTERN, OPT_BADSIG, OPT_TEXT, OPT_REQ_TEXT, OPT_RESP_TEXT, OPT_REQIN, OPT_RESPIN, OPT_SIGNER, OPT_VAFILE, OPT_SIGN_OTHER, - OPT_VERIFY_OTHER, OPT_CAFILE, OPT_CAPATH, + OPT_VERIFY_OTHER, OPT_CAFILE, OPT_CAPATH, OPT_NOCAFILE, OPT_NOCAPATH, OPT_VALIDITY_PERIOD, OPT_STATUS_AGE, OPT_SIGNKEY, OPT_REQOUT, - OPT_RESPOUT, OPT_PATH, OPT_CERT, OPT_SERIAL, + OPT_RESPOUT, OPT_PATH, OPT_ISSUER, OPT_CERT, OPT_SERIAL, OPT_INDEX, OPT_CA, OPT_NMIN, OPT_REQUEST, OPT_NDAYS, OPT_RSIGNER, OPT_RKEY, OPT_ROTHER, OPT_RMD, OPT_HEADER, OPT_V_ENUM, @@ -142,7 +102,8 @@ typedef enum OPTION_choice { OPTIONS ocsp_options[] = { {"help", OPT_HELP, '-', "Display this summary"}, {"out", OPT_OUTFILE, '>', "Output filename"}, - {"timeout", OPT_TIMEOUT, 'p'}, + {"timeout", OPT_TIMEOUT, 'p', + "Connection timeout (in seconds) to the OCSP responder"}, {"url", OPT_URL, 's', "Responder URL"}, {"host", OPT_HOST, 's', "host:prot top to connect to"}, {"port", OPT_PORT, 'p', "Port to run responder on"}, @@ -168,7 +129,8 @@ OPTIONS ocsp_options[] = { "Don't verify additional certificates"}, {"no_intern", OPT_NO_INTERN, '-', "Don't search certificates contained in response for signer"}, - {"badsig", OPT_BADSIG, '-'}, + {"badsig", OPT_BADSIG, '-', + "Corrupt last byte of loaded OSCP response signature (for test)"}, {"text", OPT_TEXT, '-', "Print text form of request and response"}, {"req_text", OPT_REQ_TEXT, '-', "Print text form of request"}, {"resp_text", OPT_RESP_TEXT, '-', "Print text form of response"}, @@ -182,6 +144,10 @@ OPTIONS ocsp_options[] = { "Additional certificates to search for signer"}, {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"}, {"CApath", OPT_CAPATH, '<', "Trusted certificates directory"}, + {"no-CAfile", OPT_NOCAFILE, '-', + "Do not load the default certificates file"}, + {"no-CApath", OPT_NOCAPATH, '-', + "Do not load certificates from the default certificates directory"}, {"validity_period", OPT_VALIDITY_PERIOD, 'u', "Maximum validity discrepancy in seconds"}, {"status_age", OPT_STATUS_AGE, 'p', "Maximum status age in seconds"}, @@ -189,8 +155,9 @@ OPTIONS ocsp_options[] = { {"reqout", OPT_REQOUT, 's', "Output file for the DER-encoded request"}, {"respout", OPT_RESPOUT, 's', "Output file for the DER-encoded response"}, {"path", OPT_PATH, 's', "Path to use in OCSP request"}, + {"issuer", OPT_ISSUER, '<', "Issuer certificate"}, {"cert", OPT_CERT, '<', "Certificate to check"}, - {"serial", OPT_SERIAL, 's', "Nerial number to check"}, + {"serial", OPT_SERIAL, 's', "Serial number to check"}, {"index", OPT_INDEX, '<', "Certificate status index file"}, {"CA", OPT_CA, '<', "CA certificate"}, {"nmin", OPT_NMIN, 'p', "Number of minutes before next update"}, @@ -198,12 +165,12 @@ OPTIONS ocsp_options[] = { "Number of requests to accept (default unlimited)"}, {"ndays", OPT_NDAYS, 'p', "Number of days before next update"}, {"rsigner", OPT_RSIGNER, '<', - "Sesponder certificate to sign responses with"}, + "Responder certificate to sign responses with"}, {"rkey", OPT_RKEY, '<', "Responder key to sign responses with"}, {"rother", OPT_ROTHER, '<', "Other certificates to include in response"}, - {"rmd", OPT_RMD, 's'}, + {"rmd", OPT_RMD, 's', "Digest Algorithm to use in signature of OCSP response"}, {"header", OPT_HEADER, 's', "key=value header to add"}, - {"", OPT_MD, '-', "Any supported digest"}, + {"", OPT_MD, '-', "Any supported digest algorithm (sha1,sha256, ... )"}, OPT_V_OPTIONS, {NULL} }; @@ -212,6 +179,7 @@ int ocsp_main(int argc, char **argv) { BIO *acbio = NULL, *cbio = NULL, *derbio = NULL, *out = NULL; const EVP_MD *cert_id_md = NULL, *rsign_md = NULL; + int trailing_md = 0; CA_DB *rdb = NULL; EVP_PKEY *key = NULL, *rkey = NULL; OCSP_BASICRESP *bs = NULL; @@ -221,6 +189,7 @@ int ocsp_main(int argc, char **argv) STACK_OF(OCSP_CERTID) *ids = NULL; STACK_OF(OPENSSL_STRING) *reqnames = NULL; STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL; + STACK_OF(X509) *issuers = NULL; X509 *issuer = NULL, *cert = NULL, *rca_cert = NULL; X509 *signer = NULL, *rsigner = NULL; X509_STORE *store = NULL; @@ -233,9 +202,13 @@ int ocsp_main(int argc, char **argv) char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL; char *signfile = NULL, *keyfile = NULL; char *thost = NULL, *tport = NULL, *tpath = NULL; + int noCAfile = 0, noCApath = 0; int accept_count = -1, add_nonce = 1, noverify = 0, use_ssl = -1; int vpmtouched = 0, badsig = 0, i, ignore_err = 0, nmin = 0, ndays = -1; - int req_text = 0, resp_text = 0, req_timeout = -1, ret = 1; + int req_text = 0, resp_text = 0, ret = 1; +#ifndef OPENSSL_NO_SOCK + int req_timeout = -1; +#endif long nsec = MAX_VALIDITY_PERIOD, maxage = -1; unsigned long sign_flags = 0, verify_flags = 0, rflags = 0; OPTION_CHOICE o; @@ -266,15 +239,15 @@ int ocsp_main(int argc, char **argv) outfile = opt_arg(); break; case OPT_TIMEOUT: +#ifndef OPENSSL_NO_SOCK req_timeout = atoi(opt_arg()); +#endif break; case OPT_URL: - if (thost) - OPENSSL_free(thost); - if (tport) - OPENSSL_free(tport); - if (tpath) - OPENSSL_free(tpath); + OPENSSL_free(thost); + OPENSSL_free(tport); + OPENSSL_free(tpath); + thost = tport = tpath = NULL; if (!OCSP_parse_url(opt_arg(), &host, &port, &path, &use_ssl)) { BIO_printf(bio_err, "%s Error parsing URL\n", prog); goto end; @@ -368,6 +341,12 @@ int ocsp_main(int argc, char **argv) case OPT_CAPATH: CApath = opt_arg(); break; + case OPT_NOCAFILE: + noCAfile = 1; + break; + case OPT_NOCAPATH: + noCApath = 1; + break; case OPT_V_CASES: if (!opt_verify(o, vpm)) goto end; @@ -391,10 +370,19 @@ int ocsp_main(int argc, char **argv) case OPT_PATH: path = opt_arg(); break; + case OPT_ISSUER: + issuer = load_cert(opt_arg(), FORMAT_PEM, "issuer certificate"); + if (issuer == NULL) + goto end; + if (issuers == NULL) { + if ((issuers = sk_X509_new_null()) == NULL) + goto end; + } + sk_X509_push(issuers, issuer); + break; case OPT_CERT: X509_free(cert); - cert = load_cert(opt_arg(), FORMAT_PEM, - NULL, NULL, "certificate"); + cert = load_cert(opt_arg(), FORMAT_PEM, "certificate"); if (cert == NULL) goto end; if (cert_id_md == NULL) @@ -403,6 +391,7 @@ int ocsp_main(int argc, char **argv) goto end; if (!sk_OPENSSL_STRING_push(reqnames, opt_arg())) goto end; + trailing_md = 0; break; case OPT_SERIAL: if (cert_id_md == NULL) @@ -411,6 +400,7 @@ int ocsp_main(int argc, char **argv) goto end; if (!sk_OPENSSL_STRING_push(reqnames, opt_arg())) goto end; + trailing_md = 0; break; case OPT_INDEX: ridx_filename = opt_arg(); @@ -438,7 +428,7 @@ int ocsp_main(int argc, char **argv) case OPT_ROTHER: rcertfile = opt_arg(); break; - case OPT_RMD: + case OPT_RMD: /* Response MessageDigest */ if (!opt_md(opt_arg(), &rsign_md)) goto end; break; @@ -454,7 +444,7 @@ int ocsp_main(int argc, char **argv) goto end; break; case OPT_MD: - if (cert_id_md != NULL) { + if (trailing_md) { BIO_printf(bio_err, "%s: Digest must be before -cert or -serial\n", prog); @@ -462,17 +452,25 @@ int ocsp_main(int argc, char **argv) } if (!opt_md(opt_unknown(), &cert_id_md)) goto opthelp; + trailing_md = 1; break; } } + + if (trailing_md) { + BIO_printf(bio_err, "%s: Digest must be before -cert or -serial\n", + prog); + goto opthelp; + } argc = opt_num_rest(); - argv = opt_rest(); + if (argc != 0) + goto opthelp; /* Have we anything to do? */ if (!req && !reqin && !respin && !(port && ridx_filename)) goto opthelp; - out = bio_open_default(outfile, "w"); + out = bio_open_default(outfile, 'w', FORMAT_TEXT); if (out == NULL) goto end; @@ -480,7 +478,7 @@ int ocsp_main(int argc, char **argv) add_nonce = 0; if (!req && reqin) { - derbio = bio_open_default(reqin, "rb"); + derbio = bio_open_default(reqin, 'r', FORMAT_ASN1); if (derbio == NULL) goto end; req = d2i_OCSP_REQUEST_bio(derbio, NULL); @@ -497,21 +495,18 @@ int ocsp_main(int argc, char **argv) goto end; } - if (rsignfile && !rdb) { + if (rsignfile) { if (!rkeyfile) rkeyfile = rsignfile; - rsigner = load_cert(rsignfile, FORMAT_PEM, - NULL, NULL, "responder certificate"); + rsigner = load_cert(rsignfile, FORMAT_PEM, "responder certificate"); if (!rsigner) { BIO_printf(bio_err, "Error loading responder certificate\n"); goto end; } - rca_cert = load_cert(rca_filename, FORMAT_PEM, - NULL, NULL, "CA certificate"); + rca_cert = load_cert(rca_filename, FORMAT_PEM, "CA certificate"); if (rcertfile) { - rother = load_certs(rcertfile, FORMAT_PEM, - NULL, NULL, "responder other certificates"); - if (!rother) + if (!load_certs(rcertfile, &rother, FORMAT_PEM, NULL, + "responder other certificates")) goto end; } rkey = load_key(rkeyfile, FORMAT_PEM, 0, NULL, NULL, @@ -525,7 +520,7 @@ int ocsp_main(int argc, char **argv) redo_accept: if (acbio) { - if (!do_responder(&req, &cbio, acbio, port)) + if (!do_responder(&req, &cbio, acbio)) goto end; if (!req) { resp = @@ -547,16 +542,14 @@ int ocsp_main(int argc, char **argv) if (signfile) { if (!keyfile) keyfile = signfile; - signer = load_cert(signfile, FORMAT_PEM, - NULL, NULL, "signer certificate"); + signer = load_cert(signfile, FORMAT_PEM, "signer certificate"); if (!signer) { BIO_printf(bio_err, "Error loading signer certificate\n"); goto end; } if (sign_certfile) { - sign_other = load_certs(sign_certfile, FORMAT_PEM, - NULL, NULL, "signer certificates"); - if (!sign_other) + if (!load_certs(sign_certfile, &sign_other, FORMAT_PEM, NULL, + "signer certificates")) goto end; } key = load_key(keyfile, FORMAT_PEM, 0, NULL, NULL, @@ -575,7 +568,7 @@ int ocsp_main(int argc, char **argv) OCSP_REQUEST_print(out, req, 0); if (reqout) { - derbio = bio_open_default(reqout, "wb"); + derbio = bio_open_default(reqout, 'w', FORMAT_ASN1); if (derbio == NULL) goto end; i2d_OCSP_REQUEST_bio(derbio, req); @@ -613,7 +606,7 @@ int ocsp_main(int argc, char **argv) goto end; # endif } else if (respin) { - derbio = bio_open_default(respin, "rb"); + derbio = bio_open_default(respin, 'r', FORMAT_ASN1); if (derbio == NULL) goto end; resp = d2i_OCSP_RESPONSE_bio(derbio, NULL); @@ -630,7 +623,7 @@ int ocsp_main(int argc, char **argv) done_resp: if (respout) { - derbio = bio_open_default(respout, "wb"); + derbio = bio_open_default(respout, 'w', FORMAT_ASN1); if (derbio == NULL) goto end; i2d_OCSP_RESPONSE_bio(derbio, resp); @@ -652,7 +645,8 @@ int ocsp_main(int argc, char **argv) /* If running as responder don't verify our own response */ if (cbio) { - if (--accept_count <= 0) { + /* If not unlimited, see if we took all we should. */ + if (accept_count != -1 && --accept_count <= 0) { ret = 0; goto end; } @@ -670,16 +664,15 @@ int ocsp_main(int argc, char **argv) } if (!store) { - store = setup_verify(CAfile, CApath); + store = setup_verify(CAfile, CApath, noCAfile, noCApath); if (!store) goto end; } if (vpmtouched) X509_STORE_set1_param(store, vpm); if (verify_certfile) { - verify_other = load_certs(verify_certfile, FORMAT_PEM, - NULL, NULL, "validator certificate"); - if (!verify_other) + if (!load_certs(verify_certfile, &verify_other, FORMAT_PEM, NULL, + "validator certificate")) goto end; } @@ -703,6 +696,11 @@ int ocsp_main(int argc, char **argv) } i = OCSP_basic_verify(bs, verify_other, store, verify_flags); + if (i <= 0 && issuers) { + i = OCSP_basic_verify(bs, issuers, store, OCSP_TRUSTOTHER); + if (i > 0) + ERR_clear_error(); + } if (i <= 0) { BIO_printf(bio_err, "Response Verify Failure\n"); ERR_print_errors(bio_err); @@ -718,11 +716,11 @@ int ocsp_main(int argc, char **argv) ERR_print_errors(bio_err); X509_free(signer); X509_STORE_free(store); - if (vpm) - X509_VERIFY_PARAM_free(vpm); + X509_VERIFY_PARAM_free(vpm); EVP_PKEY_free(key); EVP_PKEY_free(rkey); X509_free(cert); + sk_X509_pop_free(issuers, X509_free); X509_free(rsigner); X509_free(rca_cert); free_index(rdb); @@ -737,13 +735,9 @@ int ocsp_main(int argc, char **argv) sk_X509_pop_free(sign_other, X509_free); sk_X509_pop_free(verify_other, X509_free); sk_CONF_VALUE_pop_free(headers, X509V3_conf_free); - - if (thost) - OPENSSL_free(thost); - if (tport) - OPENSSL_free(tport); - if (tpath) - OPENSSL_free(tpath); + OPENSSL_free(thost); + OPENSSL_free(tport); + OPENSSL_free(tpath); return (ret); } @@ -757,9 +751,9 @@ static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, BIO_printf(bio_err, "No issuer certificate specified\n"); return 0; } - if (!*req) + if (*req == NULL) *req = OCSP_REQUEST_new(); - if (!*req) + if (*req == NULL) goto err; id = OCSP_cert_to_id(cert_id_md, cert, issuer); if (!id || !sk_OCSP_CERTID_push(ids, id)) @@ -785,9 +779,9 @@ static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, BIO_printf(bio_err, "No issuer certificate specified\n"); return 0; } - if (!*req) + if (*req == NULL) *req = OCSP_REQUEST_new(); - if (!*req) + if (*req == NULL) goto err; iname = X509_get_subject_name(issuer); ikey = X509_get0_pubkey_bitstr(issuer); @@ -798,7 +792,7 @@ static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, } id = OCSP_cert_id_new(cert_id_md, iname, ikey, sno); ASN1_INTEGER_free(sno); - if (!id || !sk_OCSP_CERTID_push(ids, id)) + if (id == NULL || !sk_OCSP_CERTID_push(ids, id)) goto err; if (!OCSP_request_add0_id(*req, id)) goto err; @@ -888,7 +882,7 @@ static void make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, bs = OCSP_BASICRESP_new(); thisupd = X509_gmtime_adj(NULL, 0); if (ndays != -1) - nextupd = X509_gmtime_adj(NULL, nmin * 60 + ndays * 3600 * 24); + nextupd = X509_time_adj_ex(NULL, ndays, nmin * 60, NULL); /* Examine each certificate id in the request */ for (i = 0; i < id_count; i++) { @@ -908,8 +902,7 @@ static void make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, NULL); goto end; } - if (ca_id) - OCSP_CERTID_free(ca_id); + OCSP_CERTID_free(ca_id); ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca); /* Is this request about our CA? */ @@ -982,7 +975,7 @@ static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser) OPENSSL_assert(bn); /* FIXME: should report an error at this * point and abort */ if (BN_is_zero(bn)) - itmp = BUF_strdup("00"); + itmp = OPENSSL_strdup("00"); else itmp = BN_bn2hex(bn); row[DB_serial] = itmp; @@ -996,24 +989,29 @@ static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser) static BIO *init_responder(const char *port) { +# ifdef OPENSSL_NO_SOCK + BIO_printf(bio_err, + "Error setting up accept BIO - sockets not supported.\n"); + return NULL; +# else BIO *acbio = NULL, *bufbio = NULL; bufbio = BIO_new(BIO_f_buffer()); - if (!bufbio) + if (bufbio == NULL) goto err; -# ifndef OPENSSL_NO_SOCK - acbio = BIO_new_accept(port); -# else - BIO_printf(bio_err, - "Error setting up accept BIO - sockets not supported.\n"); -# endif - if (!acbio) + acbio = BIO_new(BIO_s_accept()); + if (acbio == NULL + || BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR) < 0 + || BIO_set_accept_port(acbio, port) < 0) { + BIO_printf(bio_err, "Error setting up accept BIO\n"); + ERR_print_errors(bio_err); goto err; + } + BIO_set_accept_bios(acbio, bufbio); bufbio = NULL; - if (BIO_do_accept(acbio) <= 0) { - BIO_printf(bio_err, "Error setting up accept BIO\n"); + BIO_printf(bio_err, "Error starting accept\n"); ERR_print_errors(bio_err); goto err; } @@ -1024,15 +1022,45 @@ static BIO *init_responder(const char *port) BIO_free_all(acbio); BIO_free(bufbio); return NULL; +# endif } -static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, - const char *port) +# ifndef OPENSSL_NO_SOCK +/* + * Decode %xx URL-decoding in-place. Ignores mal-formed sequences. + */ +static int urldecode(char *p) { + unsigned char *out = (unsigned char *)p; + unsigned char *save = out; + + for (; *p; p++) { + if (*p != '%') + *out++ = *p; + else if (isxdigit(_UC(p[1])) && isxdigit(_UC(p[2]))) { + /* Don't check, can't fail because of ixdigit() call. */ + *out++ = (OPENSSL_hexchar2int(p[1]) << 4) + | OPENSSL_hexchar2int(p[2]); + p += 2; + } + else + return -1; + } + *out = '\0'; + return (int)(out - save); +} +# endif + +static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio) +{ +# ifdef OPENSSL_NO_SOCK + return 0; +# else int len; OCSP_REQUEST *req = NULL; - char inbuf[2048]; - BIO *cbio = NULL; + char inbuf[2048], reqbuf[2048]; + char *p, *q; + BIO *cbio = NULL, *getbio = NULL, *b64 = NULL; if (BIO_do_accept(acbio) <= 0) { BIO_printf(bio_err, "Error accepting connection\n"); @@ -1044,24 +1072,61 @@ static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, *pcbio = cbio; /* Read the request line. */ - len = BIO_gets(cbio, inbuf, sizeof inbuf); + len = BIO_gets(cbio, reqbuf, sizeof reqbuf); if (len <= 0) return 1; - if (strncmp(inbuf, "POST", 4) != 0) { - BIO_printf(bio_err, "Invalid request\n"); + if (strncmp(reqbuf, "GET ", 4) == 0) { + /* Expecting GET {sp} /URL {sp} HTTP/1.x */ + for (p = reqbuf + 4; *p == ' '; ++p) + continue; + if (*p != '/') { + BIO_printf(bio_err, "Invalid request -- bad URL\n"); + return 1; + } + p++; + + /* Splice off the HTTP version identifier. */ + for (q = p; *q; q++) + if (*q == ' ') + break; + if (strncmp(q, " HTTP/1.", 8) != 0) { + BIO_printf(bio_err, "Invalid request -- bad HTTP vesion\n"); + return 1; + } + *q = '\0'; + len = urldecode(p); + if (len <= 0) { + BIO_printf(bio_err, "Invalid request -- bad URL encoding\n"); + return 1; + } + if ((getbio = BIO_new_mem_buf(p, len)) == NULL + || (b64 = BIO_new(BIO_f_base64())) == NULL) { + BIO_printf(bio_err, "Could not allocate memory\n"); + ERR_print_errors(bio_err); + return 1; + } + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + getbio = BIO_push(b64, getbio); + } else if (strncmp(reqbuf, "POST ", 5) != 0) { + BIO_printf(bio_err, "Invalid request -- bad HTTP verb\n"); return 1; } + + /* Read and skip past the headers. */ for (;;) { len = BIO_gets(cbio, inbuf, sizeof inbuf); if (len <= 0) return 1; - /* Look for end of headers */ if ((inbuf[0] == '\r') || (inbuf[0] == '\n')) break; } /* Try to read OCSP request */ - req = d2i_OCSP_REQUEST_bio(cbio, NULL); + if (getbio) { + req = d2i_OCSP_REQUEST_bio(getbio, NULL); + BIO_free_all(getbio); + } else + req = d2i_OCSP_REQUEST_bio(cbio, NULL); if (!req) { BIO_printf(bio_err, "Error parsing OCSP request\n"); @@ -1071,7 +1136,7 @@ static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, *preq = req; return 1; - +# endif } static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp) @@ -1087,13 +1152,16 @@ static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp) return 1; } -static OCSP_RESPONSE *query_responder(BIO *cbio, const char *path, +# ifndef OPENSSL_NO_SOCK +static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host, + const char *path, const STACK_OF(CONF_VALUE) *headers, OCSP_REQUEST *req, int req_timeout) { int fd; int rv; int i; + int add_host = 1; OCSP_REQ_CTX *ctx = NULL; OCSP_RESPONSE *rsp = NULL; fd_set confds; @@ -1109,7 +1177,7 @@ static OCSP_RESPONSE *query_responder(BIO *cbio, const char *path, return NULL; } - if (BIO_get_fd(cbio, &fd) <= 0) { + if (BIO_get_fd(cbio, &fd) < 0) { BIO_puts(bio_err, "Can't get connection fd\n"); goto err; } @@ -1127,15 +1195,20 @@ static OCSP_RESPONSE *query_responder(BIO *cbio, const char *path, } ctx = OCSP_sendreq_new(cbio, path, NULL, -1); - if (!ctx) + if (ctx == NULL) return NULL; for (i = 0; i < sk_CONF_VALUE_num(headers); i++) { CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i); + if (add_host == 1 && strcasecmp("host", hdr->name) == 0) + add_host = 0; if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value)) goto err; } + if (add_host == 1 && OCSP_REQ_CTX_add1_header(ctx, "Host", host) == 0) + goto err; + if (!OCSP_REQ_CTX_set1_req(ctx, req)) goto err; @@ -1168,8 +1241,7 @@ static OCSP_RESPONSE *query_responder(BIO *cbio, const char *path, } err: - if (ctx) - OCSP_REQ_CTX_free(ctx); + OCSP_REQ_CTX_free(ctx); return rsp; } @@ -1177,12 +1249,13 @@ static OCSP_RESPONSE *query_responder(BIO *cbio, const char *path, OCSP_RESPONSE *process_responder(OCSP_REQUEST *req, const char *host, const char *path, const char *port, int use_ssl, - const STACK_OF(CONF_VALUE) *headers, + STACK_OF(CONF_VALUE) *headers, int req_timeout) { BIO *cbio = NULL; SSL_CTX *ctx = NULL; OCSP_RESPONSE *resp = NULL; + cbio = BIO_new_connect(host); if (!cbio) { BIO_printf(bio_err, "Error creating connect BIO\n"); @@ -1192,7 +1265,7 @@ OCSP_RESPONSE *process_responder(OCSP_REQUEST *req, BIO_set_conn_port(cbio, port); if (use_ssl == 1) { BIO *sbio; - ctx = SSL_CTX_new(SSLv23_client_method()); + ctx = SSL_CTX_new(TLS_client_method()); if (ctx == NULL) { BIO_printf(bio_err, "Error creating SSL context.\n"); goto end; @@ -1201,7 +1274,8 @@ OCSP_RESPONSE *process_responder(OCSP_REQUEST *req, sbio = BIO_new_ssl(ctx, 1); cbio = BIO_push(sbio, cbio); } - resp = query_responder(cbio, path, headers, req, req_timeout); + + resp = query_responder(cbio, host, path, headers, req, req_timeout); if (!resp) BIO_printf(bio_err, "Error querying OCSP responder\n"); end: @@ -1209,5 +1283,6 @@ OCSP_RESPONSE *process_responder(OCSP_REQUEST *req, SSL_CTX_free(ctx); return resp; } +# endif #endif