Backport certificate status request TLS extension support to 0.9.8.

This commit is contained in:
Dr. Stephen Henson 2007-10-12 00:00:36 +00:00
parent 074471ab0c
commit a523276786
27 changed files with 1410 additions and 149 deletions

View File

@ -4,7 +4,12 @@
Changes between 0.9.8f and 0.9.8g [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]
Changes between 0.9.8e and 0.9.8f [11 Oct 2007]

View File

@ -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);
@ -228,6 +231,12 @@ extern BIO *bio_err;
# endif
#endif
#ifdef OPENSSL_SYSNAME_WIN32
# define openssl_fdset(a,b) FD_SET((unsigned int)a, b)
#else
# define openssl_fdset(a,b) FD_SET(a, b)
#endif
typedef struct args_st
{
char **data;
@ -275,6 +284,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);

View File

@ -58,13 +58,14 @@
#ifndef OPENSSL_NO_OCSP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "apps.h"
#include <openssl/pem.h>
#include <openssl/e_os2.h>
#include <openssl/bio.h>
#include <openssl/ocsp.h>
#include <openssl/err.h>
#include <openssl/txt_db.h>
#include <openssl/ssl.h>
#include <openssl/bn.h>
#include "apps.h"
/* Maximum leeway in validity period: default 5 minutes */
#define MAX_VALIDITY_PERIOD (5 * 60)
@ -86,6 +87,8 @@ static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser);
static BIO *init_responder(char *port);
static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, char *port);
static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp);
static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
OCSP_REQUEST *req, int req_timeout);
#undef PROG
#define PROG ocsp_main
@ -112,11 +115,11 @@ int MAIN(int argc, char **argv)
BIO *acbio = NULL, *cbio = NULL;
BIO *derbio = NULL;
BIO *out = NULL;
int req_timeout = -1;
int req_text = 0, resp_text = 0;
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;
@ -154,6 +157,22 @@ int MAIN(int argc, char **argv)
}
else badarg = 1;
}
else if (!strcmp(*args, "-timeout"))
{
if (args[1])
{
args++;
req_timeout = atol(*args);
if (req_timeout < 0)
{
BIO_printf(bio_err,
"Illegal timeout value %s\n",
*args);
badarg = 1;
}
}
else badarg = 1;
}
else if (!strcmp(*args, "-url"))
{
if (args[1])
@ -703,52 +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);
}
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_all(cbio);
cbio = NULL;
if (!resp)
{
BIO_printf(bio_err, "Error querying OCSP responsder\n");
goto end;
}
}
else if (respin)
{
@ -897,7 +878,6 @@ end:
OPENSSL_free(host);
OPENSSL_free(port);
OPENSSL_free(path);
SSL_CTX_free(ctx);
}
OPENSSL_EXIT(ret);
@ -1121,6 +1101,7 @@ static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser)
char *itmp, *row[DB_NUMBER],**rrow;
for (i = 0; i < DB_NUMBER; i++) row[i] = NULL;
bn = ASN1_INTEGER_to_BN(ser,NULL);
OPENSSL_assert(bn); /* FIXME: should report an error at this point and abort */
if (BN_is_zero(bn))
itmp = BUF_strdup("00");
else
@ -1231,4 +1212,137 @@ static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp)
return 1;
}
static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
OCSP_REQUEST *req, int req_timeout)
{
int fd;
int rv;
OCSP_REQ_CTX *ctx = NULL;
OCSP_RESPONSE *rsp = NULL;
fd_set confds;
struct timeval tv;
if (req_timeout != -1)
BIO_set_nbio(cbio, 1);
rv = BIO_do_connect(cbio);
if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio)))
{
BIO_puts(err, "Error connecting BIO\n");
return NULL;
}
if (req_timeout == -1)
return OCSP_sendreq_bio(cbio, path, req);
if (BIO_get_fd(cbio, &fd) <= 0)
{
BIO_puts(err, "Can't get connection fd\n");
goto err;
}
if (rv <= 0)
{
FD_ZERO(&confds);
openssl_fdset(fd, &confds);
tv.tv_usec = 0;
tv.tv_sec = req_timeout;
rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
if (rv == 0)
{
BIO_puts(err, "Timeout on connect\n");
return NULL;
}
}
ctx = OCSP_sendreq_new(cbio, path, req, -1);
if (!ctx)
return NULL;
for (;;)
{
rv = OCSP_sendreq_nbio(&rsp, ctx);
if (rv != -1)
break;
FD_ZERO(&confds);
openssl_fdset(fd, &confds);
tv.tv_usec = 0;
tv.tv_sec = req_timeout;
if (BIO_should_read(cbio))
rv = select(fd + 1, (void *)&confds, NULL, NULL, &tv);
else if (BIO_should_write(cbio))
rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
else
{
BIO_puts(err, "Unexpected retry condition\n");
goto err;
}
if (rv == 0)
{
BIO_puts(err, "Timeout on request\n");
break;
}
if (rv == -1)
{
BIO_puts(err, "Select error\n");
break;
}
}
err:
if (ctx)
OCSP_REQ_CTX_free(ctx);
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

