From: Dr. Stephen Henson Date: Sat, 13 Jan 2001 01:48:38 +0000 (+0000) Subject: New OCSP utility. This can generate, parse and print X-Git-Tag: OpenSSL_0_9_6a-beta1~81^2~32 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=5782ceb2983b9e998b858474224fc011d6f0bd39 New OCSP utility. This can generate, parse and print OCSP requests. It can also query reponders and parse or print out responses. Still needs some more work: OCSP response checks and of course documentation. --- diff --git a/CHANGES b/CHANGES index 0970f62b42..403568adc0 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,12 @@ Changes between 0.9.6 and 0.9.7 [xx XXX 2000] + *) New OCSP utility. Allows OCSP requests to be generated or + read. The request can be sent to a responder and the output + parsed, outputed or printed in text form. Not complete yet: + still needs to check the OCSP response validity. + [Steve Henson] + *) New subcommands for 'openssl ca': 'openssl ca -status ' prints the status of the cert with the given serial number (according to the index file). diff --git a/apps/Makefile.ssl b/apps/Makefile.ssl index c6cf14da5e..638f5db55c 100644 --- a/apps/Makefile.ssl +++ b/apps/Makefile.ssl @@ -41,7 +41,7 @@ E_EXE= verify asn1pars req dgst dh dhparam enc passwd gendh errstr \ ca crl rsa rsautl dsa dsaparam \ x509 genrsa gendsa s_server s_client speed \ s_time version pkcs7 crl2pkcs7 sess_id ciphers nseq pkcs12 \ - pkcs8 spkac smime rand engine + pkcs8 spkac smime rand engine ocsp PROGS= $(PROGRAM).c @@ -57,14 +57,14 @@ E_OBJ= verify.o asn1pars.o req.o dgst.o dh.o dhparam.o enc.o passwd.o gendh.o er rsa.o rsautl.o dsa.o dsaparam.o \ x509.o genrsa.o gendsa.o s_server.o s_client.o speed.o \ s_time.o $(A_OBJ) $(S_OBJ) $(RAND_OBJ) version.o sess_id.o \ - ciphers.o nseq.o pkcs12.o pkcs8.o spkac.o smime.o rand.o engine.o + ciphers.o nseq.o pkcs12.o pkcs8.o spkac.o smime.o rand.o engine.o ocsp.o E_SRC= verify.c asn1pars.c req.c dgst.c dh.c enc.c passwd.c gendh.c errstr.c ca.c \ pkcs7.c crl2p7.c crl.c \ rsa.c rsautl.c dsa.c dsaparam.c \ x509.c genrsa.c gendsa.c s_server.c s_client.c speed.c \ s_time.c $(A_SRC) $(S_SRC) $(RAND_SRC) version.c sess_id.c \ - ciphers.c nseq.c pkcs12.c pkcs8.c spkac.c smime.c rand.c engine.c + ciphers.c nseq.c pkcs12.c pkcs8.c spkac.c smime.c rand.c engine.c ocsp.c SRC=$(E_SRC) diff --git a/apps/ocsp.c b/apps/ocsp.c new file mode 100644 index 0000000000..09357ae098 --- /dev/null +++ b/apps/ocsp.c @@ -0,0 +1,452 @@ +/* ocsp.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) 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). + * + */ + +#include +#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); + +#undef PROG +#define PROG ocsp_main + +int MAIN(int, char **); + +int MAIN(int argc, char **argv) + { + char **args; + char *host = NULL, *path = "/"; + char *reqin = NULL, *respin = NULL; + char *reqout = NULL, *respout = NULL; + char *signfile = NULL, *keyfile = NULL; + char *outfile = NULL; + int add_nonce = 1; + OCSP_REQUEST *req = NULL; + OCSP_RESPONSE *resp = 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; + int ret = 1; + int badarg = 0; + if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + ERR_load_crypto_strings(); + args = argv + 1; + while (!badarg && *args && *args[0] == '-') + { + if (!strcmp(*args, "-out")) + { + if (args[1]) + { + args++; + outfile = *args; + } + else badarg = 1; + } + else if (!strcmp(*args, "-host")) + { + if (args[1]) + { + args++; + host = *args; + } + else badarg = 1; + } + else if (!strcmp(*args, "-nonce")) + add_nonce = 2; + else if (!strcmp(*args, "-no_nonce")) + add_nonce = 0; + else if (!strcmp(*args, "-text")) + { + req_text = 1; + resp_text = 1; + } + else if (!strcmp(*args, "-req_text")) + req_text = 1; + else if (!strcmp(*args, "-resp_text")) + resp_text = 1; + else if (!strcmp(*args, "-reqin")) + { + if (args[1]) + { + args++; + reqin = *args; + } + else badarg = 1; + } + else if (!strcmp(*args, "-respin")) + { + if (args[1]) + { + args++; + respin = *args; + } + else badarg = 1; + } + else if (!strcmp(*args, "-signer")) + { + if (args[1]) + { + args++; + signfile = *args; + } + else badarg = 1; + } + else if (!strcmp(*args, "-signkey")) + { + if (args[1]) + { + args++; + keyfile = *args; + } + else badarg = 1; + } + else if (!strcmp(*args, "-reqout")) + { + if (args[1]) + { + args++; + reqout = *args; + } + else badarg = 1; + } + else if (!strcmp(*args, "-respout")) + { + if (args[1]) + { + args++; + respout = *args; + } + else badarg = 1; + } + else if (!strcmp(*args, "-path")) + { + if (args[1]) + { + args++; + path = *args; + } + else badarg = 1; + } + else if (!strcmp(*args, "-issuer")) + { + if (args[1]) + { + args++; + X509_free(issuer); + issuer = load_cert(bio_err, *args, FORMAT_PEM); + if(!issuer) goto end; + } + else badarg = 1; + } + else if (!strcmp (*args, "-cert")) + { + if (args[1]) + { + args++; + X509_free(cert); + cert = load_cert(bio_err, *args, FORMAT_PEM); + if(!cert) goto end; + if(!add_ocsp_cert(&req, cert, issuer)) + goto end; + } + else badarg = 1; + } + else if (!strcmp(*args, "-serial")) + { + if (args[1]) + { + args++; + if(!add_ocsp_serial(&req, *args, issuer)) + goto end; + } + else badarg = 1; + } + else badarg = 1; + args++; + } + + /* Have we anything to do? */ + if (!req && !reqin && !respin) badarg = 1; + + if (badarg) + { + 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, "-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, "-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"); + goto end; + } + + if(outfile) out = BIO_new_file(outfile, "w"); + else out = BIO_new_fp(stdout, BIO_NOCLOSE); + + if(!out) + { + BIO_printf(bio_err, "Error opening output file\n"); + goto end; + } + + if (!req && (add_nonce != 2)) add_nonce = 0; + + if (!req && reqin) + { + derbio = BIO_new_file(reqin, "rb"); + if (!derbio) + { + BIO_printf(bio_err, "Error Opening OCSP request file\n"); + goto end; + } + req = d2i_OCSP_REQUEST_bio(derbio, NULL); + BIO_free(derbio); + if(!req) + { + BIO_printf(bio_err, "Error reading OCSP request\n"); + goto end; + } + } + + if (!req && (signfile || reqout || host || add_nonce)) + { + BIO_printf(bio_err, "Need an OCSP request for this operation!\n"); + goto end; + } + + if (req) OCSP_request_add1_nonce(req, NULL, -1); + + if (signfile) + { + if (!keyfile) keyfile = signfile; + signer = load_cert(bio_err, signfile, FORMAT_PEM); + if (!signer) + { + BIO_printf(bio_err, "Error loading signer certificate\n"); + 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)) + { + BIO_printf(bio_err, "Error signing OCSP request\n"); + goto end; + } + } + + if (reqout) + { + derbio = BIO_new_file(reqout, "wb"); + if (!derbio) + { + BIO_printf(bio_err, "Error opening file %s\n", reqout); + goto end; + } + i2d_OCSP_REQUEST_bio(derbio, req); + BIO_free(derbio); + } + + if (req_text && req) OCSP_REQUEST_print(out, req, 0); + + if (host) + { + cbio = BIO_new_connect(host); + if (!cbio) + { + BIO_printf(bio_err, "Error creating connect BIO\n"); + goto end; + } + 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); + cbio = NULL; + if (!resp) + { + BIO_printf(bio_err, "Error querying OCSP responsder\n"); + goto end; + } + } + else if (respin) + { + derbio = BIO_new_file(respin, "rb"); + if (!derbio) + { + BIO_printf(bio_err, "Error Opening OCSP response file\n"); + goto end; + } + resp = d2i_OCSP_RESPONSE_bio(derbio, NULL); + BIO_free(derbio); + if(!resp) + { + BIO_printf(bio_err, "Error reading OCSP response\n"); + goto end; + } + + } + else + { + ret = 0; + goto end; + } + + if (respout) + { + derbio = BIO_new_file(respout, "wb"); + if(!derbio) + { + BIO_printf(bio_err, "Error opening file %s\n", respout); + goto end; + } + i2d_OCSP_RESPONSE_bio(derbio, resp); + BIO_free(derbio); + } + + if (resp_text) OCSP_RESPONSE_print(out, resp, 0); + + ret = 0; + +end: + ERR_print_errors(bio_err); + X509_free(signer); + EVP_PKEY_free(key); + X509_free(issuer); + X509_free(cert); + BIO_free(cbio); + BIO_free(out); + OCSP_REQUEST_free(req); + OCSP_RESPONSE_free(resp); + + EXIT(ret); +} + +static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer) + { + OCSP_CERTID *id; + if(!issuer) + { + BIO_printf(bio_err, "No issuer certificate specified\n"); + return 0; + } + if(!*req) *req = OCSP_REQUEST_new(); + if(!*req) goto err; + id = OCSP_cert_to_id(NULL, cert, issuer); + if(!id) goto err; + if(!OCSP_request_add0_id(*req, id)) goto err; + return 1; + + err: + BIO_printf(bio_err, "Error Creating OCSP request\n"); + return 0; + } + +static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer) + { + OCSP_CERTID *id; + X509_NAME *iname; + ASN1_BIT_STRING *ikey; + ASN1_INTEGER *sno; + if(!issuer) + { + BIO_printf(bio_err, "No issuer certificate specified\n"); + return 0; + } + if(!*req) *req = OCSP_REQUEST_new(); + if(!*req) goto err; + iname = X509_get_subject_name(issuer); + ikey = issuer->cert_info->key->public_key; + sno = s2i_ASN1_INTEGER(NULL, serial); + if(!sno) + { + BIO_printf(bio_err, "Error converting serial number %s\n", serial); + return 0; + } + id = OCSP_cert_id_new(EVP_sha1(), iname, ikey, sno); + ASN1_INTEGER_free(sno); + if(!id) goto err; + if(!OCSP_request_add0_id(*req, id)) goto err; + return 1; + + err: + BIO_printf(bio_err, "Error Creating OCSP request\n"); + return 0; + } diff --git a/apps/progs.h b/apps/progs.h index dfc48b0d60..9a21f7a2d8 100644 --- a/apps/progs.h +++ b/apps/progs.h @@ -36,6 +36,7 @@ extern int spkac_main(int argc,char *argv[]); extern int smime_main(int argc,char *argv[]); extern int rand_main(int argc,char *argv[]); extern int engine_main(int argc,char *argv[]); +extern int ocsp_main(int argc,char *argv[]); #define FUNC_TYPE_GENERAL 1 #define FUNC_TYPE_MD 2 @@ -111,6 +112,7 @@ FUNCTION functions[] = { {FUNC_TYPE_GENERAL,"smime",smime_main}, {FUNC_TYPE_GENERAL,"rand",rand_main}, {FUNC_TYPE_GENERAL,"engine",engine_main}, + {FUNC_TYPE_GENERAL,"ocsp",ocsp_main}, {FUNC_TYPE_MD,"md2",dgst_main}, {FUNC_TYPE_MD,"md4",dgst_main}, {FUNC_TYPE_MD,"md5",dgst_main}, diff --git a/crypto/ocsp/ocsp.h b/crypto/ocsp/ocsp.h index 1db672d08a..60b843a2fa 100644 --- a/crypto/ocsp/ocsp.h +++ b/crypto/ocsp/ocsp.h @@ -532,6 +532,7 @@ DECLARE_ASN1_FUNCTIONS(OCSP_CRLID) DECLARE_ASN1_FUNCTIONS(OCSP_SERVICELOC) int OCSP_REQUEST_print(BIO *bp, OCSP_REQUEST* a, unsigned long flags); +int OCSP_RESPONSE_print(BIO *bp, OCSP_RESPONSE* o, unsigned long flags); int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, X509_STORE *st, unsigned long flags); diff --git a/crypto/ocsp/ocsp_prn.c b/crypto/ocsp/ocsp_prn.c index f949e4b8ae..fc63183517 100644 --- a/crypto/ocsp/ocsp_prn.c +++ b/crypto/ocsp/ocsp_prn.c @@ -180,7 +180,7 @@ err: int OCSP_RESPONSE_print(BIO *bp, OCSP_RESPONSE* o, unsigned long flags) { - int i; + int i, ret = 0; long l; unsigned char *p; OCSP_CERTID *cid = NULL; @@ -209,7 +209,7 @@ int OCSP_RESPONSE_print(BIO *bp, OCSP_RESPONSE* o, unsigned long flags) p = ASN1_STRING_data(rb->response); i = ASN1_STRING_length(rb->response); - if (!(d2i_OCSP_BASICRESP(&br, &p, i))) goto err; + if (!(br = OCSP_response_get1_basic(o))) goto err; rd = br->tbsResponseData; l=ASN1_INTEGER_get(rd->version); if (BIO_printf(bp,"\n Version: %lu (0x%lx)\n", @@ -283,7 +283,8 @@ int OCSP_RESPONSE_print(BIO *bp, OCSP_RESPONSE* o, unsigned long flags) PEM_write_bio_X509(bp,sk_X509_value(br->certs,i)); } - return 1; + ret = 1; err: - return 0; + OCSP_BASICRESP_free(br); + return ret; }