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 0970f62..403568a 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 <serial>' 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 c6cf14d..638f5db 100644
--- a/apps/Makefile.ssl
+++ b/apps/Makefile.ssl
@@ -41,7 +41,7 @@
 	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 @@
 	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 0000000..09357ae
--- /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 <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;
+	}
diff --git a/apps/progs.h b/apps/progs.h
index dfc48b0..9a21f7a 100644
--- a/apps/progs.h
+++ b/apps/progs.h
@@ -36,6 +36,7 @@
 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 @@
 	{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 1db672d..60b843a 100644
--- a/crypto/ocsp/ocsp.h
+++ b/crypto/ocsp/ocsp.h
@@ -532,6 +532,7 @@
 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 f949e4b..fc63183 100644
--- a/crypto/ocsp/ocsp_prn.c
+++ b/crypto/ocsp/ocsp_prn.c
@@ -180,7 +180,7 @@
 
 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 @@
 
 	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 @@
 		PEM_write_bio_X509(bp,sk_X509_value(br->certs,i));
 		}
 
-	return 1;
+	ret = 1;
 err:
-	return 0;
+	OCSP_BASICRESP_free(br);
+	return ret;
 	}