View File

@ -134,6 +134,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"
@ -173,12 +174,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;
@ -239,6 +242,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
}
@ -435,6 +439,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)
@ -826,6 +832,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);
@ -1430,3 +1453,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;
}

View File

@ -153,6 +153,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
@ -269,6 +270,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;
@ -585,6 +588,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 **);
@ -792,6 +941,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; }
@ -1430,6 +1606,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)

View File

@ -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);

View File

@ -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)

View File

@ -186,11 +186,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,
@ -198,14 +198,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)
*/
@ -397,6 +401,10 @@ typedef struct ocsp_service_locator_st
(char *(*)())d2i_OCSP_CERTSTATUS,(char *)(cs))
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req);
OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, char *path, OCSP_REQUEST *req,
int maxline);
int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx);
void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx);
OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer);
@ -574,6 +582,7 @@ void ERR_load_OCSP_strings(void);
#define OCSP_F_OCSP_REQUEST_VERIFY 116
#define OCSP_F_OCSP_RESPONSE_GET1_BASIC 111
#define OCSP_F_OCSP_SENDREQ_BIO 112
#define OCSP_F_PARSE_HTTP_LINE1 117
#define OCSP_F_REQUEST_VERIFY 113
/* Reason codes. */

View File

@ -1,6 +1,6 @@
/* crypto/ocsp/ocsp_err.c */
/* ====================================================================
* Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved.
* Copyright (c) 1999-2007 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
@ -86,6 +86,7 @@ static ERR_STRING_DATA OCSP_str_functs[]=
{ERR_FUNC(OCSP_F_OCSP_REQUEST_VERIFY), "OCSP_request_verify"},
{ERR_FUNC(OCSP_F_OCSP_RESPONSE_GET1_BASIC), "OCSP_response_get1_basic"},
{ERR_FUNC(OCSP_F_OCSP_SENDREQ_BIO), "OCSP_sendreq_bio"},
{ERR_FUNC(OCSP_F_PARSE_HTTP_LINE1), "PARSE_HTTP_LINE1"},
{ERR_FUNC(OCSP_F_REQUEST_VERIFY), "REQUEST_VERIFY"},
{0,NULL}
};

View File

@ -1,9 +1,9 @@
/* ocsp_ht.c */
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
* project 2000.
* project 2006.
*/
/* ====================================================================
* Copyright (c) 2000 The OpenSSL Project. All rights reserved.
* Copyright (c) 2006 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
@ -68,106 +68,404 @@
#define strtoul (unsigned long)strtol
#endif /* OPENSSL_SYS_SUNOS */
/* Quick and dirty HTTP OCSP request handler.
* Could make this a bit cleverer by adding
* support for non blocking BIOs and a few
* other refinements.
/* Stateful OCSP request code, supporting non-blocking I/O */
/* Opaque OCSP request status structure */
struct ocsp_req_ctx_st {
int state; /* Current I/O state */
unsigned char *iobuf; /* Line buffer */
int iobuflen; /* Line buffer length */
BIO *io; /* BIO to perform I/O with */
BIO *mem; /* Memory BIO response is built into */
unsigned long asn1_len; /* ASN1 length of response */
};
#define OCSP_MAX_REQUEST_LENGTH (100 * 1024)
#define OCSP_MAX_LINE_LEN 4096;
/* OCSP states */
/* If set no reading should be performed */
#define OHS_NOREAD 0x1000
/* Error condition */
#define OHS_ERROR (0 | OHS_NOREAD)
/* First line being read */
#define OHS_FIRSTLINE 1
/* MIME headers being read */
#define OHS_HEADERS 2
/* OCSP initial header (tag + length) being read */
#define OHS_ASN1_HEADER 3
/* OCSP content octets being read */
#define OHS_ASN1_CONTENT 4
/* Request being sent */
#define OHS_ASN1_WRITE (6 | OHS_NOREAD)
/* Request being flushed */
#define OHS_ASN1_FLUSH (7 | OHS_NOREAD)
/* Completed */
#define OHS_DONE (8 | OHS_NOREAD)
static int parse_http_line1(char *line);
void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx)
{
if (rctx->mem)
BIO_free(rctx->mem);
if (rctx->iobuf)
OPENSSL_free(rctx->iobuf);
OPENSSL_free(rctx);
}
OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, char *path, OCSP_REQUEST *req,
int maxline)
{
static char post_hdr[] = "POST %s HTTP/1.0\r\n"
"Content-Type: application/ocsp-request\r\n"
"Content-Length: %d\r\n\r\n";
OCSP_REQ_CTX *rctx;
rctx = OPENSSL_malloc(sizeof(OCSP_REQ_CTX));
rctx->state = OHS_FIRSTLINE;
rctx->mem = BIO_new(BIO_s_mem());
rctx->io = io;
if (maxline > 0)
rctx->iobuflen = maxline;
else
rctx->iobuflen = OCSP_MAX_LINE_LEN;
rctx->iobuf = OPENSSL_malloc(rctx->iobuflen);
if (!path)
path = "/";
if (BIO_printf(rctx->mem, post_hdr, path,
i2d_OCSP_REQUEST(req, NULL)) <= 0)
{
rctx->state = OHS_ERROR;
return 0;
}
if (i2d_OCSP_REQUEST_bio(rctx->mem, req) <= 0)
{
rctx->state = OHS_ERROR;
return 0;
}
rctx->state = OHS_ASN1_WRITE;
rctx->asn1_len = BIO_get_mem_data(rctx->mem, NULL);
return rctx;
}
/* Parse the HTTP response. This will look like this:
* "HTTP/1.0 200 OK". We need to obtain the numeric code and
* (optional) informational message.
*/
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req)
{
BIO *mem = NULL;
char tmpbuf[1024];
OCSP_RESPONSE *resp = NULL;
static int parse_http_line1(char *line)
{
int retcode;
char *p, *q, *r;
int len, retcode;
static char req_txt[] =
"POST %s HTTP/1.0\r\n\
Content-Type: application/ocsp-request\r\n\
Content-Length: %d\r\n\r\n";
len = i2d_OCSP_REQUEST(req, NULL);
if(BIO_printf(b, req_txt, path, len) < 0) {
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_WRITE_ERROR);
goto err;
}
if(i2d_OCSP_REQUEST_bio(b, req) <= 0) {
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_WRITE_ERROR);
goto err;
}
if(!(mem = BIO_new(BIO_s_mem()))) goto err;
/* Copy response to a memory BIO: socket bios can't do gets! */
while ((len = BIO_read(b, tmpbuf, sizeof tmpbuf))) {
if(len < 0) {
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_READ_ERROR);
goto err;
}
BIO_write(mem, tmpbuf, len);
}
if(BIO_gets(mem, tmpbuf, 512) <= 0) {
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
goto err;
}
/* Parse the HTTP response. This will look like this:
* "HTTP/1.0 200 OK". We need to obtain the numeric code and
* (optional) informational message.
*/
/* Skip to first white space (passed protocol info) */
for(p = tmpbuf; *p && !isspace((unsigned char)*p); p++) continue;
if(!*p) {
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
goto err;
}
for(p = line; *p && !isspace((unsigned char)*p); p++)
continue;
if(!*p)
{
OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
return 0;
}
/* Skip past white space to start of response code */
while(*p && isspace((unsigned char)*p)) p++;
if(!*p) {
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
goto err;
}
while(*p && isspace((unsigned char)*p))
p++;
if(!*p)
{
OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
return 0;
}
/* Find end of response code: first whitespace after start of code */
for(q = p; *q && !isspace((unsigned char)*q); q++) continue;
if(!*q) {
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
goto err;
}
for(q = p; *q && !isspace((unsigned char)*q); q++)
continue;
if(!*q)
{
OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
return 0;
}
/* Set end of response code and start of message */
*q++ = 0;
/* Attempt to parse numeric code */
retcode = strtoul(p, &r, 10);
if(*r) goto err;
if(*r)
return 0;
/* Skip over any leading white space in message */
while(*q && isspace((unsigned char)*q)) q++;
if(*q) {
/* Finally zap any trailing white space in message (include CRLF) */
/* We know q has a non white space character so this is OK */
for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--) *r = 0;
}
if(retcode != 200) {
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_ERROR);
if(!*q) {
while(*q && isspace((unsigned char)*q))
q++;
if(*q)
{
/* Finally zap any trailing white space in message (include
* CRLF) */
/* We know q has a non white space character so this is OK */
for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--)
*r = 0;
}
if(retcode != 200)
{
OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_ERROR);
if(!*q)
ERR_add_error_data(2, "Code=", p);
}
else {
else
ERR_add_error_data(4, "Code=", p, ",Reason=", q);
return 0;
}
goto err;
return 1;
}
/* Find blank line marking beginning of content */
while(BIO_gets(mem, tmpbuf, 512) > 0)
int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx)
{
for(p = tmpbuf; *p && isspace((unsigned char)*p); p++) continue;
if(!*p) break;
int i, n;
const unsigned char *p;
next_io:
if (!(rctx->state & OHS_NOREAD))
{
n = BIO_read(rctx->io, rctx->iobuf, rctx->iobuflen);
if (n <= 0)
{
if (BIO_should_retry(rctx->io))
return -1;
return 0;
}
/* Write data to memory BIO */
if (BIO_write(rctx->mem, rctx->iobuf, n) != n)
return 0;
}
switch(rctx->state)
{
case OHS_ASN1_WRITE:
n = BIO_get_mem_data(rctx->mem, &p);
i = BIO_write(rctx->io,
p + (n - rctx->asn1_len), rctx->asn1_len);
if (i <= 0)
{
if (BIO_should_retry(rctx->io))
return -1;
rctx->state = OHS_ERROR;
return 0;
}
rctx->asn1_len -= i;
if (rctx->asn1_len > 0)
goto next_io;
rctx->state = OHS_ASN1_FLUSH;
(void)BIO_reset(rctx->mem);
case OHS_ASN1_FLUSH:
i = BIO_flush(rctx->io);
if (i > 0)
{
rctx->state = OHS_FIRSTLINE;
goto next_io;
}
if (BIO_should_retry(rctx->io))
return -1;
rctx->state = OHS_ERROR;
return 0;
case OHS_ERROR:
return 0;
case OHS_FIRSTLINE:
case OHS_HEADERS:
/* Attempt to read a line in */
next_line:
/* Due to &%^*$" memory BIO behaviour with BIO_gets we
* have to check there's a complete line in there before
* calling BIO_gets or we'll just get a partial read.
*/
n = BIO_get_mem_data(rctx->mem, &p);
if ((n <= 0) || !memchr(p, '\n', n))
{
if (n >= rctx->iobuflen)
{
rctx->state = OHS_ERROR;
return 0;
}
goto next_io;
}
n = BIO_gets(rctx->mem, (char *)rctx->iobuf, rctx->iobuflen);
if (n <= 0)
{
if (BIO_should_retry(rctx->mem))
goto next_io;
rctx->state = OHS_ERROR;
return 0;
}
/* Don't allow excessive lines */
if (n == rctx->iobuflen)
{
rctx->state = OHS_ERROR;
return 0;
}
/* First line */
if (rctx->state == OHS_FIRSTLINE)
{
if (parse_http_line1((char *)rctx->iobuf))
{
rctx->state = OHS_HEADERS;
goto next_line;
}
else
{
rctx->state = OHS_ERROR;
return 0;
}
}
else
{
/* Look for blank line: end of headers */
for (p = rctx->iobuf; *p; p++)
{
if ((*p != '\r') && (*p != '\n'))
break;
}
if (*p)
goto next_line;
rctx->state = OHS_ASN1_HEADER;
}
/* Fall thru */
case OHS_ASN1_HEADER:
/* Now reading ASN1 header: can read at least 6 bytes which
* is more than enough for any valid ASN1 SEQUENCE header
*/
n = BIO_get_mem_data(rctx->mem, &p);
if (n < 6)
goto next_io;
/* Check it is an ASN1 SEQUENCE */
if (*p++ != (V_ASN1_SEQUENCE|V_ASN1_CONSTRUCTED))
{
rctx->state = OHS_ERROR;
return 0;
}
/* Check out length field */
if (*p & 0x80)
{
n = *p & 0x7F;
/* Not NDEF or excessive length */
if (!n || (n > 4))
{
rctx->state = OHS_ERROR;
return 0;
}
p++;
rctx->asn1_len = 0;
for (i = 0; i < n; i++)
{
rctx->asn1_len <<= 8;
rctx->asn1_len |= *p++;
}
if (rctx->asn1_len > OCSP_MAX_REQUEST_LENGTH)
{
rctx->state = OHS_ERROR;
return 0;
}
rctx->asn1_len += n + 2;
}
else
rctx->asn1_len = *p + 2;
rctx->state = OHS_ASN1_CONTENT;
/* Fall thru */
case OHS_ASN1_CONTENT:
n = BIO_get_mem_data(rctx->mem, &p);
if (n < (int)rctx->asn1_len)
goto next_io;
*presp = d2i_OCSP_RESPONSE(NULL, &p, rctx->asn1_len);
if (*presp)
{
rctx->state = OHS_DONE;
return 1;
}
rctx->state = OHS_ERROR;
return 0;
break;
case OHS_DONE:
return 1;
}
return 0;
}
if(*p) {
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_NO_CONTENT);
goto err;
/* Blocking OCSP request handler: now a special case of non-blocking I/O */
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req)
{
OCSP_RESPONSE *resp = NULL;
OCSP_REQ_CTX *ctx;
int rv;
ctx = OCSP_sendreq_new(b, path, req, -1);
do
{
rv = OCSP_sendreq_nbio(&resp, ctx);
} while ((rv == -1) && BIO_should_retry(b));
OCSP_REQ_CTX_free(ctx);
if (rv)
return resp;
return NULL;
}
if(!(resp = d2i_OCSP_RESPONSE_bio(mem, NULL))) {
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,ERR_R_NESTED_ASN1_ERROR);
goto err;
}
err:
BIO_free(mem);
return resp;
}

