Commit 67c8e7f4 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Support for certificate status TLS extension.

parent 74eb3e09
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -4,6 +4,13 @@

 Changes between 0.9.8f and 0.9.9  [xx XXX xxxx]

  *) Implement certificate status request TLS extension defined in RFC3546.
     A client can set the appropriate parameters and receive the encoded
     OCSP response via a callback. A server can query the supplied parameters
     and set the encoded OCSP response in the callback. Add simplified examples
     to s_client and s_server.
     [Steve Henson]

  *) Implement Opaque PRF Input TLS extension as specified in
     draft-rescorla-tls-opaque-prf-input-00.txt.  Since this is not an
     official specification yet and no extension type assignment by
+9 −0
Original line number Diff line number Diff line
@@ -122,6 +122,9 @@
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif
#ifndef OPENSSL_NO_OCSP
#include <openssl/ocsp.h>
#endif
#include <openssl/ossl_typ.h>

int app_RAND_load_file(const char *file, BIO *bio_e, int dont_warn);
@@ -247,6 +250,12 @@ X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath);
ENGINE *setup_engine(BIO *err, const char *engine, int debug);
#endif

#ifndef OPENSSL_NO_OCSP
OCSP_RESPONSE *process_responder(BIO *err, OCSP_REQUEST *req,
			char *host, char *path, char *port, int use_ssl,
			int req_timeout);
#endif

int load_config(BIO *err, CONF *cnf);
char *make_config_name(void);

+51 −40
Original line number Diff line number Diff line
@@ -120,7 +120,6 @@ int MAIN(int argc, char **argv)
	long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
	char *CAfile = NULL, *CApath = NULL;
	X509_STORE *store = NULL;
	SSL_CTX *ctx = NULL;
	STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
	char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL;
	unsigned long sign_flags = 0, verify_flags = 0, rflags = 0;
@@ -723,48 +722,14 @@ int MAIN(int argc, char **argv)
	else if (host)
		{
#ifndef OPENSSL_NO_SOCK
		cbio = BIO_new_connect(host);
#else
		BIO_printf(bio_err, "Error creating connect BIO - sockets not supported.\n");
		goto end;
#endif
		if (!cbio)
			{
			BIO_printf(bio_err, "Error creating connect BIO\n");
		resp = process_responder(bio_err, req, host, path,
						port, use_ssl, req_timeout);
		if (!resp)
			goto end;
			}
		if (port) BIO_set_conn_port(cbio, port);
		if (use_ssl == 1)
			{
			BIO *sbio;
#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
			ctx = SSL_CTX_new(SSLv23_client_method());
#elif !defined(OPENSSL_NO_SSL3)
			ctx = SSL_CTX_new(SSLv3_client_method());
#elif !defined(OPENSSL_NO_SSL2)
			ctx = SSL_CTX_new(SSLv2_client_method());
#else
			BIO_printf(bio_err, "SSL is disabled\n");
		BIO_printf(bio_err, "Error creating connect BIO - sockets not supported.\n");
		goto end;
#endif
			if (ctx == NULL)
				{
				BIO_printf(bio_err, "Error creating SSL context.\n");
				goto end;
				}
			SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
			sbio = BIO_new_ssl(ctx, 1);
			cbio = BIO_push(sbio, cbio);
			}

		resp = query_responder(bio_err, cbio, path, req, req_timeout);
		BIO_free_all(cbio);
		cbio = NULL;
		if (!resp)
			{
			BIO_printf(bio_err, "Error querying OCSP responsder\n");
			goto end;
			}
		}
	else if (respin)
		{
@@ -913,7 +878,6 @@ end:
		OPENSSL_free(host);
		OPENSSL_free(port);
		OPENSSL_free(path);
		SSL_CTX_free(ctx);
		}

	OPENSSL_EXIT(ret);
@@ -1334,4 +1298,51 @@ static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
	return rsp;
	}

