aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2007-09-26 21:56:59 +0000
committerDr. Stephen Henson <steve@openssl.org>2007-09-26 21:56:59 +0000
commit67c8e7f41486934b6809673b6d836d38eaf2383b (patch)
tree06fd94dda26946a4d53a63a98b280aeffbc0aac7
parent74eb3e091412be483d419c6ae3cdb6be2c1fb273 (diff)
downloadopenssl-67c8e7f41486934b6809673b6d836d38eaf2383b.tar.gz
Support for certificate status TLS extension.
-rw-r--r--CHANGES7
-rw-r--r--apps/apps.h9
-rw-r--r--apps/ocsp.c91
-rw-r--r--apps/s_client.c48
-rw-r--r--apps/s_server.c182
-rw-r--r--apps/x509.c11
-rw-r--r--crypto/asn1/x_exten.c5
-rw-r--r--crypto/ocsp/ocsp.h12
-rw-r--r--crypto/ossl_typ.h2
-rw-r--r--crypto/stack/safestack.h22
-rw-r--r--crypto/x509/x509.h3
-rw-r--r--crypto/x509/x509_req.c4
-rw-r--r--crypto/x509v3/v3_utl.c24
-rw-r--r--crypto/x509v3/x509v3.h1
-rw-r--r--ssl/s23_clnt.c2
-rw-r--r--ssl/s3_clnt.c90
-rw-r--r--ssl/s3_lib.c46
-rw-r--r--ssl/s3_srvr.c56
-rw-r--r--ssl/ssl.h29
-rw-r--r--ssl/ssl3.h5
-rw-r--r--ssl/ssl_err.c3
-rw-r--r--ssl/ssl_lib.c17
-rw-r--r--ssl/ssl_locl.h2
-rw-r--r--ssl/t1_enc.c2
-rw-r--r--ssl/t1_lib.c233
-rw-r--r--ssl/tls1.h35
26 files changed, 885 insertions, 56 deletions
diff --git a/CHANGES b/CHANGES
index dddc1eab43..73cf7b354a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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
diff --git a/apps/apps.h b/apps/apps.h
index c7e490a271..4b1127f5e7 100644
--- a/apps/apps.h
+++ b/apps/apps.h
@@ -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);
diff --git a/apps/ocsp.c b/apps/ocsp.c
index 219dc2f359..df0339b743 100644
--- a/apps/ocsp.c
+++ b/apps/ocsp.c
@@ -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);
+ resp = process_responder(bio_err, req, host, path,
+ port, use_ssl, req_timeout);
+ if (!resp)
+ goto end;
#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");
- 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");
- 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
diff --git a/apps/s_client.c b/apps/s_client.c
index 3474e6c6a7..3ccaca3330 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -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;
+ }
diff --git a/apps/s_server.c b/apps/s_server.c
index 3b99a620da..b3ec6091bc 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -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)
diff --git a/apps/x509.c b/apps/x509.c
index dfe41a6f1f..1fa93aaeba 100644
--- a/apps/x509.c
+++ b/apps/x509.c
@@ -114,6 +114,7 @@ static const char *x509_usage[]={
" -alias - output certificate alias\n",
" -noout - no certificate output\n",
" -ocspid - print OCSP hash values for the subject name and public key\n",
+" -ocspurl - print OCSP Responder URL(s)\n",
" -trustout - output a \"trusted\" certificate\n",
" -clrtrust - clear all trusted purposes\n",
" -clrreject - clear all rejected purposes\n",
@@ -179,6 +180,7 @@ int MAIN(int argc, char **argv)
int next_serial=0;
int subject_hash=0,issuer_hash=0,ocspid=0;
int noout=0,sign_flag=0,CA_flag=0,CA_createserial=0,email=0;
+ int ocsp_uri=0;
int trustout=0,clrtrust=0,clrreject=0,aliasout=0,clrext=0;
int C=0;
int x509req=0,days=DEF_DAYS,modulus=0,pubkey=0;
@@ -378,6 +380,8 @@ int MAIN(int argc, char **argv)
C= ++num;
else if (strcmp(*argv,"-email") == 0)
email= ++num;
+ else if (strcmp(*argv,"-ocsp_uri") == 0)
+ ocsp_uri= ++num;
else if (strcmp(*argv,"-serial") == 0)
serial= ++num;
else if (strcmp(*argv,"-next_serial") == 0)
@@ -731,11 +735,14 @@ bad:
ASN1_INTEGER_free(ser);
BIO_puts(out, "\n");
}
- else if (email == i)
+ else if ((email == i) || (ocsp_uri == i))
{
int j;
STACK *emlst;
- emlst = X509_get1_email(x);
+ if (email == i)
+ emlst = X509_get1_email(x);
+ else
+ emlst = X509_get1_ocsp(x);
for (j = 0; j < sk_num(emlst); j++)
BIO_printf(STDout, "%s\n", sk_value(emlst, j));
X509_email_free(emlst);
diff --git a/crypto/asn1/x_exten.c b/crypto/asn1/x_exten.c
index 702421b6c8..1732e66712 100644
--- a/crypto/asn1/x_exten.c
+++ b/crypto/asn1/x_exten.c
@@ -67,5 +67,10 @@ ASN1_SEQUENCE(X509_EXTENSION) = {
ASN1_SIMPLE(X509_EXTENSION, value, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(X509_EXTENSION)
+ASN1_ITEM_TEMPLATE(X509_EXTENSIONS) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Extension, X509_EXTENSION)
+ASN1_ITEM_TEMPLATE_END(X509_EXTENSIONS)
+
IMPLEMENT_ASN1_FUNCTIONS(X509_EXTENSION)
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS)
IMPLEMENT_ASN1_DUP_FUNCTION(X509_EXTENSION)
diff --git a/crypto/ocsp/ocsp.h b/crypto/ocsp/ocsp.h
index 34bb62c277..bbfc5055df 100644
--- a/crypto/ocsp/ocsp.h
+++ b/crypto/ocsp/ocsp.h
@@ -187,11 +187,11 @@ typedef struct ocsp_resp_bytes_st
* responseStatus OCSPResponseStatus,
* responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
*/
-typedef struct ocsp_response_st
+struct ocsp_response_st
{
ASN1_ENUMERATED *responseStatus;
OCSP_RESPBYTES *responseBytes;
- } OCSP_RESPONSE;
+ };
/* ResponderID ::= CHOICE {
* byName [1] Name,
@@ -199,14 +199,18 @@ typedef struct ocsp_response_st
*/
#define V_OCSP_RESPID_NAME 0
#define V_OCSP_RESPID_KEY 1
-typedef struct ocsp_responder_id_st
+struct ocsp_responder_id_st
{
int type;
union {
X509_NAME* byName;
ASN1_OCTET_STRING *byKey;
} value;
- } OCSP_RESPID;
+ };
+
+DECLARE_STACK_OF(OCSP_RESPID)
+DECLARE_ASN1_FUNCTIONS(OCSP_RESPID)
+
/* KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key
* --(excluding the tag and length fields)
*/
diff --git a/crypto/ossl_typ.h b/crypto/ossl_typ.h
index b132405098..2a66d484b9 100644
--- a/crypto/ossl_typ.h
+++ b/crypto/ossl_typ.h
@@ -188,5 +188,7 @@ typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d
int idx, long argl, void *argp);
typedef struct ocsp_req_ctx_st OCSP_REQ_CTX;
+typedef struct ocsp_response_st OCSP_RESPONSE;
+typedef struct ocsp_responder_id_st OCSP_RESPID;
#endif /* def HEADER_OPENSSL_TYPES_H */
diff --git a/crypto/stack/safestack.h b/crypto/stack/safestack.h
index 250929bf7d..f80353598f 100644
--- a/crypto/stack/safestack.h
+++ b/crypto/stack/safestack.h
@@ -1074,6 +1074,28 @@ STACK_OF(type) \
#define sk_OCSP_ONEREQ_sort(st) SKM_sk_sort(OCSP_ONEREQ, (st))
#define sk_OCSP_ONEREQ_is_sorted(st) SKM_sk_is_sorted(OCSP_ONEREQ, (st))
+#define sk_OCSP_RESPID_new(st) SKM_sk_new(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_new_null() SKM_sk_new_null(OCSP_RESPID)
+#define sk_OCSP_RESPID_free(st) SKM_sk_free(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_num(st) SKM_sk_num(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_value(st, i) SKM_sk_value(OCSP_RESPID, (st), (i))
+#define sk_OCSP_RESPID_set(st, i, val) SKM_sk_set(OCSP_RESPID, (st), (i), (val))
+#define sk_OCSP_RESPID_zero(st) SKM_sk_zero(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_push(st, val) SKM_sk_push(OCSP_RESPID, (st), (val))
+#define sk_OCSP_RESPID_unshift(st, val) SKM_sk_unshift(OCSP_RESPID, (st), (val))
+#define sk_OCSP_RESPID_find(st, val) SKM_sk_find(OCSP_RESPID, (st), (val))
+#define sk_OCSP_RESPID_find_ex(st, val) SKM_sk_find_ex(OCSP_RESPID, (st), (val))
+#define sk_OCSP_RESPID_delete(st, i) SKM_sk_delete(OCSP_RESPID, (st), (i))
+#define sk_OCSP_RESPID_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_RESPID, (st), (ptr))
+#define sk_OCSP_RESPID_insert(st, val, i) SKM_sk_insert(OCSP_RESPID, (st), (val), (i))
+#define sk_OCSP_RESPID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_RESPID, (st), (cmp))
+#define sk_OCSP_RESPID_dup(st) SKM_sk_dup(OCSP_RESPID, st)
+#define sk_OCSP_RESPID_pop_free(st, free_func) SKM_sk_pop_free(OCSP_RESPID, (st), (free_func))
+#define sk_OCSP_RESPID_shift(st) SKM_sk_shift(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_pop(st) SKM_sk_pop(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_sort(st) SKM_sk_sort(OCSP_RESPID, (st))
+#define sk_OCSP_RESPID_is_sorted(st) SKM_sk_is_sorted(OCSP_RESPID, (st))
+
#define sk_OCSP_SINGLERESP_new(st) SKM_sk_new(OCSP_SINGLERESP, (st))
#define sk_OCSP_SINGLERESP_new_null() SKM_sk_new_null(OCSP_SINGLERESP)
#define sk_OCSP_SINGLERESP_free(st) SKM_sk_free(OCSP_SINGLERESP, (st))
diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h
index 914fb04b1d..4f40712448 100644
--- a/crypto/x509/x509.h
+++ b/crypto/x509/x509.h
@@ -205,6 +205,8 @@ typedef struct X509_extension_st
ASN1_OCTET_STRING *value;
} X509_EXTENSION;
+typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
+
DECLARE_STACK_OF(X509_EXTENSION)
DECLARE_ASN1_SET_OF(X509_EXTENSION)
@@ -801,6 +803,7 @@ DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE)
X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value);
DECLARE_ASN1_FUNCTIONS(X509_EXTENSION)
+DECLARE_ASN1_ENCODE_FUNCTIONS(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS)
DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY)
diff --git a/crypto/x509/x509_req.c b/crypto/x509/x509_req.c
index a2d78a8a12..48183dc00c 100644
--- a/crypto/x509/x509_req.c
+++ b/crypto/x509/x509_req.c
@@ -67,10 +67,6 @@
#include <openssl/buffer.h>
#include <openssl/pem.h>
-ASN1_ITEM_TEMPLATE(X509_EXTENSIONS) =
- ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Extension, X509_EXTENSION)
-ASN1_ITEM_TEMPLATE_END(X509_EXTENSIONS)
-
X509_REQ *X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md)
{
X509_REQ *ret;
diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c
index f1b5c94c2a..6aa54aedfa 100644
--- a/crypto/x509v3/v3_utl.c
+++ b/crypto/x509v3/v3_utl.c
@@ -473,6 +473,30 @@ STACK *X509_get1_email(X509 *x)
return ret;
}
+STACK *X509_get1_ocsp(X509 *x)
+{
+ AUTHORITY_INFO_ACCESS *info;
+ STACK *ret = NULL;
+ int i;
+ info = X509_get_ext_d2i(x, NID_info_access, NULL, NULL);
+ if (!info)
+ return NULL;
+ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++)
+ {
+ ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i);
+ if (OBJ_obj2nid(ad->method) == NID_ad_OCSP)
+ {
+ if (ad->location->type == GEN_URI)
+ {
+ if (!append_ia5(&ret, ad->location->d.uniformResourceIdentifier))
+ break;
+ }
+ }
+ }
+ AUTHORITY_INFO_ACCESS_free(info);
+ return ret;
+}
+
STACK *X509_REQ_get1_email(X509_REQ *x)
{
GENERAL_NAMES *gens;
diff --git a/crypto/x509v3/x509v3.h b/crypto/x509v3/x509v3.h
index cbadc4c185..be0c97a404 100644
--- a/crypto/x509v3/x509v3.h
+++ b/crypto/x509v3/x509v3.h
@@ -649,6 +649,7 @@ int X509_PURPOSE_get_id(X509_PURPOSE *);
STACK *X509_get1_email(X509 *x);
STACK *X509_REQ_get1_email(X509_REQ *x);
void X509_email_free(STACK *sk);
+STACK *X509_get1_ocsp(X509 *x);
ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc);
ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc);
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c
index c500a932a7..78c39d9af5 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -283,6 +283,8 @@ static int ssl23_client_hello(SSL *s)
if (s->tlsext_hostname != NULL)
ssl2_compat = 0;
+ if (s->tlsext_status_type != -1)
+ ssl2_compat = 0;
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL)
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index f8f43eb938..b7d8d4213b 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -307,10 +307,23 @@ int ssl3_connect(SSL *s)
{
ret=ssl3_get_server_certificate(s);
if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_status_expected)
+ s->state=SSL3_ST_CR_CERT_STATUS_A;
+ else
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+ }
+ else
+ {
+ skip = 1;
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
}
+#else
else
skip=1;
+
s->state=SSL3_ST_CR_KEY_EXCH_A;
+#endif
s->init_num=0;
break;
@@ -473,6 +486,14 @@ int ssl3_connect(SSL *s)
s->state=SSL3_ST_CR_FINISHED_A;
s->init_num=0;
break;
+
+ case SSL3_ST_CR_CERT_STATUS_A:
+ case SSL3_ST_CR_CERT_STATUS_B:
+ ret=ssl3_get_cert_status(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+ s->init_num=0;
+ break;
#endif
case SSL3_ST_CR_FINISHED_A:
@@ -1795,6 +1816,75 @@ f_err:
err:
return(-1);
}
+
+int ssl3_get_cert_status(SSL *s)
+ {
+ int ok, al;
+ unsigned long resplen;
+ long n;
+ const unsigned char *p;
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_CERT_STATUS_A,
+ SSL3_ST_CR_CERT_STATUS_B,
+ SSL3_MT_CERTIFICATE_STATUS,
+ 16384,
+ &ok);
+
+ if (!ok) return((int)n);
+ if (n < 4)
+ {
+ /* need at least status type + length */
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ p = (unsigned char *)s->init_msg;
+ if (*p++ != TLSEXT_STATUSTYPE_ocsp)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_UNSUPPORTED_STATUS_TYPE);
+ goto f_err;
+ }
+ n2l3(p, resplen);
+ if (resplen + 4 != n)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ if (s->tlsext_ocsp_resp)
+ OPENSSL_free(s->tlsext_ocsp_resp);
+ s->tlsext_ocsp_resp = BUF_memdup(p, resplen);
+ if (!s->tlsext_ocsp_resp)
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+ s->tlsext_ocsp_resplen = resplen;
+ if (s->ctx->tlsext_status_cb)
+ {
+ int ret;
+ ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ if (ret == 0)
+ {
+ al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_INVALID_STATUS_RESPONSE);
+ goto f_err;
+ }
+ if (ret < 0)
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+ }
+ return 1;
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return(-1);
+ }
#endif
int ssl3_get_server_done(SSL *s)
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 548eeef6f3..9910a132e8 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -2383,6 +2383,43 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
break;
#endif
+ case SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE:
+ s->tlsext_status_type=larg;
+ ret = 1;
+ break;
+
+ case SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS:
+ *(STACK_OF(X509_EXTENSION) **)parg = s->tlsext_ocsp_exts;
+ ret = 1;
+ break;
+
+ case SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS:
+ s->tlsext_ocsp_exts = parg;
+ ret = 1;
+ break;
+
+ case SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS:
+ *(STACK_OF(OCSP_RESPID) **)parg = s->tlsext_ocsp_ids;
+ ret = 1;
+ break;
+
+ case SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS:
+ s->tlsext_ocsp_ids = parg;
+ ret = 1;
+ break;
+
+ case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP:
+ *(unsigned char **)parg = s->tlsext_ocsp_resp;
+ return s->tlsext_ocsp_resplen;
+
+ case SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP:
+ if (s->tlsext_ocsp_resp)
+ OPENSSL_free(s->tlsext_ocsp_resp);
+ s->tlsext_ocsp_resp = parg;
+ s->tlsext_ocsp_resplen = larg;
+ ret = 1;
+ break;
+
#endif /* !OPENSSL_NO_TLSEXT */
default:
break;
@@ -2610,6 +2647,11 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
return 1;
#endif
+ case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG:
+ ctx->tlsext_status_arg=parg;
+ return 1;
+ break;
+
#endif /* !OPENSSL_NO_TLSEXT */
/* A Thawte special :-) */
@@ -2668,6 +2710,10 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
break;
#endif
+ case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB:
+ ctx->tlsext_status_cb=(int (*)(SSL *,void *))fp;
+ break;
+
#endif
default:
return(0);
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 697ab725bd..cc01cb109f 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -332,10 +332,23 @@ int ssl3_accept(SSL *s)
{
ret=ssl3_send_server_certificate(s);
if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_status_expected)
+ s->state=SSL3_ST_SW_CERT_STATUS_A;
+ else
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
}
else
+ {
+ skip = 1;
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ }
+#else
+ else
skip=1;
+
s->state=SSL3_ST_SW_KEY_EXCH_A;
+#endif
s->init_num=0;
break;
@@ -551,6 +564,14 @@ int ssl3_accept(SSL *s)
s->init_num=0;
break;
+ case SSL3_ST_SW_CERT_STATUS_A:
+ case SSL3_ST_SW_CERT_STATUS_B:
+ ret=ssl3_send_cert_status(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ s->init_num=0;
+ break;
+
#endif
case SSL3_ST_SW_CHANGE_A:
@@ -2823,4 +2844,39 @@ int ssl3_send_newsession_ticket(SSL *s)
/* SSL3_ST_SW_SESSION_TICKET_B */
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
}
+
+int ssl3_send_cert_status(SSL *s)
+ {
+ if (s->state == SSL3_ST_SW_CERT_STATUS_A)
+ {
+ unsigned char *p;
+ /* Grow buffer if need be: the length calculation is as
+ * follows 1 (message type) + 3 (message length) +
+ * 1 (ocsp response type) + 3 (ocsp response length)
+ * + (ocsp response)
+ */
+ if (!BUF_MEM_grow(s->init_buf, 8 + s->tlsext_ocsp_resplen))
+ return -1;
+
+ p=(unsigned char *)s->init_buf->data;
+
+ /* do the header */
+ *(p++)=SSL3_MT_CERTIFICATE_STATUS;
+ /* message length */
+ l2n3(s->tlsext_ocsp_resplen + 4, p);
+ /* status type */
+ *(p++)= s->tlsext_status_type;
+ /* length of OCSP response */
+ l2n3(s->tlsext_ocsp_resplen, p);
+ /* actual response */
+ memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen);
+ /* number of bytes to write */
+ s->init_num = 8 + s->tlsext_ocsp_resplen;
+ s->state=SSL3_ST_SW_CERT_STATUS_B;
+ s->init_off = 0;
+ }
+
+ /* SSL3_ST_SW_CERT_STATUS_B */
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ }
#endif
diff --git a/ssl/ssl.h b/ssl/ssl.h
index ec42280a9c..32f572ce46 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -800,6 +800,11 @@ struct ssl_ctx_st
unsigned char tlsext_tick_hmac_key[16];
unsigned char tlsext_tick_aes_key[16];
+ /* certificate status request info */
+ /* Callback for status request */
+ int (*tlsext_status_cb)(SSL *ssl, void *arg);
+ void *tlsext_status_arg;
+
/* draft-rescorla-tls-opaque-prf-input-00.txt information */
int (*tlsext_opaque_prf_input_callback)(SSL *, void *peerinput, size_t len, void *arg);
void *tlsext_opaque_prf_input_callback_arg;
@@ -1083,6 +1088,18 @@ struct ssl_st
1 : prepare 2, allow last ack just after in server callback.
2 : don't call servername callback, no ack in server hello
*/
+ /* certificate status request info */
+ /* Status type or -1 if no status type */
+ int tlsext_status_type;
+ /* Expect OCSP CertificateStatus message */
+ int tlsext_status_expected;
+ /* OCSP status request only */
+ STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids;
+ X509_EXTENSIONS *tlsext_ocsp_exts;
+ /* OCSP response received or to be sent */
+ unsigned char *tlsext_ocsp_resp;
+ int tlsext_ocsp_resplen;
+
/* RFC4507 session ticket expected to be received or sent */
int tlsext_ticket_expected;
#ifndef OPENSSL_NO_EC
@@ -1317,6 +1334,15 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT 60
#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB 61
#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB 63
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG 64
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE 65
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS 66
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS 67
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS 68
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS 69
+#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP 70
+#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP 71
#endif
#define SSL_session_reused(ssl) \
@@ -1766,6 +1792,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_SSL3_ENC 134
#define SSL_F_SSL3_GENERATE_KEY_BLOCK 238
#define SSL_F_SSL3_GET_CERTIFICATE_REQUEST 135
+#define SSL_F_SSL3_GET_CERT_STATUS 288
#define SSL_F_SSL3_GET_CERT_VERIFY 136
#define SSL_F_SSL3_GET_CLIENT_CERTIFICATE 137
#define SSL_F_SSL3_GET_CLIENT_HELLO 138
@@ -1964,6 +1991,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_INVALID_CHALLENGE_LENGTH 158
#define SSL_R_INVALID_COMMAND 280
#define SSL_R_INVALID_PURPOSE 278
+#define SSL_R_INVALID_STATUS_RESPONSE 328
#define SSL_R_INVALID_TICKET_KEYS_LENGTH 325
#define SSL_R_INVALID_TRUST 279
#define SSL_R_KEY_ARG_TOO_LONG 284
@@ -2132,6 +2160,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 315
#define SSL_R_UNSUPPORTED_PROTOCOL 258
#define SSL_R_UNSUPPORTED_SSL_VERSION 259
+#define SSL_R_UNSUPPORTED_STATUS_TYPE 329
#define SSL_R_WRITE_BIO_NOT_SET 260
#define SSL_R_WRONG_CIPHER_RETURNED 261
#define SSL_R_WRONG_MESSAGE_TYPE 262
diff --git a/ssl/ssl3.h b/ssl/ssl3.h
index e04226f46f..646a8e6cce 100644
--- a/ssl/ssl3.h
+++ b/ssl/ssl3.h
@@ -545,6 +545,8 @@ typedef struct ssl3_state_st
#define SSL3_ST_CR_FINISHED_B (0x1D1|SSL_ST_CONNECT)
#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0|SSL_ST_CONNECT)
#define SSL3_ST_CR_SESSION_TICKET_B (0x1E1|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_STATUS_A (0x1F0|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_STATUS_B (0x1F1|SSL_ST_CONNECT)
/* server */
/* extra state */
@@ -588,6 +590,8 @@ typedef struct ssl3_state_st
#define SSL3_ST_SW_FINISHED_B (0x1E1|SSL_ST_ACCEPT)
#define SSL3_ST_SW_SESSION_TICKET_A (0x1F0|SSL_ST_ACCEPT)
#define SSL3_ST_SW_SESSION_TICKET_B (0x1F1|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_STATUS_A (0x200|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_STATUS_B (0x201|SSL_ST_ACCEPT)
#define SSL3_MT_HELLO_REQUEST 0
#define SSL3_MT_CLIENT_HELLO 1
@@ -600,6 +604,7 @@ typedef struct ssl3_state_st
#define SSL3_MT_CERTIFICATE_VERIFY 15
#define SSL3_MT_CLIENT_KEY_EXCHANGE 16
#define SSL3_MT_FINISHED 20
+#define SSL3_MT_CERTIFICATE_STATUS 22
#define DTLS1_MT_HELLO_VERIFY_REQUEST 3
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 3121e0e70c..d9c0e35681 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -140,6 +140,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_SSL3_ENC), "SSL3_ENC"},
{ERR_FUNC(SSL_F_SSL3_GENERATE_KEY_BLOCK), "SSL3_GENERATE_KEY_BLOCK"},
{ERR_FUNC(SSL_F_SSL3_GET_CERTIFICATE_REQUEST), "SSL3_GET_CERTIFICATE_REQUEST"},
+{ERR_FUNC(SSL_F_SSL3_GET_CERT_STATUS), "SSL3_GET_CERT_STATUS"},
{ERR_FUNC(SSL_F_SSL3_GET_CERT_VERIFY), "SSL3_GET_CERT_VERIFY"},
{ERR_FUNC(SSL_F_SSL3_GET_CLIENT_CERTIFICATE), "SSL3_GET_CLIENT_CERTIFICATE"},
{ERR_FUNC(SSL_F_SSL3_GET_CLIENT_HELLO), "SSL3_GET_CLIENT_HELLO"},
@@ -341,6 +342,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
{ERR_REASON(SSL_R_INVALID_CHALLENGE_LENGTH),"invalid challenge length"},
{ERR_REASON(SSL_R_INVALID_COMMAND) ,"invalid command"},
{ERR_REASON(SSL_R_INVALID_PURPOSE) ,"invalid purpose"},
+{ERR_REASON(SSL_R_INVALID_STATUS_RESPONSE),"invalid status response"},
{ERR_REASON(SSL_R_INVALID_TICKET_KEYS_LENGTH),"invalid ticket keys length"},
{ERR_REASON(SSL_R_INVALID_TRUST) ,"invalid trust"},
{ERR_REASON(SSL_R_KEY_ARG_TOO_LONG) ,"key arg too long"},
@@ -509,6 +511,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
{ERR_REASON(SSL_R_UNSUPPORTED_ELLIPTIC_CURVE),"unsupported elliptic curve"},
{ERR_REASON(SSL_R_UNSUPPORTED_PROTOCOL) ,"unsupported protocol"},
{ERR_REASON(SSL_R_UNSUPPORTED_SSL_VERSION),"unsupported ssl version"},
+{ERR_REASON(SSL_R_UNSUPPORTED_STATUS_TYPE),"unsupported status type"},
{ERR_REASON(SSL_R_WRITE_BIO_NOT_SET) ,"write bio not set"},
{ERR_REASON(SSL_R_WRONG_CIPHER_RETURNED) ,"wrong cipher returned"},
{ERR_REASON(SSL_R_WRONG_MESSAGE_TYPE) ,"wrong message type"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 00a93eeee9..c5d9f0e93e 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -152,6 +152,7 @@
#include <openssl/lhash.h>
#include <openssl/x509v3.h>
#include <openssl/rand.h>
+#include <openssl/ocsp.h>
#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
#endif
@@ -340,6 +341,12 @@ SSL *SSL_new(SSL_CTX *ctx)
s->tlsext_debug_cb = 0;
s->tlsext_debug_arg = NULL;
s->tlsext_ticket_expected = 0;
+ s->tlsext_status_type = -1;
+ s->tlsext_status_expected = 0;
+ s->tlsext_ocsp_ids = NULL;
+ s->tlsext_ocsp_exts = NULL;
+ s->tlsext_ocsp_resp = NULL;
+ s->tlsext_ocsp_resplen = -1;
CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
s->initial_ctx=ctx;
#endif
@@ -543,6 +550,13 @@ void SSL_free(SSL *s)
if (s->tlsext_ellipticcurvelist) OPENSSL_free(s->tlsext_ellipticcurvelist);
#endif /* OPENSSL_NO_EC */
if (s->tlsext_opaque_prf_input) OPENSSL_free(s->tlsext_opaque_prf_input);
+ if (s->tlsext_ocsp_exts)
+ sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
+ X509_EXTENSION_free);
+ if (s->tlsext_ocsp_ids)
+ sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
+ if (s->tlsext_ocsp_resp)
+ OPENSSL_free(s->tlsext_ocsp_resp);
#endif
if (s->client_CA != NULL)
@@ -1556,6 +1570,9 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
|| (RAND_bytes(ret->tlsext_tick_aes_key, 16) <= 0))
ret->options |= SSL_OP_NO_TICKET;
+ ret->tlsext_status_cb = 0;
+ ret->tlsext_status_arg = NULL;
+
#endif
#ifndef OPENSSL_NO_PSK
ret->psk_identity_hint=NULL;
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 50a8acc015..cb93ff2188 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -829,6 +829,7 @@ int ssl3_put_cipher_by_char(const SSL_CIPHER *c,unsigned char *p);
void ssl3_init_finished_mac(SSL *s);
int ssl3_send_server_certificate(SSL *s);
int ssl3_send_newsession_ticket(SSL *s);
+int ssl3_send_cert_status(SSL *s);
int ssl3_get_finished(SSL *s,int state_a,int state_b);
int ssl3_setup_key_block(SSL *s);
int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b);
@@ -921,6 +922,7 @@ int ssl3_client_hello(SSL *s);
int ssl3_get_server_hello(SSL *s);
int ssl3_get_certificate_request(SSL *s);
int ssl3_get_new_session_ticket(SSL *s);
+int ssl3_get_cert_status(SSL *s);
int ssl3_get_server_done(SSL *s);
int ssl3_send_client_verify(SSL *s);
int ssl3_send_client_certificate(SSL *s);
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 3509f62b18..4aa7600fe7 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -899,7 +899,7 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
{
unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH];
const void *co = NULL, *so = NULL;
- int col = 0, sol = NULL;
+ int col = 0, sol = 0;
#ifdef KSSL_DEBUG
printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 1aaf8905c8..476e4240e5 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -113,6 +113,7 @@
#include <openssl/objects.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#include <openssl/ocsp.h>
#include "ssl_locl.h"
const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
@@ -387,6 +388,54 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
}
#endif
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+ {
+ int i;
+ long extlen, idlen, itmp;
+ OCSP_RESPID *id;
+
+ idlen = 0;
+ for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
+ {
+ id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+ itmp = i2d_OCSP_RESPID(id, NULL);
+ if (itmp <= 0)
+ return NULL;
+ idlen += itmp + 2;
+ }
+
+ if (s->tlsext_ocsp_exts)
+ {
+ extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
+ if (extlen < 0)
+ return NULL;
+ }
+ else
+ extlen = 0;
+
+ if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL;
+ s2n(TLSEXT_TYPE_status_request, ret);
+ if (extlen + idlen > 0xFFF0)
+ return NULL;
+ s2n(extlen + idlen + 5, ret);
+ *(ret++) = TLSEXT_STATUSTYPE_ocsp;
+ s2n(idlen, ret);
+ for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
+ {
+ /* save position of id len */
+ unsigned char *q = ret;
+ id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+ /* skip over id len */
+ ret += 2;
+ itmp = i2d_OCSP_RESPID(id, &ret);
+ /* write id len */
+ s2n(itmp, q);
+ }
+ s2n(extlen, ret);
+ if (extlen > 0)
+ i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
+ }
+
if ((extdatalen = ret-p-2)== 0)
return p;
@@ -432,7 +481,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
}
/* Currently the server should not respond with a SupportedCurves extension */
#endif /* OPENSSL_NO_EC */
-
+
if (s->tlsext_ticket_expected
&& !(SSL_get_options(s) & SSL_OP_NO_TICKET))
{
@@ -441,6 +490,13 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
s2n(0,ret);
}
+ if (s->tlsext_status_expected)
+ {
+ if ((long)(limit - ret - 4) < 0) return NULL;
+ s2n(TLSEXT_TYPE_status_request,ret);
+ s2n(0,ret);
+ }
+
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->s3->server_opaque_prf_input != NULL)
{
@@ -473,6 +529,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
unsigned short len;
unsigned char *data = *p;
s->servername_done = 0;
+ s->tlsext_status_type = -1;
if (data >= (d+n-2))
return 1;
@@ -675,6 +732,106 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
}
}
#endif
+ else if (type == TLSEXT_TYPE_status_request
+ && s->ctx->tlsext_status_cb)
+ {
+
+ if (size < 5)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ s->tlsext_status_type = *data++;
+ size--;
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+ {
+ const unsigned char *sdata;
+ int dsize;
+ /* Read in responder_id_list */
+ n2s(data,dsize);
+ size -= 2;
+ if (dsize > size )
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ while (dsize > 0)
+ {
+ OCSP_RESPID *id;
+ int idsize;
+ if (dsize < 4)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(data, idsize);
+ dsize -= 2 + idsize;
+ if (dsize < 0)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ sdata = data;
+ data += idsize;
+ id = d2i_OCSP_RESPID(NULL,
+ &sdata, idsize);
+ if (!id)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (data != sdata)
+ {
+ OCSP_RESPID_free(id);
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!s->tlsext_ocsp_ids
+ && !(s->tlsext_ocsp_ids =
+ sk_OCSP_RESPID_new_null()))
+ {
+ OCSP_RESPID_free(id);
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ if (!sk_OCSP_RESPID_push(
+ s->tlsext_ocsp_ids, id))
+ {
+ OCSP_RESPID_free(id);
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+
+ /* Read in request_extensions */
+ n2s(data,dsize);
+ size -= 2;
+ if (dsize > size)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ sdata = data;
+ if (dsize > 0)
+ {
+ s->tlsext_ocsp_exts =
+ d2i_X509_EXTENSIONS(NULL,
+ &sdata, dsize);
+ if (!s->tlsext_ocsp_exts
+ || (data + dsize != sdata))
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+ }
+ /* We don't know what to do with any other type
+ * so ignore it.
+ */
+ else
+ s->tlsext_status_type = -1;
+ }
/* session ticket processed earlier */
data+=size;
@@ -791,6 +948,19 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
}
}
#endif
+ else if (type == TLSEXT_TYPE_status_request)
+ {
+ /* MUST be empty and only sent if we've requested
+ * a status request message.
+ */
+ if ((s->tlsext_status_type == -1) || (size > 0))
+ {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+ /* Set flag to expect CertificateStatus message */
+ s->tlsext_status_expected = 1;
+ }
data+=size;
}
@@ -822,6 +992,35 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
}
}
+ /* If we've requested certificate status and we wont get one
+ * tell the callback
+ */
+ if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
+ && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ /* Set resp to NULL, resplen to -1 so callback knows
+ * there is no response.
+ */
+ if (s->tlsext_ocsp_resp)
+ {
+ OPENSSL_free(s->tlsext_ocsp_resp);
+ s->tlsext_ocsp_resp = NULL;
+ }
+ s->tlsext_ocsp_resplen = -1;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ if (r == 0)
+ {
+ *al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+ return 0;
+ }
+ if (r < 0)
+ {
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+
*p = data;
return 1;
}
@@ -966,6 +1165,36 @@ int ssl_check_clienthello_tlsext(SSL *s)
else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+ /* If status request then ask callback what to do.
+ * Note: this must be called after servername callbacks in case
+ * the certificate has changed.
+ */
+ if ((s->tlsext_status_type != -1) && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ switch (r)
+ {
+ /* We don't want to send a status request response */
+ case SSL_TLSEXT_ERR_NOACK:
+ s->tlsext_status_expected = 0;
+ break;
+ /* status request response should be sent */
+ case SSL_TLSEXT_ERR_OK:
+ if (s->tlsext_ocsp_resp)
+ s->tlsext_status_expected = 1;
+ else
+ s->tlsext_status_expected = 0;
+ break;
+ /* something bad happened */
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ }
+ else
+ s->tlsext_status_expected = 0;
#ifdef TLSEXT_TYPE_opaque_prf_input
{
@@ -1022,8 +1251,8 @@ int ssl_check_clienthello_tlsext(SSL *s)
al = SSL_AD_HANDSHAKE_FAILURE;
}
}
-#endif
+#endif
err:
switch (ret)
{
diff --git a/ssl/tls1.h b/ssl/tls1.h
index cac8d0ea22..d831eecd87 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -203,6 +203,8 @@ extern "C" {
/* NameType value from RFC 3546 */
#define TLSEXT_NAMETYPE_host_name 0
+/* status request value from RFC 3546 */
+#define TLSEXT_STATUSTYPE_ocsp 1
/* ECPointFormat values from draft-ietf-tls-ecc-12 */
#define TLSEXT_ECPOINTFORMAT_first 0
@@ -227,12 +229,33 @@ SSL_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_CB,(void (*)(void))cb)
#define SSL_set_tlsext_debug_arg(ssl, arg) \
SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg)
+#define SSL_set_tlsext_status_type(ssl, type) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE,type, NULL)
+
+#define SSL_get_tlsext_status_exts(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg)
+
+#define SSL_set_tlsext_status_exts(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg)
+
+#define SSL_get_tlsext_status_ids(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg)
+
+#define SSL_set_tlsext_status_ids(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg)
+
+#define SSL_get_tlsext_status_ocsp_resp(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP,0, (void *)arg)
+
+#define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen, (void *)arg)
+
#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb)
-#define SSL_TLSEXT_ERR_OK 0
-#define SSL_TLSEXT_ERR_ALERT_WARNING 1
-#define SSL_TLSEXT_ERR_ALERT_FATAL 2
+#define SSL_TLSEXT_ERR_OK 0
+#define SSL_TLSEXT_ERR_ALERT_WARNING 1
+#define SSL_TLSEXT_ERR_ALERT_FATAL 2
#define SSL_TLSEXT_ERR_NOACK 3
#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
@@ -243,6 +266,12 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
#define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \
SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLXEXT_TICKET_KEYS,(keylen),(keys))
+#define SSL_CTX_set_tlsext_status_cb(ssl, cb) \
+SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB,(void (*)(void))cb)
+
+#define SSL_CTX_set_tlsext_status_arg(ssl, arg) \
+SSL_CTX_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG,0, (void *)arg)
+
#define SSL_set_tlsext_opaque_prf_input(s, src, len) \
SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT, len, src)
#define SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb) \