View File

@ -171,4 +171,8 @@ typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
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 */

View File

@ -964,6 +964,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))

View File

@ -203,6 +203,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)
@ -918,6 +920,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)

View File

@ -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;

View File

@ -617,6 +617,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);

View File

@ -230,6 +230,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;
}
#endif

View File

@ -283,10 +283,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;
@ -450,6 +463,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:
@ -1688,7 +1709,7 @@ int ssl3_get_new_session_ticket(SSL *s)
if (ticklen + 6 != n)
{
al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
goto f_err;
}
if (s->session->tlsext_tick)
@ -1699,7 +1720,7 @@ int ssl3_get_new_session_ticket(SSL *s)
s->session->tlsext_tick = OPENSSL_malloc(ticklen);
if (!s->session->tlsext_tick)
{
SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
goto err;
}
memcpy(s->session->tlsext_tick, p, ticklen);
@ -1712,6 +1733,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)

View File

@ -1936,6 +1936,44 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
s->tlsext_debug_arg=parg;
ret = 1;
break;
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;
@ -2156,6 +2194,12 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
}
return 1;
}
case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG:
ctx->tlsext_status_arg=parg;
return 1;
break;
#endif /* !OPENSSL_NO_TLSEXT */
/* A Thawte special :-) */
case SSL_CTRL_EXTRA_CHAIN_CERT:
@ -2206,6 +2250,11 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB:
ctx->tlsext_servername_callback=(int (*)(SSL *,int *,void *))fp;
break;
case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB:
ctx->tlsext_status_cb=(int (*)(SSL *,void *))fp;
break;
#endif
default:
return(0);

