Backport certificate status request TLS extension support to 0.9.8.
This commit is contained in:
parent
074471ab0c
commit
a523276786
7
CHANGES
7
CHANGES
@ -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]
|
||||
|
||||
|
15
apps/apps.h
15
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);
|
||||
@ -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);
|
||||
|
||||
|
210
apps/ocsp.c
210
apps/ocsp.c
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
182
apps/s_server.c
182
apps/s_server.c
@ -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)
|
||||
|
11
apps/x509.c
11
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);
|
||||
|
@ -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)
|
||||
|
@ -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. */
|
||||
|
@ -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}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
49
ssl/s3_lib.c
49
ssl/s3_lib.c
@ -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);
|
||||
|
@ -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
|
||||
|
31
ssl/ssl.h
31
ssl/ssl.h
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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"},
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
232
ssl/t1_lib.c
232
ssl/t1_lib.c
@ -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:
|
||||
|
36
ssl/tls1.h
36
ssl/tls1.h
@ -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
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user