X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Focsp.c;h=293b46cdb382f9ad5aa6464e87097232988d3f23;hp=cfd4f18d2e6155c08a35d3f0071e806e5c7684e3;hb=56dde3ebe6df8d925fa2465df9c87ed5506aa107;hpb=b4b1bdd5d36a279b37a303fce34cd08e4e07df9b diff --git a/apps/ocsp.c b/apps/ocsp.c index cfd4f18d2e..293b46cdb3 100644 --- a/apps/ocsp.c +++ b/apps/ocsp.c @@ -61,10 +61,15 @@ #include #include #include +#include #include "apps.h" -static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer); -static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer); +static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer, + STACK_OF(OCSP_CERTID) *ids); +static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer, + STACK_OF(OCSP_CERTID) *ids); +static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, + STACK *names, STACK_OF(OCSP_CERTID) *ids); #undef PROG #define PROG ocsp_main @@ -74,25 +79,37 @@ int MAIN(int, char **); int MAIN(int argc, char **argv) { char **args; - char *host = NULL, *path = "/"; + char *host = NULL, *port = NULL, *path = "/"; char *reqin = NULL, *respin = NULL; char *reqout = NULL, *respout = NULL; char *signfile = NULL, *keyfile = NULL; char *outfile = NULL; - int add_nonce = 1; + int add_nonce = 1, noverify = 0, use_ssl = -1; OCSP_REQUEST *req = NULL; OCSP_RESPONSE *resp = NULL; + OCSP_BASICRESP *bs = NULL; X509 *issuer = NULL, *cert = NULL; X509 *signer = NULL; EVP_PKEY *key = NULL; BIO *cbio = NULL, *derbio = NULL; BIO *out = NULL; int req_text = 0, resp_text = 0; + char *CAfile = NULL, *CApath = NULL; + X509_STORE *store = NULL; + SSL_CTX *ctx = NULL; + STACK_OF(X509) *sign_other = NULL, *verify_other = NULL; + char *sign_certfile = NULL, *verify_certfile = NULL; + unsigned long sign_flags = 0, verify_flags = 0; int ret = 1; int badarg = 0; + int i; + STACK *reqnames = NULL; + STACK_OF(OCSP_CERTID) *ids = NULL; if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); - ERR_load_crypto_strings(); + SSL_load_error_strings(); args = argv + 1; + reqnames = sk_new_null(); + ids = sk_OCSP_CERTID_new_null(); while (!badarg && *args && *args[0] == '-') { if (!strcmp(*args, "-out")) @@ -104,6 +121,19 @@ int MAIN(int argc, char **argv) } else badarg = 1; } + else if (!strcmp(*args, "-url")) + { + if (args[1]) + { + args++; + if (!OCSP_parse_url(*args, &host, &port, &path, &use_ssl)) + { + BIO_printf(bio_err, "Error parsing URL\n"); + badarg = 1; + } + } + else badarg = 1; + } else if (!strcmp(*args, "-host")) { if (args[1]) @@ -113,10 +143,28 @@ int MAIN(int argc, char **argv) } else badarg = 1; } + else if (!strcmp(*args, "-noverify")) + noverify = 1; else if (!strcmp(*args, "-nonce")) add_nonce = 2; else if (!strcmp(*args, "-no_nonce")) add_nonce = 0; + else if (!strcmp(*args, "-no_certs")) + sign_flags |= OCSP_NOCERTS; + else if (!strcmp(*args, "-no_signature_verify")) + verify_flags |= OCSP_NOSIGS; + else if (!strcmp(*args, "-no_cert_verify")) + verify_flags |= OCSP_NOVERIFY; + else if (!strcmp(*args, "-no_chain")) + verify_flags |= OCSP_NOCHAIN; + else if (!strcmp(*args, "-no_cert_checks")) + verify_flags |= OCSP_NOCHECKS; + else if (!strcmp(*args, "-no_explicit")) + verify_flags |= OCSP_NOEXPLICIT; + else if (!strcmp(*args, "-trust_other")) + verify_flags |= OCSP_TRUSTOTHER; + else if (!strcmp(*args, "-no_intern")) + verify_flags |= OCSP_NOINTERN; else if (!strcmp(*args, "-text")) { req_text = 1; @@ -153,6 +201,52 @@ int MAIN(int argc, char **argv) } else badarg = 1; } + else if (!strcmp (*args, "-VAfile")) + { + if (args[1]) + { + args++; + verify_certfile = *args; + verify_flags |= OCSP_TRUSTOTHER; + } + else badarg = 1; + } + else if (!strcmp(*args, "-sign_other")) + { + if (args[1]) + { + args++; + sign_certfile = *args; + } + else badarg = 1; + } + else if (!strcmp(*args, "-verify_other")) + { + if (args[1]) + { + args++; + verify_certfile = *args; + } + else badarg = 1; + } + else if (!strcmp (*args, "-CAfile")) + { + if (args[1]) + { + args++; + CAfile = *args; + } + else badarg = 1; + } + else if (!strcmp (*args, "-CApath")) + { + if (args[1]) + { + args++; + CApath = *args; + } + else badarg = 1; + } else if (!strcmp(*args, "-signkey")) { if (args[1]) @@ -208,7 +302,9 @@ int MAIN(int argc, char **argv) X509_free(cert); cert = load_cert(bio_err, *args, FORMAT_PEM); if(!cert) goto end; - if(!add_ocsp_cert(&req, cert, issuer)) + if(!add_ocsp_cert(&req, cert, issuer, ids)) + goto end; + if(!sk_push(reqnames, *args)) goto end; } else badarg = 1; @@ -218,7 +314,9 @@ int MAIN(int argc, char **argv) if (args[1]) { args++; - if(!add_ocsp_serial(&req, *args, issuer)) + if(!add_ocsp_serial(&req, *args, issuer, ids)) + goto end; + if(!sk_push(reqnames, *args)) goto end; } else badarg = 1; @@ -235,23 +333,37 @@ int MAIN(int argc, char **argv) BIO_printf (bio_err, "OCSP utility\n"); BIO_printf (bio_err, "Usage ocsp [options]\n"); BIO_printf (bio_err, "where options are\n"); - BIO_printf (bio_err, "-out file output filename\n"); - BIO_printf (bio_err, "-issuer file issuer certificate\n"); - BIO_printf (bio_err, "-cert file certificate to check\n"); - BIO_printf (bio_err, "-serial n serial number to check\n"); - BIO_printf (bio_err, "-signer file certificate to sign OCSP request with\n"); - BIO_printf (bio_err, "-signkey file private key to sign OCSP request with\n"); - BIO_printf (bio_err, "-req_text print text form of request\n"); - BIO_printf (bio_err, "-resp_text print text form of response\n"); - BIO_printf (bio_err, "-text print text form of request and response\n"); - BIO_printf (bio_err, "-reqout file write DER encoded OCSP request to \"file\"\n"); - BIO_printf (bio_err, "-respout file write DER encoded OCSP reponse to \"file\"\n"); - BIO_printf (bio_err, "-reqin file read DER encoded OCSP request from \"file\"\n"); - BIO_printf (bio_err, "-respin file read DER encoded OCSP reponse from \"file\"\n"); - BIO_printf (bio_err, "-nonce add OCSP nonce to request\n"); - BIO_printf (bio_err, "-no_nonce don't add OCSP nonce to request\n"); - BIO_printf (bio_err, "-host host:n send OCSP request to host on port n\n"); - BIO_printf (bio_err, "-path path to use in OCSP request\n"); + BIO_printf (bio_err, "-out file output filename\n"); + BIO_printf (bio_err, "-issuer file issuer certificate\n"); + BIO_printf (bio_err, "-cert file certificate to check\n"); + BIO_printf (bio_err, "-serial n serial number to check\n"); + BIO_printf (bio_err, "-signer file certificate to sign OCSP request with\n"); + BIO_printf (bio_err, "-signkey file private key to sign OCSP request with\n"); + BIO_printf (bio_err, "-sign_certs file additional certificates to include in signed request\n"); + BIO_printf (bio_err, "-no_certs don't include any certificates in signed request\n"); + BIO_printf (bio_err, "-req_text print text form of request\n"); + BIO_printf (bio_err, "-resp_text print text form of response\n"); + BIO_printf (bio_err, "-text print text form of request and response\n"); + BIO_printf (bio_err, "-reqout file write DER encoded OCSP request to \"file\"\n"); + BIO_printf (bio_err, "-respout file write DER encoded OCSP reponse to \"file\"\n"); + BIO_printf (bio_err, "-reqin file read DER encoded OCSP request from \"file\"\n"); + BIO_printf (bio_err, "-respin file read DER encoded OCSP reponse from \"file\"\n"); + BIO_printf (bio_err, "-nonce add OCSP nonce to request\n"); + BIO_printf (bio_err, "-no_nonce don't add OCSP nonce to request\n"); + BIO_printf (bio_err, "-url URL OCSP responder URL\n"); + BIO_printf (bio_err, "-host host:n send OCSP request to host on port n\n"); + BIO_printf (bio_err, "-path path to use in OCSP request\n"); + BIO_printf (bio_err, "-CApath dir trusted certificates directory\n"); + BIO_printf (bio_err, "-CAfile file trusted certificates file\n"); + BIO_printf (bio_err, "-VAfile file validator certificates file\n"); + BIO_printf (bio_err, "-noverify don't verify response at all\n"); + BIO_printf (bio_err, "-verify_certs file additional certificates to search for signer\n"); + BIO_printf (bio_err, "-trust_other don't verify additional certificates\n"); + BIO_printf (bio_err, "-no_intern don't search certificates contained in response for signer\n"); + BIO_printf (bio_err, "-no_sig_verify don't check signature on response\n"); + BIO_printf (bio_err, "-no_cert_verify don't check signing certificate\n"); + BIO_printf (bio_err, "-no_chain don't chain verify response\n"); + BIO_printf (bio_err, "-no_cert_checks don't do additional checks on signing certificate\n"); goto end; } @@ -289,7 +401,7 @@ int MAIN(int argc, char **argv) goto end; } - if (req) OCSP_request_add1_nonce(req, NULL, -1); + if (req && add_nonce) OCSP_request_add1_nonce(req, NULL, -1); if (signfile) { @@ -300,13 +412,18 @@ int MAIN(int argc, char **argv) BIO_printf(bio_err, "Error loading signer certificate\n"); goto end; } + if (sign_certfile) + { + sign_other = load_certs(bio_err, sign_certfile, FORMAT_PEM); + if (!sign_other) goto end; + } key = load_key(bio_err, keyfile, FORMAT_PEM, NULL, NULL); if (!key) { BIO_printf(bio_err, "Error loading signer private key\n"); goto end; } - if (!OCSP_request_sign(req, signer, key, EVP_sha1(), NULL, 0)) + if (!OCSP_request_sign(req, signer, key, EVP_sha1(), sign_other, sign_flags)) { BIO_printf(bio_err, "Error signing OCSP request\n"); goto end; @@ -335,13 +452,22 @@ int MAIN(int argc, char **argv) BIO_printf(bio_err, "Error creating connect BIO\n"); goto end; } + if (port) BIO_set_conn_port(cbio, port); + if (use_ssl == 1) + { + BIO *sbio; + ctx = SSL_CTX_new(SSLv23_client_method()); + SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); + sbio = BIO_new_ssl(ctx, 1); + cbio = BIO_push(sbio, cbio); + } if (BIO_do_connect(cbio) <= 0) { BIO_printf(bio_err, "Error connecting BIO\n"); goto end; } resp = OCSP_sendreq_bio(cbio, path, req); - BIO_free(cbio); + BIO_free_all(cbio); cbio = NULL; if (!resp) { @@ -384,25 +510,95 @@ int MAIN(int argc, char **argv) BIO_free(derbio); } + i = OCSP_response_status(resp); + + if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) + { + BIO_printf(out, "Responder Error: %s (%ld)\n", + OCSP_response_status_str(i), i); + ret = 0; + goto end; + } + if (resp_text) OCSP_RESPONSE_print(out, resp, 0); + store = setup_verify(bio_err, CAfile, CApath); + if(!store) goto end; + if (verify_certfile) + { + verify_other = load_certs(bio_err, verify_certfile, FORMAT_PEM); + if (!verify_other) goto end; + } + + bs = OCSP_response_get1_basic(resp); + + if (!bs) + { + BIO_printf(bio_err, "Error parsing response\n"); + goto end; + } + + if (!noverify) + { + if (req && ((i = OCSP_check_nonce(req, bs)) <= 0)) + { + if (i == -1) + BIO_printf(bio_err, "WARNING: no nonce in response\n"); + else + { + BIO_printf(bio_err, "Nonce Verify error\n"); + goto end; + } + } + + i = OCSP_basic_verify(bs, verify_other, store, verify_flags); + if (i < 0) i = OCSP_basic_verify(bs, NULL, store, 0); + + if(i <= 0) + { + BIO_printf(bio_err, "Response Verify Failure\n", i); + ERR_print_errors(bio_err); + } + else + BIO_printf(bio_err, "Response verify OK\n"); + + } + + if (!print_ocsp_summary(out, bs, req, reqnames, ids)) + goto end; + ret = 0; end: ERR_print_errors(bio_err); X509_free(signer); + X509_STORE_free(store); EVP_PKEY_free(key); X509_free(issuer); X509_free(cert); - BIO_free(cbio); + BIO_free_all(cbio); BIO_free(out); OCSP_REQUEST_free(req); OCSP_RESPONSE_free(resp); + OCSP_BASICRESP_free(bs); + sk_free(reqnames); + sk_OCSP_CERTID_free(ids); + sk_X509_pop_free(sign_other, X509_free); + sk_X509_pop_free(verify_other, X509_free); + + if (use_ssl != -1) + { + OPENSSL_free(host); + OPENSSL_free(port); + OPENSSL_free(path); + SSL_CTX_free(ctx); + } EXIT(ret); } -static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer) +static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer, + STACK_OF(OCSP_CERTID) *ids) { OCSP_CERTID *id; if(!issuer) @@ -413,7 +609,7 @@ static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer) if(!*req) *req = OCSP_REQUEST_new(); if(!*req) goto err; id = OCSP_cert_to_id(NULL, cert, issuer); - if(!id) goto err; + if(!id || !sk_OCSP_CERTID_push(ids, id)) goto err; if(!OCSP_request_add0_id(*req, id)) goto err; return 1; @@ -422,7 +618,8 @@ static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer) return 0; } -static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer) +static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer, + STACK_OF(OCSP_CERTID) *ids) { OCSP_CERTID *id; X509_NAME *iname; @@ -436,7 +633,7 @@ static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer) if(!*req) *req = OCSP_REQUEST_new(); if(!*req) goto err; iname = X509_get_subject_name(issuer); - ikey = issuer->cert_info->key->public_key; + ikey = X509_get0_pubkey_bitstr(issuer); sno = s2i_ASN1_INTEGER(NULL, serial); if(!sno) { @@ -445,7 +642,7 @@ static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer) } id = OCSP_cert_id_new(EVP_sha1(), iname, ikey, sno); ASN1_INTEGER_free(sno); - if(!id) goto err; + if(!id || !sk_OCSP_CERTID_push(ids, id)) goto err; if(!OCSP_request_add0_id(*req, id)) goto err; return 1; @@ -453,3 +650,58 @@ static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer) BIO_printf(bio_err, "Error Creating OCSP request\n"); return 0; } + +static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, + STACK *names, STACK_OF(OCSP_CERTID) *ids) + { + OCSP_CERTID *id; + char *name; + int i; + + int status, reason; + + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + + if (!bs || !req || !sk_num(names) || !sk_OCSP_CERTID_num(ids)) + return 1; + + for (i = 0; i < sk_OCSP_CERTID_num(ids); i++) + { + id = sk_OCSP_CERTID_value(ids, i); + name = sk_value(names, i); + BIO_printf(out, "%s: ", name); + + if(!OCSP_resp_find_status(bs, id, &status, &reason, + &rev, &thisupd, &nextupd)) + { + BIO_puts(out, "ERROR: No Status found.\n"); + continue; + } + BIO_printf(out, "%s\n", OCSP_cert_status_str(status)); + + BIO_puts(out, "\tThis Update: "); + ASN1_GENERALIZEDTIME_print(out, thisupd); + BIO_puts(out, "\n"); + + if(nextupd) + { + BIO_puts(out, "\tNext Update: "); + ASN1_GENERALIZEDTIME_print(out, thisupd); + BIO_puts(out, "\n"); + } + + if (status != V_OCSP_CERTSTATUS_REVOKED) + continue; + + if (reason != -1) + BIO_printf(out, "\tReason: %s\n", + OCSP_crl_reason_str(reason)); + + BIO_puts(out, "\tRevocation Time: "); + ASN1_GENERALIZEDTIME_print(out, rev); + BIO_puts(out, "\n"); + } + + return 1; + } +