View File

@ -306,10 +306,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;
@ -512,6 +525,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:
@ -2740,4 +2761,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

View File

@ -767,6 +767,11 @@ struct ssl_ctx_st
unsigned char tlsext_tick_key_name[16];
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;
#endif
};
@ -1003,6 +1008,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;
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
@ -1158,6 +1175,7 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
#define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION
#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE
#define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME
#define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE
#define SSL_ERROR_NONE 0
#define SSL_ERROR_SSL 1
@ -1225,6 +1243,16 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
#define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57
#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58
#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59
#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) \
@ -1670,6 +1698,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
@ -1854,6 +1883,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 316
#define SSL_R_INVALID_TICKET_KEYS_LENGTH 275
#define SSL_R_INVALID_TRUST 279
#define SSL_R_KEY_ARG_TOO_LONG 284
@ -2010,6 +2040,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

View File

@ -483,6 +483,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 */
@ -526,6 +528,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
@ -538,6 +542,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

View File

@ -141,6 +141,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"},
@ -328,6 +329,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"},
@ -484,6 +486,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"},

View File

@ -126,6 +126,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
@ -311,6 +312,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
@ -501,6 +508,13 @@ void SSL_free(SSL *s)
if (s->ctx) SSL_CTX_free(s->ctx);
#ifndef OPENSSL_NO_TLSEXT
if (s->initial_ctx) SSL_CTX_free(s->initial_ctx);
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)
sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free);
@ -1494,6 +1508,9 @@ SSL_CTX *SSL_CTX_new(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
return(ret);

View File

@ -777,6 +777,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);
@ -870,6 +871,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);