OCSP_RESPONSE *process_responder(BIO *err, OCSP_REQUEST *req,
			char *host, char *path, char *port, int use_ssl,
			int req_timeout)
	{
	BIO *cbio = NULL;
	SSL_CTX *ctx = NULL;
	OCSP_RESPONSE *resp = NULL;
	cbio = BIO_new_connect(host);
	if (!cbio)
		{
		BIO_printf(err, "Error creating connect BIO\n");
		goto end;
		}
	if (port) BIO_set_conn_port(cbio, port);
	if (use_ssl == 1)
		{
		BIO *sbio;
#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
		ctx = SSL_CTX_new(SSLv23_client_method());
#elif !defined(OPENSSL_NO_SSL3)
		ctx = SSL_CTX_new(SSLv3_client_method());
#elif !defined(OPENSSL_NO_SSL2)
		ctx = SSL_CTX_new(SSLv2_client_method());
#else
		BIO_printf(err, "SSL is disabled\n");
			goto end;
#endif
		if (ctx == NULL)
			{
			BIO_printf(err, "Error creating SSL context.\n");
			goto end;
			}
		SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
		sbio = BIO_new_ssl(ctx, 1);
		cbio = BIO_push(sbio, cbio);
		}
	resp = query_responder(err, cbio, path, req, req_timeout);
	if (!resp)
		BIO_printf(bio_err, "Error querying OCSP responsder\n");
	end:
	if (ctx)
		SSL_CTX_free(ctx);
	if (cbio)
		BIO_free_all(cbio);
	return resp;
	}

#endif
+48 −0
Original line number Diff line number Diff line
@@ -161,6 +161,7 @@ typedef unsigned int u_int;
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/ocsp.h>
#include "s_apps.h"
#include "timeouts.h"

@@ -196,12 +197,14 @@ static int c_Pause=0;
static int c_debug=0;
#ifndef OPENSSL_NO_TLSEXT
static int c_tlsextdebug=0;
static int c_status_req=0;
#endif
static int c_msg=0;
static int c_showcerts=0;

static void sc_usage(void);
static void print_stuff(BIO *berr,SSL *con,int full);
static int ocsp_resp_cb(SSL *s, void *arg);
static BIO *bio_c_out=NULL;
static int c_quiet=0;
static int c_ign_eof=0;
@@ -329,6 +332,7 @@ static void sc_usage(void)
#ifndef OPENSSL_NO_TLSEXT
	BIO_printf(bio_err," -servername host  - Set TLS extension servername in ClientHello\n");
	BIO_printf(bio_err," -tlsextdebug      - hex dump of all TLS extensions received\n");
	BIO_printf(bio_err," -status           - request certificate status from server\n");
	BIO_printf(bio_err," -no_ticket        - disable use of RFC4507bis session tickets\n");
#endif
	}
@@ -528,6 +532,8 @@ int MAIN(int argc, char **argv)
#ifndef OPENSSL_NO_TLSEXT
		else if	(strcmp(*argv,"-tlsextdebug") == 0)
			c_tlsextdebug=1;
		else if	(strcmp(*argv,"-status") == 0)
			c_status_req=1;
#endif
#ifdef WATT32
		else if (strcmp(*argv,"-wdebug") == 0)
@@ -954,6 +960,23 @@ re_start:
		SSL_set_tlsext_debug_callback(con, tlsext_cb);
		SSL_set_tlsext_debug_arg(con, bio_c_out);
		}
	if (c_status_req)
		{
		SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp);
		SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb);
		SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out);
#if 0
{
STACK_OF(OCSP_RESPID) *ids = sk_OCSP_RESPID_new_null();
OCSP_RESPID *id = OCSP_RESPID_new();
id->value.byKey = ASN1_OCTET_STRING_new();
id->type = V_OCSP_RESPID_KEY;
ASN1_STRING_set(id->value.byKey, "Hello World", -1);
sk_OCSP_RESPID_push(ids, id);
SSL_set_tlsext_status_ids(con, ids);
}
#endif
		}
#endif

	SSL_set_bio(con,sbio,sbio);
@@ -1592,3 +1615,28 @@ static void print_stuff(BIO *bio, SSL *s, int full)
	(void)BIO_flush(bio);
	}

