New OCSP utility. This can generate, parse and print
authorDr. Stephen Henson <steve@openssl.org>
Sat, 13 Jan 2001 01:48:38 +0000 (01:48 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Sat, 13 Jan 2001 01:48:38 +0000 (01:48 +0000)
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.

CHANGES
apps/Makefile.ssl
apps/ocsp.c [new file with mode: 0644]
apps/progs.h
crypto/ocsp/ocsp.h
crypto/ocsp/ocsp_prn.c

diff --git a/CHANGES b/CHANGES
index 0970f62b42c3df1186347b7cd539a919b23fcc6c..403568adc0d52f8acce5c806987b153d2f9acd96 100644 (file)
--- 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 <serial>' prints the status of the cert with
      the given serial number (according to the index file).
index c6cf14da5efb0b429eb8189d6d229fc57a46ba55..638f5db55c4475039ece08976527d64b6437c8f7 100644 (file)
@@ -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 (file)
index 0000000..09357ae
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <openssl/pem.h>
+#include <openssl/ocsp.h>
+#include <openssl/err.h>
+#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;
+       }
index dfc48b0d608d1cb99f892beecb1f6203f4710218..9a21f7a2d832a9eac66d713d3041fde52c33dbbb 100644 (file)
@@ -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},
index 1db672d08a806ef54f4af58d84c4a5c4d9a900b1..60b843a2fa0239eebfd166ee3eb936f35e28c3c0 100644 (file)
@@ -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);
index f949e4b8aec65a52e8e5b0223dfa0640eb7c46d0..fc6318351798a06d7416f2556075027dadf522f3 100644 (file)
@@ -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;
        }