X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Focsp.c;h=ee38b23388688910ba12d13cca69aff99b4643c1;hp=015f4d3d1fffdcb508e74a96cc2a90d8dcd7aba4;hb=5388f9862d9aaf3c7cf7a70c1e36e7e983c26cfc;hpb=a9dd51a800f1920aa7545dc2f4f831000a60af48 diff --git a/apps/ocsp.c b/apps/ocsp.c index 015f4d3d1f..ee38b23388 100644 --- a/apps/ocsp.c +++ b/apps/ocsp.c @@ -1,7 +1,7 @@ /* * Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (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 @@ -36,7 +36,21 @@ NON_EMPTY_TRANSLATION_UNIT # include # include -# if defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_NO_SOCK) \ +#ifndef HAVE_FORK +# if defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_WINDOWS) +# define HAVE_FORK 0 +# else +# define HAVE_FORK 1 +# endif +#endif + +#if HAVE_FORK +# undef NO_FORK +#else +# define NO_FORK +#endif + +# if !defined(NO_FORK) && !defined(OPENSSL_NO_SOCK) \ && !defined(OPENSSL_NO_POSIX_IO) # define OCSP_DAEMON # include @@ -53,6 +67,20 @@ NON_EMPTY_TRANSLATION_UNIT # define LOG_ERR 2 # endif +# if defined(OPENSSL_SYS_VXWORKS) +/* not supported */ +int setpgid(pid_t pid, pid_t pgid) +{ + errno = ENOSYS; + return 0; +} +/* not supported */ +pid_t fork(void) +{ + errno = ENOSYS; + return (pid_t) -1; +} +# endif /* Maximum leeway in validity period: default 5 minutes */ # define MAX_VALIDITY_PERIOD (5 * 60) @@ -71,7 +99,8 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req EVP_PKEY *rkey, const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts, STACK_OF(X509) *rother, unsigned long flags, - int nmin, int ndays, int badsig); + int nmin, int ndays, int badsig, + const EVP_MD *resp_md); static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser); static BIO *init_responder(const char *port); @@ -105,42 +134,82 @@ 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_NOCAFILE, OPT_NOCAPATH, + OPT_VERIFY_OTHER, OPT_CAFILE, OPT_CAPATH, OPT_CASTORE, OPT_NOCAFILE, + OPT_NOCAPATH, OPT_NOCASTORE, OPT_VALIDITY_PERIOD, OPT_STATUS_AGE, OPT_SIGNKEY, OPT_REQOUT, 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_RSIGOPT, OPT_HEADER, + OPT_RCID, OPT_V_ENUM, OPT_MD, OPT_MULTI } OPTION_CHOICE; const OPTIONS ocsp_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"out", OPT_OUTFILE, '>', "Output filename"}, - {"timeout", OPT_TIMEOUT, 'p', - "Connection timeout (in seconds) to the OCSP responder"}, - {"url", OPT_URL, 's', "Responder URL"}, - {"host", OPT_HOST, 's', "TCP/IP hostname:port to connect to"}, - {"port", OPT_PORT, 'p', "Port to run responder on"}, {"ignore_err", OPT_IGNORE_ERR, '-', "Ignore error on OCSP request or response and continue running"}, - {"noverify", OPT_NOVERIFY, '-', "Don't verify response at all"}, - {"nonce", OPT_NONCE, '-', "Add OCSP nonce to request"}, - {"no_nonce", OPT_NO_NONCE, '-', "Don't add OCSP nonce to request"}, + {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"}, + {"CApath", OPT_CAPATH, '<', "Trusted certificates directory"}, + {"CAstore", OPT_CASTORE, ':', "Trusted certificates store URI"}, + {"no-CAfile", OPT_NOCAFILE, '-', + "Do not load the default certificates file"}, + {"no-CApath", OPT_NOCAPATH, '-', + "Do not load certificates from the default certificates directory"}, + {"no-CAstore", OPT_NOCAPATH, '-', + "Do not load certificates from the default certificates store"}, + + OPT_SECTION("Responder"), + {"timeout", OPT_TIMEOUT, 'p', + "Connection timeout (in seconds) to the OCSP responder"}, {"resp_no_certs", OPT_RESP_NO_CERTS, '-', "Don't include any certificates in response"}, - {"resp_key_id", OPT_RESP_KEY_ID, '-', - "Identify response by signing certificate key ID"}, # ifdef OCSP_DAEMON {"multi", OPT_MULTI, 'p', "run multiple responder processes"}, # endif {"no_certs", OPT_NO_CERTS, '-', "Don't include any certificates in signed request"}, + {"badsig", OPT_BADSIG, '-', + "Corrupt last byte of loaded OSCP response signature (for test)"}, + {"CA", OPT_CA, '<', "CA certificate"}, + {"nmin", OPT_NMIN, 'p', "Number of minutes before next update"}, + {"nrequest", OPT_REQUEST, 'p', + "Number of requests to accept (default unlimited)"}, + {"reqin", OPT_REQIN, 's', "File with the DER-encoded request"}, + {"signer", OPT_SIGNER, '<', "Certificate to sign OCSP request with"}, + {"sign_other", OPT_SIGN_OTHER, '<', + "Additional certificates to include in signed request"}, + {"index", OPT_INDEX, '<', "Certificate status index file"}, + {"ndays", OPT_NDAYS, 'p', "Number of days before next update"}, + {"rsigner", OPT_RSIGNER, '<', + "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', "Digest Algorithm to use in signature of OCSP response"}, + {"rsigopt", OPT_RSIGOPT, 's', "OCSP response signature parameter in n:v form"}, + {"header", OPT_HEADER, 's', "key=value header to add"}, + {"rcid", OPT_RCID, 's', "Use specified algorithm for cert id in response"}, + {"", OPT_MD, '-', "Any supported digest algorithm (sha1,sha256, ... )"}, + + OPT_SECTION("Client"), + {"url", OPT_URL, 's', "Responder URL"}, + {"host", OPT_HOST, 's', "TCP/IP hostname:port to connect to"}, + {"port", OPT_PORT, 'p', "Port to run responder on"}, + {"out", OPT_OUTFILE, '>', "Output filename"}, + {"noverify", OPT_NOVERIFY, '-', "Don't verify response at all"}, + {"nonce", OPT_NONCE, '-', "Add OCSP nonce to request"}, + {"no_nonce", OPT_NO_NONCE, '-', "Don't add OCSP nonce to request"}, {"no_signature_verify", OPT_NO_SIGNATURE_VERIFY, '-', "Don't check signature on response"}, + {"resp_key_id", OPT_RESP_KEY_ID, '-', + "Identify response by signing certificate key ID"}, {"no_cert_verify", OPT_NO_CERT_VERIFY, '-', "Don't check signing certificate"}, + {"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"}, {"no_chain", OPT_NO_CHAIN, '-', "Don't chain verify response"}, {"no_cert_checks", OPT_NO_CERT_CHECKS, '-', "Don't do additional checks on signing certificate"}, @@ -150,49 +219,21 @@ const 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, '-', - "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"}, - {"reqin", OPT_REQIN, 's', "File with the DER-encoded request"}, {"respin", OPT_RESPIN, 's', "File with the DER-encoded response"}, - {"signer", OPT_SIGNER, '<', "Certificate to sign OCSP request with"}, {"VAfile", OPT_VAFILE, '<', "Validator certificates file"}, - {"sign_other", OPT_SIGN_OTHER, '<', - "Additional certificates to include in signed request"}, {"verify_other", OPT_VERIFY_OTHER, '<', "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"}, + {"path", OPT_PATH, 's', "Path to use in OCSP request"}, + {"cert", OPT_CERT, '<', "Certificate to check"}, + {"serial", OPT_SERIAL, 's', "Serial number to check"}, {"validity_period", OPT_VALIDITY_PERIOD, 'u', "Maximum validity discrepancy in seconds"}, - {"status_age", OPT_STATUS_AGE, 'p', "Maximum status age in seconds"}, {"signkey", OPT_SIGNKEY, 's', "Private key to sign OCSP request with"}, {"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', "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"}, - {"nrequest", OPT_REQUEST, 'p', - "Number of requests to accept (default unlimited)"}, - {"ndays", OPT_NDAYS, 'p', "Number of days before next update"}, - {"rsigner", OPT_RSIGNER, '<', - "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', "Digest Algorithm to use in signature of OCSP response"}, - {"rsigopt", OPT_RSIGOPT, 's', "OCSP response signature parameter in n:v form"}, - {"header", OPT_HEADER, 's', "key=value header to add"}, - {"", OPT_MD, '-', "Any supported digest algorithm (sha1,sha256, ... )"}, + {"status_age", OPT_STATUS_AGE, 'p', "Maximum status age in seconds"}, + OPT_V_OPTIONS, {NULL} }; @@ -215,10 +256,11 @@ int ocsp_main(int argc, char **argv) STACK_OF(X509) *issuers = NULL; X509 *issuer = NULL, *cert = NULL; STACK_OF(X509) *rca_cert = NULL; + const EVP_MD *resp_certid_md = NULL; X509 *signer = NULL, *rsigner = NULL; X509_STORE *store = NULL; X509_VERIFY_PARAM *vpm = NULL; - const char *CAfile = NULL, *CApath = NULL; + const char *CAfile = NULL, *CApath = NULL, *CAstore = NULL; char *header, *value; char *host = NULL, *port = NULL, *path = "/", *outfile = NULL; char *rca_filename = NULL, *reqin = NULL, *respin = NULL; @@ -227,7 +269,7 @@ 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 noCAfile = 0, noCApath = 0, noCAstore = 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, ret = 1; @@ -363,12 +405,18 @@ int ocsp_main(int argc, char **argv) case OPT_CAPATH: CApath = opt_arg(); break; + case OPT_CASTORE: + CAstore = opt_arg(); + break; case OPT_NOCAFILE: noCAfile = 1; break; case OPT_NOCAPATH: noCApath = 1; break; + case OPT_NOCASTORE: + noCAstore = 1; + break; case OPT_V_CASES: if (!opt_verify(o, vpm)) goto end; @@ -471,6 +519,11 @@ int ocsp_main(int argc, char **argv) if (!X509V3_add_value(header, value, &headers)) goto end; break; + case OPT_RCID: + resp_certid_md = EVP_get_digestbyname(opt_arg()); + if (resp_certid_md == NULL) + goto opthelp; + break; case OPT_MD: if (trailing_md) { BIO_printf(bio_err, @@ -559,7 +612,7 @@ int ocsp_main(int argc, char **argv) if (ridx_filename != NULL) { rdb = load_index(ridx_filename, NULL); - if (rdb == NULL || !index_index(rdb)) { + if (rdb == NULL || index_index(rdb) <= 0) { ret = 1; goto end; } @@ -582,10 +635,11 @@ redo_accept: if (index_changed(rdb)) { CA_DB *newrdb = load_index(ridx_filename, NULL); - if (newrdb != NULL) { + if (newrdb != NULL && index_index(newrdb) > 0) { free_index(rdb); rdb = newrdb; } else { + free_index(newrdb); log_message(LOG_ERR, "error reloading updated index: %s", ridx_filename); } @@ -612,8 +666,10 @@ redo_accept: goto end; } - if (req != NULL && add_nonce) - OCSP_request_add1_nonce(req, NULL, -1); + if (req != NULL && add_nonce) { + if (!OCSP_request_add1_nonce(req, NULL, -1)) + goto end; + } if (signfile != NULL) { if (keyfile == NULL) @@ -653,7 +709,8 @@ redo_accept: if (rdb != NULL) { make_ocsp_response(bio_err, &resp, req, rdb, rca_cert, rsigner, rkey, - rsign_md, rsign_sigopts, rother, rflags, nmin, ndays, badsig); + rsign_md, rsign_sigopts, rother, rflags, nmin, ndays, badsig, + resp_certid_md); if (cbio != NULL) send_ocsp_response(cbio, resp); } else if (host != NULL) { @@ -696,10 +753,8 @@ redo_accept: if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) { BIO_printf(out, "Responder Error: %s (%d)\n", OCSP_response_status_str(i), i); - if (!ignore_err) { - ret = 0; + if (!ignore_err) goto end; - } } if (resp_text) @@ -726,7 +781,8 @@ redo_accept: } if (store == NULL) { - store = setup_verify(CAfile, CApath, noCAfile, noCApath); + store = setup_verify(CAfile, noCAfile, CApath, noCApath, + CAstore, noCAstore); if (!store) goto end; } @@ -864,6 +920,7 @@ static void killall(int ret, pid_t *kidpids) for (i = 0; i < multi; ++i) if (kidpids[i] != 0) (void)kill(kidpids[i], SIGTERM); + OPENSSL_free(kidpids); sleep(1); exit(ret); } @@ -882,7 +939,6 @@ static void noteterm (int sig) */ static void spawn_loop(void) { - const char *signame; pid_t *kidpids = NULL; int status; int procs = 0; @@ -952,6 +1008,7 @@ static void spawn_loop(void) sleep(30); break; case 0: /* child */ + OPENSSL_free(kidpids); signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); if (termsig) @@ -978,9 +1035,7 @@ static void spawn_loop(void) } /* The loop above can only break on termsig */ - signame = strsignal(termsig); - syslog(LOG_INFO, "terminating on signal: %s(%d)", - signame ? signame : "", termsig); + syslog(LOG_INFO, "terminating on signal: %d", termsig); killall(0, kidpids); } # endif @@ -1110,7 +1165,8 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req EVP_PKEY *rkey, const EVP_MD *rmd, STACK_OF(OPENSSL_STRING) *sigopts, STACK_OF(X509) *rother, unsigned long flags, - int nmin, int ndays, int badsig) + int nmin, int ndays, int badsig, + const EVP_MD *resp_md) { ASN1_TIME *thisupd = NULL, *nextupd = NULL; OCSP_CERTID *cid; @@ -1141,6 +1197,8 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req int found = 0; ASN1_OBJECT *cert_id_md_oid; const EVP_MD *cert_id_md; + OCSP_CERTID *cid_resp_md = NULL; + one = OCSP_request_onereq_get0(req, i); cid = OCSP_onereq_get0_id(one); @@ -1156,11 +1214,18 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req X509 *ca_cert = sk_X509_value(ca, jj); OCSP_CERTID *ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca_cert); - if (OCSP_id_issuer_cmp(ca_id, cid) == 0) + if (OCSP_id_issuer_cmp(ca_id, cid) == 0) { found = 1; - + if (resp_md != NULL) + cid_resp_md = OCSP_cert_to_id(resp_md, NULL, ca_cert); + } OCSP_CERTID_free(ca_id); } + OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid); + inf = lookup_serial(db, serial); + + /* at this point, we can have cid be an alias of cid_resp_md */ + cid = (cid_resp_md != NULL) ? cid_resp_md : cid; if (!found) { OCSP_basic_add1_status(bs, cid, @@ -1168,8 +1233,6 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req 0, NULL, thisupd, nextupd); continue; } - OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid); - inf = lookup_serial(db, serial); if (inf == NULL) { OCSP_basic_add1_status(bs, cid, V_OCSP_CERTSTATUS_UNKNOWN, @@ -1184,6 +1247,7 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req ASN1_GENERALIZEDTIME *invtm = NULL; OCSP_SINGLERESP *single; int reason = -1; + unpack_revinfo(&revtm, &reason, &inst, &invtm, inf[DB_rev_date]); single = OCSP_basic_add1_status(bs, cid, V_OCSP_CERTSTATUS_REVOKED, @@ -1199,6 +1263,7 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req ASN1_TIME_free(revtm); ASN1_GENERALIZEDTIME_free(invtm); } + OCSP_CERTID_free(cid_resp_md); } OCSP_copy_nonce(bs, req); @@ -1219,7 +1284,10 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req goto end; } } - OCSP_basic_sign_ctx(bs, rcert, mctx, rother, flags); + if (!OCSP_basic_sign_ctx(bs, rcert, mctx, rother, flags)) { + *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, bs); + goto end; + } if (badsig) { const ASN1_OCTET_STRING *sig = OCSP_resp_get0_signature(bs); @@ -1385,9 +1453,11 @@ static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, *q = '\0'; /* - * Skip "GET / HTTP..." requests often used by load-balancers + * Skip "GET / HTTP..." requests often used by load-balancers. Note: + * 'p' was incremented above to point to the first byte *after* the + * leading slash, so with 'GET / ' it is now an empty string. */ - if (p[1] == '\0') + if (p[0] == '\0') goto out; len = urldecode(p);