static int ocsp_resp_cb(SSL *s, void *arg)
	{
	const unsigned char *p;
	int len;
	OCSP_RESPONSE *rsp;
	len = SSL_get_tlsext_status_ocsp_resp(s, &p);
	BIO_puts(arg, "OCSP response: ");
	if (!p)
		{
		BIO_puts(arg, "no response sent\n");
		return 1;
		}
	rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
	if (!rsp)
		{
		BIO_puts(arg, "response parse error\n");
		BIO_dump_indent(arg, (char *)p, len, 4);
		return 0;
		}
	BIO_puts(arg, "\n======================================\n");
	OCSP_RESPONSE_print(arg, rsp, 0);
	BIO_puts(arg, "======================================\n");
	OCSP_RESPONSE_free(rsp);
	return 1;
	}
+182 −0
Original line number Diff line number Diff line
@@ -179,6 +179,7 @@ typedef unsigned int u_int;
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/ocsp.h>
#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
#endif
@@ -283,6 +284,8 @@ static BIO *bio_s_out=NULL;
static int s_debug=0;
#ifndef OPENSSL_NO_TLSEXT
static int s_tlsextdebug=0;
static int s_tlsextstatus=0;
static int cert_status_cb(SSL *s, void *arg);
#endif
static int s_msg=0;
static int s_quiet=0;
@@ -664,6 +667,152 @@ static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg)
		}
	return SSL_TLSEXT_ERR_OK;
}

/* Structure passed to cert status callback */

typedef struct tlsextstatusctx_st {
   /* Default responder to use */
   char *host, *path, *port;
   int use_ssl;
   int timeout;
   BIO *err;
   int verbose;
} tlsextstatusctx;

static tlsextstatusctx tlscstatp = {NULL, NULL, NULL, 0, -1, NULL, 0};

/* Certificate Status callback. This is called when a client includes a
 * certificate status request extension.
 *
 * This is a simplified version. It examines certificates each time and
 * makes one OCSP responder query for each request.
 *
 * A full version would store details such as the OCSP certificate IDs and
 * minimise the number of OCSP responses by caching them until they were
 * considered "expired".
 */