View File

@ -60,6 +60,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;
@ -190,6 +191,54 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
}
}
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;
@ -220,7 +269,14 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
s2n(TLSEXT_TYPE_session_ticket,ret);
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);
}
if ((extdatalen = ret-p-2)== 0)
return p;
@ -235,6 +291,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;
@ -349,6 +406,106 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
}
}
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;
@ -403,6 +560,19 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
}
s->tlsext_ticket_expected = 1;
}
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;
}
@ -448,6 +618,37 @@ 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;
err:
switch (ret)
{
case SSL_TLSEXT_ERR_ALERT_FATAL:
@ -475,6 +676,35 @@ int ssl_check_serverhello_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 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;
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
}
if (r < 0)
{
al = SSL_AD_INTERNAL_ERROR;
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
}
}
switch (ret)
{
case SSL_TLSEXT_ERR_ALERT_FATAL:

View File

@ -117,6 +117,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
#ifndef OPENSSL_NO_TLSEXT
@ -134,12 +136,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) \
@ -149,6 +172,13 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLXEXT_TICKET_KEYS,(keylen),(keys))
#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)
#endif
/* Additional TLS ciphersuites from draft-ietf-tls-56-bit-ciphersuites-00.txt

View File

@ -3521,3 +3521,11 @@ SEED_ecb_encrypt 3915 EXIST::FUNCTION:SEED
EVP_seed_ecb 3916 EXIST::FUNCTION:SEED
SEED_set_key 3917 EXIST::FUNCTION:SEED
EVP_seed_cfb128 3918 EXIST::FUNCTION:SEED
X509_EXTENSIONS_it 3919 EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
X509_EXTENSIONS_it 3919 EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
X509_get1_ocsp 3920 EXIST::FUNCTION:
OCSP_REQ_CTX_free 3921 EXIST::FUNCTION:
i2d_X509_EXTENSIONS 3922 EXIST::FUNCTION:
OCSP_sendreq_nbio 3923 EXIST::FUNCTION:
OCSP_sendreq_new 3924 EXIST::FUNCTION:
d2i_X509_EXTENSIONS 3925 EXIST::FUNCTION: