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]
|
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]
|
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
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
#include <openssl/engine.h>
|
#include <openssl/engine.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef OPENSSL_NO_OCSP
|
||||||
|
#include <openssl/ocsp.h>
|
||||||
|
#endif
|
||||||
#include <openssl/ossl_typ.h>
|
#include <openssl/ossl_typ.h>
|
||||||
|
|
||||||
int app_RAND_load_file(const char *file, BIO *bio_e, int dont_warn);
|
int app_RAND_load_file(const char *file, BIO *bio_e, int dont_warn);
|
||||||
@ -228,6 +231,12 @@ extern BIO *bio_err;
|
|||||||
# endif
|
# endif
|
||||||
#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
|
typedef struct args_st
|
||||||
{
|
{
|
||||||
char **data;
|
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);
|
ENGINE *setup_engine(BIO *err, const char *engine, int debug);
|
||||||
#endif
|
#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);
|
int load_config(BIO *err, CONF *cnf);
|
||||||
char *make_config_name(void);
|
char *make_config_name(void);
|
||||||
|
|
||||||
|
210
apps/ocsp.c
210
apps/ocsp.c
@ -58,13 +58,14 @@
|
|||||||
#ifndef OPENSSL_NO_OCSP
|
#ifndef OPENSSL_NO_OCSP
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "apps.h"
|
#include <openssl/e_os2.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/ocsp.h>
|
#include <openssl/ocsp.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/txt_db.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/bn.h>
|
#include "apps.h"
|
||||||
|
|
||||||
/* Maximum leeway in validity period: default 5 minutes */
|
/* Maximum leeway in validity period: default 5 minutes */
|
||||||
#define MAX_VALIDITY_PERIOD (5 * 60)
|
#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 BIO *init_responder(char *port);
|
||||||
static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, 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 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
|
#undef PROG
|
||||||
#define PROG ocsp_main
|
#define PROG ocsp_main
|
||||||
@ -112,11 +115,11 @@ int MAIN(int argc, char **argv)
|
|||||||
BIO *acbio = NULL, *cbio = NULL;
|
BIO *acbio = NULL, *cbio = NULL;
|
||||||
BIO *derbio = NULL;
|
BIO *derbio = NULL;
|
||||||
BIO *out = NULL;
|
BIO *out = NULL;
|
||||||
|
int req_timeout = -1;
|
||||||
int req_text = 0, resp_text = 0;
|
int req_text = 0, resp_text = 0;
|
||||||
long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
|
long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
|
||||||
char *CAfile = NULL, *CApath = NULL;
|
char *CAfile = NULL, *CApath = NULL;
|
||||||
X509_STORE *store = NULL;
|
X509_STORE *store = NULL;
|
||||||
SSL_CTX *ctx = NULL;
|
|
||||||
STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
|
STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
|
||||||
char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL;
|
char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL;
|
||||||
unsigned long sign_flags = 0, verify_flags = 0, rflags = 0;
|
unsigned long sign_flags = 0, verify_flags = 0, rflags = 0;
|
||||||
@ -154,6 +157,22 @@ int MAIN(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
else badarg = 1;
|
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"))
|
else if (!strcmp(*args, "-url"))
|
||||||
{
|
{
|
||||||
if (args[1])
|
if (args[1])
|
||||||
@ -703,52 +722,14 @@ int MAIN(int argc, char **argv)
|
|||||||
else if (host)
|
else if (host)
|
||||||
{
|
{
|
||||||
#ifndef OPENSSL_NO_SOCK
|
#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
|
#else
|
||||||
BIO_printf(bio_err, "Error creating connect BIO - sockets not supported.\n");
|
BIO_printf(bio_err, "Error creating connect BIO - sockets not supported.\n");
|
||||||
goto end;
|
goto end;
|
||||||
#endif
|
#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)
|
else if (respin)
|
||||||
{
|
{
|
||||||
@ -897,7 +878,6 @@ end:
|
|||||||
OPENSSL_free(host);
|
OPENSSL_free(host);
|
||||||
OPENSSL_free(port);
|
OPENSSL_free(port);
|
||||||
OPENSSL_free(path);
|
OPENSSL_free(path);
|
||||||
SSL_CTX_free(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OPENSSL_EXIT(ret);
|
OPENSSL_EXIT(ret);
|
||||||
@ -1121,6 +1101,7 @@ static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser)
|
|||||||
char *itmp, *row[DB_NUMBER],**rrow;
|
char *itmp, *row[DB_NUMBER],**rrow;
|
||||||
for (i = 0; i < DB_NUMBER; i++) row[i] = NULL;
|
for (i = 0; i < DB_NUMBER; i++) row[i] = NULL;
|
||||||
bn = ASN1_INTEGER_to_BN(ser,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))
|
if (BN_is_zero(bn))
|
||||||
itmp = BUF_strdup("00");
|
itmp = BUF_strdup("00");
|
||||||
else
|
else
|
||||||
@ -1231,4 +1212,137 @@ static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp)
|
|||||||
return 1;
|
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
|
#endif
|
||||||
|
@ -134,6 +134,7 @@ typedef unsigned int u_int;
|
|||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/ocsp.h>
|
||||||
#include "s_apps.h"
|
#include "s_apps.h"
|
||||||
#include "timeouts.h"
|
#include "timeouts.h"
|
||||||
|
|
||||||
@ -173,12 +174,14 @@ static int c_Pause=0;
|
|||||||
static int c_debug=0;
|
static int c_debug=0;
|
||||||
#ifndef OPENSSL_NO_TLSEXT
|
#ifndef OPENSSL_NO_TLSEXT
|
||||||
static int c_tlsextdebug=0;
|
static int c_tlsextdebug=0;
|
||||||
|
static int c_status_req=0;
|
||||||
#endif
|
#endif
|
||||||
static int c_msg=0;
|
static int c_msg=0;
|
||||||
static int c_showcerts=0;
|
static int c_showcerts=0;
|
||||||
|
|
||||||
static void sc_usage(void);
|
static void sc_usage(void);
|
||||||
static void print_stuff(BIO *berr,SSL *con,int full);
|
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 BIO *bio_c_out=NULL;
|
||||||
static int c_quiet=0;
|
static int c_quiet=0;
|
||||||
static int c_ign_eof=0;
|
static int c_ign_eof=0;
|
||||||
@ -239,6 +242,7 @@ static void sc_usage(void)
|
|||||||
#ifndef OPENSSL_NO_TLSEXT
|
#ifndef OPENSSL_NO_TLSEXT
|
||||||
BIO_printf(bio_err," -servername host - Set TLS extension servername in ClientHello\n");
|
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," -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");
|
BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -435,6 +439,8 @@ int MAIN(int argc, char **argv)
|
|||||||
#ifndef OPENSSL_NO_TLSEXT
|
#ifndef OPENSSL_NO_TLSEXT
|
||||||
else if (strcmp(*argv,"-tlsextdebug") == 0)
|
else if (strcmp(*argv,"-tlsextdebug") == 0)
|
||||||
c_tlsextdebug=1;
|
c_tlsextdebug=1;
|
||||||
|
else if (strcmp(*argv,"-status") == 0)
|
||||||
|
c_status_req=1;
|
||||||
#endif
|
#endif
|
||||||
#ifdef WATT32
|
#ifdef WATT32
|
||||||
else if (strcmp(*argv,"-wdebug") == 0)
|
else if (strcmp(*argv,"-wdebug") == 0)
|
||||||
@ -826,6 +832,23 @@ re_start:
|
|||||||
SSL_set_tlsext_debug_callback(con, tlsext_cb);
|
SSL_set_tlsext_debug_callback(con, tlsext_cb);
|
||||||
SSL_set_tlsext_debug_arg(con, bio_c_out);
|
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
|
#endif
|
||||||
|
|
||||||
SSL_set_bio(con,sbio,sbio);
|
SSL_set_bio(con,sbio,sbio);
|
||||||
@ -1430,3 +1453,28 @@ static void print_stuff(BIO *bio, SSL *s, int full)
|
|||||||
(void)BIO_flush(bio);
|
(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/x509.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/ocsp.h>
|
||||||
#ifndef OPENSSL_NO_DH
|
#ifndef OPENSSL_NO_DH
|
||||||
#include <openssl/dh.h>
|
#include <openssl/dh.h>
|
||||||
#endif
|
#endif
|
||||||
@ -269,6 +270,8 @@ static BIO *bio_s_out=NULL;
|
|||||||
static int s_debug=0;
|
static int s_debug=0;
|
||||||
#ifndef OPENSSL_NO_TLSEXT
|
#ifndef OPENSSL_NO_TLSEXT
|
||||||
static int s_tlsextdebug=0;
|
static int s_tlsextdebug=0;
|
||||||
|
static int s_tlsextstatus=0;
|
||||||
|
static int cert_status_cb(SSL *s, void *arg);
|
||||||
#endif
|
#endif
|
||||||
static int s_msg=0;
|
static int s_msg=0;
|
||||||
static int s_quiet=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;
|
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
|
#endif
|
||||||
int MAIN(int, char **);
|
int MAIN(int, char **);
|
||||||
|
|
||||||
@ -792,6 +941,33 @@ int MAIN(int argc, char *argv[])
|
|||||||
#ifndef OPENSSL_NO_TLSEXT
|
#ifndef OPENSSL_NO_TLSEXT
|
||||||
else if (strcmp(*argv,"-tlsextdebug") == 0)
|
else if (strcmp(*argv,"-tlsextdebug") == 0)
|
||||||
s_tlsextdebug=1;
|
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
|
#endif
|
||||||
else if (strcmp(*argv,"-msg") == 0)
|
else if (strcmp(*argv,"-msg") == 0)
|
||||||
{ s_msg=1; }
|
{ 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_callback(con, tlsext_cb);
|
||||||
SSL_set_tlsext_debug_arg(con, bio_s_out);
|
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
|
#endif
|
||||||
#ifndef OPENSSL_NO_KRB5
|
#ifndef OPENSSL_NO_KRB5
|
||||||
if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
|
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",
|
" -alias - output certificate alias\n",
|
||||||
" -noout - no certificate output\n",
|
" -noout - no certificate output\n",
|
||||||
" -ocspid - print OCSP hash values for the subject name and public key\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",
|
" -trustout - output a \"trusted\" certificate\n",
|
||||||
" -clrtrust - clear all trusted purposes\n",
|
" -clrtrust - clear all trusted purposes\n",
|
||||||
" -clrreject - clear all rejected purposes\n",
|
" -clrreject - clear all rejected purposes\n",
|
||||||
@ -179,6 +180,7 @@ int MAIN(int argc, char **argv)
|
|||||||
int next_serial=0;
|
int next_serial=0;
|
||||||
int subject_hash=0,issuer_hash=0,ocspid=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 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 trustout=0,clrtrust=0,clrreject=0,aliasout=0,clrext=0;
|
||||||
int C=0;
|
int C=0;
|
||||||
int x509req=0,days=DEF_DAYS,modulus=0,pubkey=0;
|
int x509req=0,days=DEF_DAYS,modulus=0,pubkey=0;
|
||||||
@ -378,6 +380,8 @@ int MAIN(int argc, char **argv)
|
|||||||
C= ++num;
|
C= ++num;
|
||||||
else if (strcmp(*argv,"-email") == 0)
|
else if (strcmp(*argv,"-email") == 0)
|
||||||
email= ++num;
|
email= ++num;
|
||||||
|
else if (strcmp(*argv,"-ocsp_uri") == 0)
|
||||||
|
ocsp_uri= ++num;
|
||||||
else if (strcmp(*argv,"-serial") == 0)
|
else if (strcmp(*argv,"-serial") == 0)
|
||||||
serial= ++num;
|
serial= ++num;
|
||||||
else if (strcmp(*argv,"-next_serial") == 0)
|
else if (strcmp(*argv,"-next_serial") == 0)
|
||||||
@ -731,11 +735,14 @@ bad:
|
|||||||
ASN1_INTEGER_free(ser);
|
ASN1_INTEGER_free(ser);
|
||||||
BIO_puts(out, "\n");
|
BIO_puts(out, "\n");
|
||||||
}
|
}
|
||||||
else if (email == i)
|
else if ((email == i) || (ocsp_uri == i))
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
STACK *emlst;
|
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++)
|
for (j = 0; j < sk_num(emlst); j++)
|
||||||
BIO_printf(STDout, "%s\n", sk_value(emlst, j));
|
BIO_printf(STDout, "%s\n", sk_value(emlst, j));
|
||||||
X509_email_free(emlst);
|
X509_email_free(emlst);
|
||||||
|
@ -67,5 +67,10 @@ ASN1_SEQUENCE(X509_EXTENSION) = {
|
|||||||
ASN1_SIMPLE(X509_EXTENSION, value, ASN1_OCTET_STRING)
|
ASN1_SIMPLE(X509_EXTENSION, value, ASN1_OCTET_STRING)
|
||||||
} ASN1_SEQUENCE_END(X509_EXTENSION)
|
} 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_FUNCTIONS(X509_EXTENSION)
|
||||||
|
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS)
|
||||||
IMPLEMENT_ASN1_DUP_FUNCTION(X509_EXTENSION)
|
IMPLEMENT_ASN1_DUP_FUNCTION(X509_EXTENSION)
|
||||||
|
@ -186,11 +186,11 @@ typedef struct ocsp_resp_bytes_st
|
|||||||
* responseStatus OCSPResponseStatus,
|
* responseStatus OCSPResponseStatus,
|
||||||
* responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
|
* responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
|
||||||
*/
|
*/
|
||||||
typedef struct ocsp_response_st
|
struct ocsp_response_st
|
||||||
{
|
{
|
||||||
ASN1_ENUMERATED *responseStatus;
|
ASN1_ENUMERATED *responseStatus;
|
||||||
OCSP_RESPBYTES *responseBytes;
|
OCSP_RESPBYTES *responseBytes;
|
||||||
} OCSP_RESPONSE;
|
};
|
||||||
|
|
||||||
/* ResponderID ::= CHOICE {
|
/* ResponderID ::= CHOICE {
|
||||||
* byName [1] Name,
|
* byName [1] Name,
|
||||||
@ -198,14 +198,18 @@ typedef struct ocsp_response_st
|
|||||||
*/
|
*/
|
||||||
#define V_OCSP_RESPID_NAME 0
|
#define V_OCSP_RESPID_NAME 0
|
||||||
#define V_OCSP_RESPID_KEY 1
|
#define V_OCSP_RESPID_KEY 1
|
||||||
typedef struct ocsp_responder_id_st
|
struct ocsp_responder_id_st
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
union {
|
union {
|
||||||
X509_NAME* byName;
|
X509_NAME* byName;
|
||||||
ASN1_OCTET_STRING *byKey;
|
ASN1_OCTET_STRING *byKey;
|
||||||
} value;
|
} value;
|
||||||
} OCSP_RESPID;
|
};
|
||||||
|
|
||||||
|
DECLARE_STACK_OF(OCSP_RESPID)
|
||||||
|
DECLARE_ASN1_FUNCTIONS(OCSP_RESPID)
|
||||||
|
|
||||||
/* KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key
|
/* KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key
|
||||||
* --(excluding the tag and length fields)
|
* --(excluding the tag and length fields)
|
||||||
*/
|
*/
|
||||||
@ -397,6 +401,10 @@ typedef struct ocsp_service_locator_st
|
|||||||
(char *(*)())d2i_OCSP_CERTSTATUS,(char *)(cs))
|
(char *(*)())d2i_OCSP_CERTSTATUS,(char *)(cs))
|
||||||
|
|
||||||
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req);
|
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);
|
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_REQUEST_VERIFY 116
|
||||||
#define OCSP_F_OCSP_RESPONSE_GET1_BASIC 111
|
#define OCSP_F_OCSP_RESPONSE_GET1_BASIC 111
|
||||||
#define OCSP_F_OCSP_SENDREQ_BIO 112
|
#define OCSP_F_OCSP_SENDREQ_BIO 112
|
||||||
|
#define OCSP_F_PARSE_HTTP_LINE1 117
|
||||||
#define OCSP_F_REQUEST_VERIFY 113
|
#define OCSP_F_REQUEST_VERIFY 113
|
||||||
|
|
||||||
/* Reason codes. */
|
/* Reason codes. */
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* crypto/ocsp/ocsp_err.c */
|
/* 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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* 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_REQUEST_VERIFY), "OCSP_request_verify"},
|
||||||
{ERR_FUNC(OCSP_F_OCSP_RESPONSE_GET1_BASIC), "OCSP_response_get1_basic"},
|
{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_OCSP_SENDREQ_BIO), "OCSP_sendreq_bio"},
|
||||||
|
{ERR_FUNC(OCSP_F_PARSE_HTTP_LINE1), "PARSE_HTTP_LINE1"},
|
||||||
{ERR_FUNC(OCSP_F_REQUEST_VERIFY), "REQUEST_VERIFY"},
|
{ERR_FUNC(OCSP_F_REQUEST_VERIFY), "REQUEST_VERIFY"},
|
||||||
{0,NULL}
|
{0,NULL}
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
/* ocsp_ht.c */
|
/* ocsp_ht.c */
|
||||||
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
|
/* 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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -68,106 +68,404 @@
|
|||||||
#define strtoul (unsigned long)strtol
|
#define strtoul (unsigned long)strtol
|
||||||
#endif /* OPENSSL_SYS_SUNOS */
|
#endif /* OPENSSL_SYS_SUNOS */
|
||||||
|
|
||||||
/* Quick and dirty HTTP OCSP request handler.
|
/* Stateful OCSP request code, supporting non-blocking I/O */
|
||||||
* Could make this a bit cleverer by adding
|
|
||||||
* support for non blocking BIOs and a few
|
/* Opaque OCSP request status structure */
|
||||||
* other refinements.
|
|
||||||
|
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)
|
static int parse_http_line1(char *line)
|
||||||
{
|
{
|
||||||
BIO *mem = NULL;
|
int retcode;
|
||||||
char tmpbuf[1024];
|
|
||||||
OCSP_RESPONSE *resp = NULL;
|
|
||||||
char *p, *q, *r;
|
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) */
|
/* Skip to first white space (passed protocol info) */
|
||||||
for(p = tmpbuf; *p && !isspace((unsigned char)*p); p++) continue;
|
|
||||||
if(!*p) {
|
for(p = line; *p && !isspace((unsigned char)*p); p++)
|
||||||
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
|
continue;
|
||||||
goto err;
|
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 */
|
/* Skip past white space to start of response code */
|
||||||
while(*p && isspace((unsigned char)*p)) p++;
|
while(*p && isspace((unsigned char)*p))
|
||||||
if(!*p) {
|
p++;
|
||||||
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
|
|
||||||
goto err;
|
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 */
|
/* Find end of response code: first whitespace after start of code */
|
||||||
for(q = p; *q && !isspace((unsigned char)*q); q++) continue;
|
for(q = p; *q && !isspace((unsigned char)*q); q++)
|
||||||
if(!*q) {
|
continue;
|
||||||
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
|
|
||||||
goto err;
|
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 */
|
/* Set end of response code and start of message */
|
||||||
*q++ = 0;
|
*q++ = 0;
|
||||||
|
|
||||||
/* Attempt to parse numeric code */
|
/* Attempt to parse numeric code */
|
||||||
retcode = strtoul(p, &r, 10);
|
retcode = strtoul(p, &r, 10);
|
||||||
if(*r) goto err;
|
|
||||||
|
if(*r)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Skip over any leading white space in message */
|
/* Skip over any leading white space in message */
|
||||||
while(*q && isspace((unsigned char)*q)) q++;
|
while(*q && isspace((unsigned char)*q))
|
||||||
if(*q) {
|
q++;
|
||||||
/* Finally zap any trailing white space in message (include CRLF) */
|
|
||||||
/* We know q has a non white space character so this is OK */
|
if(*q)
|
||||||
for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--) *r = 0;
|
{
|
||||||
}
|
/* Finally zap any trailing white space in message (include
|
||||||
if(retcode != 200) {
|
* CRLF) */
|
||||||
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_ERROR);
|
|
||||||
if(!*q) {
|
/* 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);
|
ERR_add_error_data(2, "Code=", p);
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
ERR_add_error_data(4, "Code=", p, ",Reason=", q);
|
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;
|
int i, n;
|
||||||
if(!*p) break;
|
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);
|
/* Blocking OCSP request handler: now a special case of non-blocking I/O */
|
||||||
goto err;
|
|
||||||
|
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,
|
typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d,
|
||||||
int idx, long argl, void *argp);
|
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 */
|
#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_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_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(st) SKM_sk_new(OCSP_SINGLERESP, (st))
|
||||||
#define sk_OCSP_SINGLERESP_new_null() SKM_sk_new_null(OCSP_SINGLERESP)
|
#define sk_OCSP_SINGLERESP_new_null() SKM_sk_new_null(OCSP_SINGLERESP)
|
||||||
#define sk_OCSP_SINGLERESP_free(st) SKM_sk_free(OCSP_SINGLERESP, (st))
|
#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;
|
ASN1_OCTET_STRING *value;
|
||||||
} X509_EXTENSION;
|
} X509_EXTENSION;
|
||||||
|
|
||||||
|
typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
|
||||||
|
|
||||||
DECLARE_STACK_OF(X509_EXTENSION)
|
DECLARE_STACK_OF(X509_EXTENSION)
|
||||||
DECLARE_ASN1_SET_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);
|
X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value);
|
||||||
|
|
||||||
DECLARE_ASN1_FUNCTIONS(X509_EXTENSION)
|
DECLARE_ASN1_FUNCTIONS(X509_EXTENSION)
|
||||||
|
DECLARE_ASN1_ENCODE_FUNCTIONS(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS)
|
||||||
|
|
||||||
DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY)
|
DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY)
|
||||||
|
|
||||||
|
@ -473,6 +473,30 @@ STACK *X509_get1_email(X509 *x)
|
|||||||
return ret;
|
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)
|
STACK *X509_REQ_get1_email(X509_REQ *x)
|
||||||
{
|
{
|
||||||
GENERAL_NAMES *gens;
|
GENERAL_NAMES *gens;
|
||||||
|
@ -617,6 +617,7 @@ int X509_PURPOSE_get_id(X509_PURPOSE *);
|
|||||||
STACK *X509_get1_email(X509 *x);
|
STACK *X509_get1_email(X509 *x);
|
||||||
STACK *X509_REQ_get1_email(X509_REQ *x);
|
STACK *X509_REQ_get1_email(X509_REQ *x);
|
||||||
void X509_email_free(STACK *sk);
|
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(const char *ipasc);
|
||||||
ASN1_OCTET_STRING *a2i_IPADDRESS_NC(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)
|
if (s->tlsext_hostname != NULL)
|
||||||
ssl2_compat = 0;
|
ssl2_compat = 0;
|
||||||
|
if (s->tlsext_status_type != -1)
|
||||||
|
ssl2_compat = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -283,10 +283,23 @@ int ssl3_connect(SSL *s)
|
|||||||
{
|
{
|
||||||
ret=ssl3_get_server_certificate(s);
|
ret=ssl3_get_server_certificate(s);
|
||||||
if (ret <= 0) goto end;
|
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
|
else
|
||||||
skip=1;
|
skip=1;
|
||||||
|
|
||||||
s->state=SSL3_ST_CR_KEY_EXCH_A;
|
s->state=SSL3_ST_CR_KEY_EXCH_A;
|
||||||
|
#endif
|
||||||
s->init_num=0;
|
s->init_num=0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -450,6 +463,14 @@ int ssl3_connect(SSL *s)
|
|||||||
s->state=SSL3_ST_CR_FINISHED_A;
|
s->state=SSL3_ST_CR_FINISHED_A;
|
||||||
s->init_num=0;
|
s->init_num=0;
|
||||||
break;
|
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
|
#endif
|
||||||
|
|
||||||
case SSL3_ST_CR_FINISHED_A:
|
case SSL3_ST_CR_FINISHED_A:
|
||||||
@ -1688,7 +1709,7 @@ int ssl3_get_new_session_ticket(SSL *s)
|
|||||||
if (ticklen + 6 != n)
|
if (ticklen + 6 != n)
|
||||||
{
|
{
|
||||||
al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
|
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;
|
goto f_err;
|
||||||
}
|
}
|
||||||
if (s->session->tlsext_tick)
|
if (s->session->tlsext_tick)
|
||||||
@ -1699,7 +1720,7 @@ int ssl3_get_new_session_ticket(SSL *s)
|
|||||||
s->session->tlsext_tick = OPENSSL_malloc(ticklen);
|
s->session->tlsext_tick = OPENSSL_malloc(ticklen);
|
||||||
if (!s->session->tlsext_tick)
|
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;
|
goto err;
|
||||||
}
|
}
|
||||||
memcpy(s->session->tlsext_tick, p, ticklen);
|
memcpy(s->session->tlsext_tick, p, ticklen);
|
||||||
@ -1712,6 +1733,75 @@ f_err:
|
|||||||
err:
|
err:
|
||||||
return(-1);
|
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
|
#endif
|
||||||
|
|
||||||
int ssl3_get_server_done(SSL *s)
|
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;
|
s->tlsext_debug_arg=parg;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
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 */
|
#endif /* !OPENSSL_NO_TLSEXT */
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -2156,6 +2194,12 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG:
|
||||||
|
ctx->tlsext_status_arg=parg;
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
|
||||||
#endif /* !OPENSSL_NO_TLSEXT */
|
#endif /* !OPENSSL_NO_TLSEXT */
|
||||||
/* A Thawte special :-) */
|
/* A Thawte special :-) */
|
||||||
case SSL_CTRL_EXTRA_CHAIN_CERT:
|
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:
|
case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB:
|
||||||
ctx->tlsext_servername_callback=(int (*)(SSL *,int *,void *))fp;
|
ctx->tlsext_servername_callback=(int (*)(SSL *,int *,void *))fp;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB:
|
||||||
|
ctx->tlsext_status_cb=(int (*)(SSL *,void *))fp;
|
||||||
|
break;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return(0);
|
return(0);
|
||||||
|
@ -306,10 +306,23 @@ int ssl3_accept(SSL *s)
|
|||||||
{
|
{
|
||||||
ret=ssl3_send_server_certificate(s);
|
ret=ssl3_send_server_certificate(s);
|
||||||
if (ret <= 0) goto end;
|
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
|
else
|
||||||
skip=1;
|
skip=1;
|
||||||
|
|
||||||
s->state=SSL3_ST_SW_KEY_EXCH_A;
|
s->state=SSL3_ST_SW_KEY_EXCH_A;
|
||||||
|
#endif
|
||||||
s->init_num=0;
|
s->init_num=0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -512,6 +525,14 @@ int ssl3_accept(SSL *s)
|
|||||||
s->init_num=0;
|
s->init_num=0;
|
||||||
break;
|
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
|
#endif
|
||||||
|
|
||||||
case SSL3_ST_SW_CHANGE_A:
|
case SSL3_ST_SW_CHANGE_A:
|
||||||
@ -2740,4 +2761,39 @@ int ssl3_send_newsession_ticket(SSL *s)
|
|||||||
/* SSL3_ST_SW_SESSION_TICKET_B */
|
/* SSL3_ST_SW_SESSION_TICKET_B */
|
||||||
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
|
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
|
#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_key_name[16];
|
||||||
unsigned char tlsext_tick_hmac_key[16];
|
unsigned char tlsext_tick_hmac_key[16];
|
||||||
unsigned char tlsext_tick_aes_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
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -1003,6 +1008,18 @@ struct ssl_st
|
|||||||
1 : prepare 2, allow last ack just after in server callback.
|
1 : prepare 2, allow last ack just after in server callback.
|
||||||
2 : don't call servername callback, no ack in server hello
|
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 */
|
/* RFC4507 session ticket expected to be received or sent */
|
||||||
int tlsext_ticket_expected;
|
int tlsext_ticket_expected;
|
||||||
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
|
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_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION
|
||||||
#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE
|
#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE
|
||||||
#define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME
|
#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_NONE 0
|
||||||
#define SSL_ERROR_SSL 1
|
#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_SET_TLSEXT_DEBUG_ARG 57
|
||||||
#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58
|
#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58
|
||||||
#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59
|
#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
|
#endif
|
||||||
|
|
||||||
#define SSL_session_reused(ssl) \
|
#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_ENC 134
|
||||||
#define SSL_F_SSL3_GENERATE_KEY_BLOCK 238
|
#define SSL_F_SSL3_GENERATE_KEY_BLOCK 238
|
||||||
#define SSL_F_SSL3_GET_CERTIFICATE_REQUEST 135
|
#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_CERT_VERIFY 136
|
||||||
#define SSL_F_SSL3_GET_CLIENT_CERTIFICATE 137
|
#define SSL_F_SSL3_GET_CLIENT_CERTIFICATE 137
|
||||||
#define SSL_F_SSL3_GET_CLIENT_HELLO 138
|
#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_CHALLENGE_LENGTH 158
|
||||||
#define SSL_R_INVALID_COMMAND 280
|
#define SSL_R_INVALID_COMMAND 280
|
||||||
#define SSL_R_INVALID_PURPOSE 278
|
#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_TICKET_KEYS_LENGTH 275
|
||||||
#define SSL_R_INVALID_TRUST 279
|
#define SSL_R_INVALID_TRUST 279
|
||||||
#define SSL_R_KEY_ARG_TOO_LONG 284
|
#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_ELLIPTIC_CURVE 315
|
||||||
#define SSL_R_UNSUPPORTED_PROTOCOL 258
|
#define SSL_R_UNSUPPORTED_PROTOCOL 258
|
||||||
#define SSL_R_UNSUPPORTED_SSL_VERSION 259
|
#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_WRITE_BIO_NOT_SET 260
|
||||||
#define SSL_R_WRONG_CIPHER_RETURNED 261
|
#define SSL_R_WRONG_CIPHER_RETURNED 261
|
||||||
#define SSL_R_WRONG_MESSAGE_TYPE 262
|
#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_FINISHED_B (0x1D1|SSL_ST_CONNECT)
|
||||||
#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0|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_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 */
|
/* server */
|
||||||
/* extra state */
|
/* 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_FINISHED_B (0x1E1|SSL_ST_ACCEPT)
|
||||||
#define SSL3_ST_SW_SESSION_TICKET_A (0x1F0|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_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_HELLO_REQUEST 0
|
||||||
#define SSL3_MT_CLIENT_HELLO 1
|
#define SSL3_MT_CLIENT_HELLO 1
|
||||||
@ -538,6 +542,7 @@ typedef struct ssl3_state_st
|
|||||||
#define SSL3_MT_CERTIFICATE_VERIFY 15
|
#define SSL3_MT_CERTIFICATE_VERIFY 15
|
||||||
#define SSL3_MT_CLIENT_KEY_EXCHANGE 16
|
#define SSL3_MT_CLIENT_KEY_EXCHANGE 16
|
||||||
#define SSL3_MT_FINISHED 20
|
#define SSL3_MT_FINISHED 20
|
||||||
|
#define SSL3_MT_CERTIFICATE_STATUS 22
|
||||||
#define DTLS1_MT_HELLO_VERIFY_REQUEST 3
|
#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_ENC), "SSL3_ENC"},
|
||||||
{ERR_FUNC(SSL_F_SSL3_GENERATE_KEY_BLOCK), "SSL3_GENERATE_KEY_BLOCK"},
|
{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_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_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_CERTIFICATE), "SSL3_GET_CLIENT_CERTIFICATE"},
|
||||||
{ERR_FUNC(SSL_F_SSL3_GET_CLIENT_HELLO), "SSL3_GET_CLIENT_HELLO"},
|
{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_CHALLENGE_LENGTH),"invalid challenge length"},
|
||||||
{ERR_REASON(SSL_R_INVALID_COMMAND) ,"invalid command"},
|
{ERR_REASON(SSL_R_INVALID_COMMAND) ,"invalid command"},
|
||||||
{ERR_REASON(SSL_R_INVALID_PURPOSE) ,"invalid purpose"},
|
{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_TICKET_KEYS_LENGTH),"invalid ticket keys length"},
|
||||||
{ERR_REASON(SSL_R_INVALID_TRUST) ,"invalid trust"},
|
{ERR_REASON(SSL_R_INVALID_TRUST) ,"invalid trust"},
|
||||||
{ERR_REASON(SSL_R_KEY_ARG_TOO_LONG) ,"key arg too long"},
|
{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_ELLIPTIC_CURVE),"unsupported elliptic curve"},
|
||||||
{ERR_REASON(SSL_R_UNSUPPORTED_PROTOCOL) ,"unsupported protocol"},
|
{ERR_REASON(SSL_R_UNSUPPORTED_PROTOCOL) ,"unsupported protocol"},
|
||||||
{ERR_REASON(SSL_R_UNSUPPORTED_SSL_VERSION),"unsupported ssl version"},
|
{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_WRITE_BIO_NOT_SET) ,"write bio not set"},
|
||||||
{ERR_REASON(SSL_R_WRONG_CIPHER_RETURNED) ,"wrong cipher returned"},
|
{ERR_REASON(SSL_R_WRONG_CIPHER_RETURNED) ,"wrong cipher returned"},
|
||||||
{ERR_REASON(SSL_R_WRONG_MESSAGE_TYPE) ,"wrong message type"},
|
{ERR_REASON(SSL_R_WRONG_MESSAGE_TYPE) ,"wrong message type"},
|
||||||
|
@ -126,6 +126,7 @@
|
|||||||
#include <openssl/lhash.h>
|
#include <openssl/lhash.h>
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/ocsp.h>
|
||||||
#ifndef OPENSSL_NO_DH
|
#ifndef OPENSSL_NO_DH
|
||||||
#include <openssl/dh.h>
|
#include <openssl/dh.h>
|
||||||
#endif
|
#endif
|
||||||
@ -311,6 +312,12 @@ SSL *SSL_new(SSL_CTX *ctx)
|
|||||||
s->tlsext_debug_cb = 0;
|
s->tlsext_debug_cb = 0;
|
||||||
s->tlsext_debug_arg = NULL;
|
s->tlsext_debug_arg = NULL;
|
||||||
s->tlsext_ticket_expected = 0;
|
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);
|
CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
|
||||||
s->initial_ctx=ctx;
|
s->initial_ctx=ctx;
|
||||||
#endif
|
#endif
|
||||||
@ -501,6 +508,13 @@ void SSL_free(SSL *s)
|
|||||||
if (s->ctx) SSL_CTX_free(s->ctx);
|
if (s->ctx) SSL_CTX_free(s->ctx);
|
||||||
#ifndef OPENSSL_NO_TLSEXT
|
#ifndef OPENSSL_NO_TLSEXT
|
||||||
if (s->initial_ctx) SSL_CTX_free(s->initial_ctx);
|
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
|
#endif
|
||||||
if (s->client_CA != NULL)
|
if (s->client_CA != NULL)
|
||||||
sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free);
|
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))
|
|| (RAND_bytes(ret->tlsext_tick_aes_key, 16) <= 0))
|
||||||
ret->options |= SSL_OP_NO_TICKET;
|
ret->options |= SSL_OP_NO_TICKET;
|
||||||
|
|
||||||
|
ret->tlsext_status_cb = 0;
|
||||||
|
ret->tlsext_status_arg = NULL;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return(ret);
|
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);
|
void ssl3_init_finished_mac(SSL *s);
|
||||||
int ssl3_send_server_certificate(SSL *s);
|
int ssl3_send_server_certificate(SSL *s);
|
||||||
int ssl3_send_newsession_ticket(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_get_finished(SSL *s,int state_a,int state_b);
|
||||||
int ssl3_setup_key_block(SSL *s);
|
int ssl3_setup_key_block(SSL *s);
|
||||||
int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b);
|
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_server_hello(SSL *s);
|
||||||
int ssl3_get_certificate_request(SSL *s);
|
int ssl3_get_certificate_request(SSL *s);
|
||||||
int ssl3_get_new_session_ticket(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_get_server_done(SSL *s);
|
||||||
int ssl3_send_client_verify(SSL *s);
|
int ssl3_send_client_verify(SSL *s);
|
||||||
int ssl3_send_client_certificate(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/objects.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
|
#include <openssl/ocsp.h>
|
||||||
#include "ssl_locl.h"
|
#include "ssl_locl.h"
|
||||||
|
|
||||||
const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
|
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)
|
if ((extdatalen = ret-p-2)== 0)
|
||||||
return p;
|
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(TLSEXT_TYPE_session_ticket,ret);
|
||||||
s2n(0,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)
|
if ((extdatalen = ret-p-2)== 0)
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
@ -235,6 +291,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
|||||||
unsigned short len;
|
unsigned short len;
|
||||||
unsigned char *data = *p;
|
unsigned char *data = *p;
|
||||||
s->servername_done = 0;
|
s->servername_done = 0;
|
||||||
|
s->tlsext_status_type = -1;
|
||||||
|
|
||||||
if (data >= (d+n-2))
|
if (data >= (d+n-2))
|
||||||
return 1;
|
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 */
|
/* session ticket processed earlier */
|
||||||
|
|
||||||
data+=size;
|
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;
|
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;
|
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)
|
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);
|
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)
|
switch (ret)
|
||||||
{
|
{
|
||||||
case SSL_TLSEXT_ERR_ALERT_FATAL:
|
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)
|
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);
|
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)
|
switch (ret)
|
||||||
{
|
{
|
||||||
case SSL_TLSEXT_ERR_ALERT_FATAL:
|
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 */
|
/* NameType value from RFC 3546 */
|
||||||
#define TLSEXT_NAMETYPE_host_name 0
|
#define TLSEXT_NAMETYPE_host_name 0
|
||||||
|
/* status request value from RFC 3546 */
|
||||||
|
#define TLSEXT_STATUSTYPE_ocsp 1
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_TLSEXT
|
#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) \
|
#define SSL_set_tlsext_debug_arg(ssl, arg) \
|
||||||
SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)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) \
|
#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
|
||||||
SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))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_OK 0
|
||||||
#define SSL_TLSEXT_ERR_ALERT_WARNING 1
|
#define SSL_TLSEXT_ERR_ALERT_WARNING 1
|
||||||
#define SSL_TLSEXT_ERR_ALERT_FATAL 2
|
#define SSL_TLSEXT_ERR_ALERT_FATAL 2
|
||||||
#define SSL_TLSEXT_ERR_NOACK 3
|
#define SSL_TLSEXT_ERR_NOACK 3
|
||||||
|
|
||||||
#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
|
#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))
|
SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLXEXT_TICKET_KEYS,(keylen),(keys))
|
||||||
#define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \
|
#define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \
|
||||||
SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLXEXT_TICKET_KEYS,(keylen),(keys))
|
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
|
#endif
|
||||||
|
|
||||||
/* Additional TLS ciphersuites from draft-ietf-tls-56-bit-ciphersuites-00.txt
|
/* 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
|
EVP_seed_ecb 3916 EXIST::FUNCTION:SEED
|
||||||
SEED_set_key 3917 EXIST::FUNCTION:SEED
|
SEED_set_key 3917 EXIST::FUNCTION:SEED
|
||||||
EVP_seed_cfb128 3918 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