static int cert_status_cb(SSL *s, void *arg)
	{
	tlsextstatusctx *srctx = arg;
	BIO *err = srctx->err;
	char *host, *port, *path;
	int use_ssl;
	unsigned char *rspder = NULL;
	int rspderlen;
	STACK *aia = NULL;
	X509 *x = NULL;
	X509_STORE_CTX inctx;
	X509_OBJECT obj;
	OCSP_REQUEST *req = NULL;
	OCSP_RESPONSE *resp = NULL;
	OCSP_CERTID *id = NULL;
	STACK_OF(X509_EXTENSION) *exts;
	int ret = SSL_TLSEXT_ERR_NOACK;
	int i;
#if 0
STACK_OF(OCSP_RESPID) *ids;
SSL_get_tlsext_status_ids(s, &ids);
BIO_printf(err, "cert_status: received %d ids\n", sk_OCSP_RESPID_num(ids));
#endif
	if (srctx->verbose)
		BIO_puts(err, "cert_status: callback called\n");
	/* Build up OCSP query from server certificate */
	x = SSL_get_certificate(s);
	aia = X509_get1_ocsp(x);
	if (aia)
		{
		if (!OCSP_parse_url(sk_value(aia, 0),
			&host, &port, &path, &use_ssl))
			{
			BIO_puts(err, "cert_status: can't parse AIA URL\n");
			goto err;
			}
		if (srctx->verbose)
			BIO_printf(err, "cert_status: AIA URL: %s\n",
					sk_value(aia, 0));
		}
	else
		{
		if (!srctx->host)
			{
			BIO_puts(srctx->err, "cert_status: no AIA and no default responder URL\n");
			goto done;
			}
		host = srctx->host;
		path = srctx->path;
		port = srctx->port;
		use_ssl = srctx->use_ssl;
		}
		
	if (!X509_STORE_CTX_init(&inctx,
				SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s)),
				NULL, NULL))
		goto err;
	if (X509_STORE_get_by_subject(&inctx,X509_LU_X509,
				X509_get_issuer_name(x),&obj) <= 0)
		{
		BIO_puts(err, "cert_status: Can't retrieve issuer certificate.\n");
		X509_STORE_CTX_cleanup(&inctx);
		goto done;
		}
	req = OCSP_REQUEST_new();
	if (!req)
		goto err;
	id = OCSP_cert_to_id(NULL, x, obj.data.x509);
	X509_free(obj.data.x509);
	X509_STORE_CTX_cleanup(&inctx);
	if (!id)
		goto err;
	if (!OCSP_request_add0_id(req, id))
		goto err;
	id = NULL;
	/* Add any extensions to the request */
	SSL_get_tlsext_status_exts(s, &exts);
	for (i = 0; i < sk_X509_EXTENSION_num(exts); i++)
		{
		X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
		if (!OCSP_REQUEST_add_ext(req, ext, -1))
			goto err;
		}
	resp = process_responder(err, req, host, path, port, use_ssl,
					srctx->timeout);
	if (!resp)
		{
		BIO_puts(err, "cert_status: error querying responder\n");
		goto done;
		}
	rspderlen = i2d_OCSP_RESPONSE(resp, &rspder);
	if (rspderlen <= 0)
		goto err;
	SSL_set_tlsext_status_ocsp_resp(s, rspder, rspderlen);
	if (srctx->verbose)
		{
		BIO_puts(err, "cert_status: ocsp response sent:\n");
		OCSP_RESPONSE_print(err, resp, 2);
		}
	ret = SSL_TLSEXT_ERR_OK;
	done:
	if (ret != SSL_TLSEXT_ERR_OK)
		ERR_print_errors(err);
	if (aia)
		{
		OPENSSL_free(host);
		OPENSSL_free(path);
		OPENSSL_free(port);
		X509_email_free(aia);
		}
	if (id)
		OCSP_CERTID_free(id);
	if (req)
		OCSP_REQUEST_free(req);
	if (resp)
		OCSP_RESPONSE_free(resp);
	return ret;
	err:
	ret = SSL_TLSEXT_ERR_ALERT_FATAL;
	goto done;
	}
#endif

int MAIN(int, char **);
@@ -877,6 +1026,33 @@ int MAIN(int argc, char *argv[])
#ifndef OPENSSL_NO_TLSEXT
		else if	(strcmp(*argv,"-tlsextdebug") == 0)
			s_tlsextdebug=1;
		else if	(strcmp(*argv,"-status") == 0)
			s_tlsextstatus=1;
		else if	(strcmp(*argv,"-status_verbose") == 0)
			{
			s_tlsextstatus=1;
			tlscstatp.verbose = 1;
			}
		else if (!strcmp(*argv, "-status_timeout"))
			{
			s_tlsextstatus=1;
                        if (--argc < 1) goto bad;
			tlscstatp.timeout = atoi(*(++argv));
			}
		else if (!strcmp(*argv, "-status_url"))
			{
			s_tlsextstatus=1;
                        if (--argc < 1) goto bad;
			if (!OCSP_parse_url(*(++argv),
					&tlscstatp.host,
					&tlscstatp.port,
					&tlscstatp.path,
					&tlscstatp.use_ssl))
				{
				BIO_printf(bio_err, "Error parsing URL\n");
				goto bad;
				}
			}
#endif
		else if	(strcmp(*argv,"-msg") == 0)
			{ s_msg=1; }
@@ -1560,6 +1736,12 @@ static int sv_body(char *hostname, int s, unsigned char *context)
		SSL_set_tlsext_debug_callback(con, tlsext_cb);
		SSL_set_tlsext_debug_arg(con, bio_s_out);
		}
	if (s_tlsextstatus);
		{
		SSL_CTX_set_tlsext_status_cb(ctx, cert_status_cb);
		tlscstatp.err = bio_err;
		SSL_CTX_set_tlsext_status_arg(ctx, &tlscstatp);
		}
#endif
#ifndef OPENSSL_NO_KRB5
		if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
Loading