Adds CT validation to SSL connections

Disabled by default, but can be enabled by setting the
ct_validation_callback on a SSL or SSL_CTX.

Reviewed-by: Ben Laurie <ben@openssl.org>
Reviewed-by: Rich Salz <rsalz@openssl.org>
This commit is contained in:
Rob Percival 2016-03-03 16:19:23 +00:00 committed by Rich Salz
parent ddb4c0477a
commit ed29e82ade
11 changed files with 495 additions and 8 deletions

View File

@ -159,6 +159,9 @@
# include <openssl/safestack.h>
# include <openssl/symhacks.h>
# ifndef OPENSSL_NO_CT
# include <openssl/ct.h>
# endif
#ifdef __cplusplus
extern "C" {
@ -862,6 +865,9 @@ const char *SSL_get_psk_identity(const SSL *s);
/* Register callbacks to handle custom TLS Extensions for client or server. */
__owur int SSL_CTX_has_client_custom_ext(const SSL_CTX *ctx,
unsigned int ext_type);
__owur int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
custom_ext_add_cb add_cb,
custom_ext_free_cb free_cb,
@ -1865,6 +1871,43 @@ __owur const char *SSL_CIPHER_standard_name(const SSL_CIPHER *c);
int DTLSv1_listen(SSL *s, BIO_ADDR *client);
# ifndef OPENSSL_NO_CT
/*
* Sets a |callback| that is invoked upon receipt of ServerHelloDone to validate
* the received SCTs.
* If the callback returns a non-positive result, the connection is terminated.
* Call this function before beginning a handshake.
* If a NULL |callback| is provided, SCT validation is disabled.
* |arg| is arbitrary userdata that will be passed to the callback whenever it
* is invoked. Ownership of |arg| remains with the caller.
*
* NOTE: A side-effect of setting a CT callback is that an OCSP stapled response
* will be requested.
*/
__owur int SSL_set_ct_validation_callback(SSL *s,
ct_validation_cb callback,
void *arg);
__owur int SSL_CTX_set_ct_validation_callback(SSL_CTX *ctx,
ct_validation_cb callback,
void *arg);
/*
* Gets the callback being used to validate SCTs.
* This will return NULL if SCTs are neither being requested nor validated.
*/
__owur ct_validation_cb SSL_get_ct_validation_callback(const SSL *s);
__owur ct_validation_cb SSL_CTX_get_ct_validation_callback(const SSL_CTX *ctx);
/* Gets the SCTs received from a connection */
const STACK_OF(SCT) *SSL_get0_peer_scts(SSL *s);
/* Load the CT log list from the default location */
int SSL_CTX_set_default_ctlog_list_file(SSL_CTX *ctx);
/* Load the CT log list from the specified file path */
int SSL_CTX_set_ctlog_list_file(SSL_CTX *ctx, const char *path);
# endif /* OPENSSL_NO_CT */
/* What the "other" parameter contains in security callback */
/* Mask for type */
# define SSL_SECOP_OTHER_TYPE 0xffff0000
@ -1976,6 +2019,7 @@ void ERR_load_SSL_strings(void);
/* Function codes. */
# define SSL_F_CHECK_SUITEB_CIPHER_LIST 331
# define SSL_F_CT_MOVE_SCTS 345
# define SSL_F_D2I_SSL_SESSION 103
# define SSL_F_DANE_CTX_ENABLE 347
# define SSL_F_DANE_MTYPE_SET 393
@ -2058,11 +2102,13 @@ void ERR_load_SSL_strings(void);
# define SSL_F_SSL_CREATE_CIPHER_LIST 166
# define SSL_F_SSL_CTRL 232
# define SSL_F_SSL_CTX_CHECK_PRIVATE_KEY 168
# define SSL_F_SSL_CTX_GET_CT_VALIDATION_CALLBACK 349
# define SSL_F_SSL_CTX_MAKE_PROFILES 309
# define SSL_F_SSL_CTX_NEW 169
# define SSL_F_SSL_CTX_SET_ALPN_PROTOS 343
# define SSL_F_SSL_CTX_SET_CIPHER_LIST 269
# define SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE 290
# define SSL_F_SSL_CTX_SET_CT_VALIDATION_CALLBACK 396
# define SSL_F_SSL_CTX_SET_PURPOSE 226
# define SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT 219
# define SSL_F_SSL_CTX_SET_SSL_VERSION 170
@ -2082,6 +2128,8 @@ void ERR_load_SSL_strings(void);
# define SSL_F_SSL_DANE_ENABLE 395
# define SSL_F_SSL_DO_CONFIG 391
# define SSL_F_SSL_DO_HANDSHAKE 180
# define SSL_F_SSL_GET0_PEER_SCTS 397
# define SSL_F_SSL_GET_CT_VALIDATION_CALLBACK 398
# define SSL_F_SSL_GET_NEW_SESSION 181
# define SSL_F_SSL_GET_PREV_SESSION 217
# define SSL_F_SSL_GET_SERVER_CERT_INDEX 322
@ -2111,6 +2159,7 @@ void ERR_load_SSL_strings(void);
# define SSL_F_SSL_SET_ALPN_PROTOS 344
# define SSL_F_SSL_SET_CERT 191
# define SSL_F_SSL_SET_CIPHER_LIST 271
# define SSL_F_SSL_SET_CT_VALIDATION_CALLBACK 399
# define SSL_F_SSL_SET_FD 192
# define SSL_F_SSL_SET_PKEY 193
# define SSL_F_SSL_SET_PURPOSE 227
@ -2136,6 +2185,7 @@ void ERR_load_SSL_strings(void);
# define SSL_F_SSL_USE_RSAPRIVATEKEY 204
# define SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1 205
# define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE 206
# define SSL_F_SSL_VALIDATE_CT 400
# define SSL_F_SSL_VERIFY_CERT_CHAIN 207
# define SSL_F_SSL_WRITE 208
# define SSL_F_STATE_MACHINE 353
@ -2253,6 +2303,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_CONTEXT_NOT_DANE_ENABLED 167
# define SSL_R_COOKIE_GEN_CALLBACK_FAILURE 400
# define SSL_R_COOKIE_MISMATCH 308
# define SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED 206
# define SSL_R_DANE_ALREADY_ENABLED 172
# define SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL 173
# define SSL_R_DANE_NOT_ENABLED 175
@ -2377,8 +2428,10 @@ void ERR_load_SSL_strings(void);
# define SSL_R_REQUIRED_CIPHER_MISSING 215
# define SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING 342
# define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 345
# define SSL_R_SCT_VERIFICATION_FAILED 208
# define SSL_R_SERVERHELLO_TLSEXT 275
# define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 277
# define SSL_R_SET_FAILED 209
# define SSL_R_SHUTDOWN_WHILE_IN_INIT 407
# define SSL_R_SIGNATURE_ALGORITHMS_ERROR 360
# define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE 220

View File

@ -240,6 +240,12 @@ extern "C" {
/* ExtensionType value from RFC7301 */
# define TLSEXT_TYPE_application_layer_protocol_negotiation 16
/*
* Extension type for Certificate Transparency
* https://tools.ietf.org/html/rfc6962#section-3.3.1
*/
# define TLSEXT_TYPE_signed_certificate_timestamp 18
/*
* ExtensionType value for TLS padding extension.
* http://tools.ietf.org/html/draft-agl-tls-padding

View File

@ -70,6 +70,7 @@
static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_CHECK_SUITEB_CIPHER_LIST), "check_suiteb_cipher_list"},
{ERR_FUNC(SSL_F_CT_MOVE_SCTS), "CT_move_scts"},
{ERR_FUNC(SSL_F_D2I_SSL_SESSION), "d2i_SSL_SESSION"},
{ERR_FUNC(SSL_F_DANE_CTX_ENABLE), "dane_ctx_enable"},
{ERR_FUNC(SSL_F_DANE_MTYPE_SET), "dane_mtype_set"},
@ -169,12 +170,16 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_SSL_CREATE_CIPHER_LIST), "ssl_create_cipher_list"},
{ERR_FUNC(SSL_F_SSL_CTRL), "SSL_ctrl"},
{ERR_FUNC(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY), "SSL_CTX_check_private_key"},
{ERR_FUNC(SSL_F_SSL_CTX_GET_CT_VALIDATION_CALLBACK),
"SSL_CTX_get_ct_validation_callback"},
{ERR_FUNC(SSL_F_SSL_CTX_MAKE_PROFILES), "ssl_ctx_make_profiles"},
{ERR_FUNC(SSL_F_SSL_CTX_NEW), "SSL_CTX_new"},
{ERR_FUNC(SSL_F_SSL_CTX_SET_ALPN_PROTOS), "SSL_CTX_set_alpn_protos"},
{ERR_FUNC(SSL_F_SSL_CTX_SET_CIPHER_LIST), "SSL_CTX_set_cipher_list"},
{ERR_FUNC(SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE),
"SSL_CTX_set_client_cert_engine"},
{ERR_FUNC(SSL_F_SSL_CTX_SET_CT_VALIDATION_CALLBACK),
"SSL_CTX_set_ct_validation_callback"},
{ERR_FUNC(SSL_F_SSL_CTX_SET_PURPOSE), "SSL_CTX_set_purpose"},
{ERR_FUNC(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT),
"SSL_CTX_set_session_id_context"},
@ -203,6 +208,9 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_SSL_DANE_ENABLE), "SSL_dane_enable"},
{ERR_FUNC(SSL_F_SSL_DO_CONFIG), "ssl_do_config"},
{ERR_FUNC(SSL_F_SSL_DO_HANDSHAKE), "SSL_do_handshake"},
{ERR_FUNC(SSL_F_SSL_GET0_PEER_SCTS), "SSL_get0_peer_scts"},
{ERR_FUNC(SSL_F_SSL_GET_CT_VALIDATION_CALLBACK),
"SSL_get_ct_validation_callback"},
{ERR_FUNC(SSL_F_SSL_GET_NEW_SESSION), "ssl_get_new_session"},
{ERR_FUNC(SSL_F_SSL_GET_PREV_SESSION), "ssl_get_prev_session"},
{ERR_FUNC(SSL_F_SSL_GET_SERVER_CERT_INDEX), "ssl_get_server_cert_index"},
@ -243,6 +251,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_SSL_SET_ALPN_PROTOS), "SSL_set_alpn_protos"},
{ERR_FUNC(SSL_F_SSL_SET_CERT), "ssl_set_cert"},
{ERR_FUNC(SSL_F_SSL_SET_CIPHER_LIST), "SSL_set_cipher_list"},
{ERR_FUNC(SSL_F_SSL_SET_CT_VALIDATION_CALLBACK),
"SSL_set_ct_validation_callback"},
{ERR_FUNC(SSL_F_SSL_SET_FD), "SSL_set_fd"},
{ERR_FUNC(SSL_F_SSL_SET_PKEY), "ssl_set_pkey"},
{ERR_FUNC(SSL_F_SSL_SET_PURPOSE), "SSL_set_purpose"},
@ -270,6 +280,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY), "SSL_use_RSAPrivateKey"},
{ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1), "SSL_use_RSAPrivateKey_ASN1"},
{ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE), "SSL_use_RSAPrivateKey_file"},
{ERR_FUNC(SSL_F_SSL_VALIDATE_CT), "SSL_validate_ct"},
{ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN), "ssl_verify_cert_chain"},
{ERR_FUNC(SSL_F_SSL_WRITE), "SSL_write"},
{ERR_FUNC(SSL_F_STATE_MACHINE), "state_machine"},
@ -422,6 +433,8 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
{ERR_REASON(SSL_R_COOKIE_GEN_CALLBACK_FAILURE),
"cookie gen callback failure"},
{ERR_REASON(SSL_R_COOKIE_MISMATCH), "cookie mismatch"},
{ERR_REASON(SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED),
"custom ext handler already installed"},
{ERR_REASON(SSL_R_DANE_ALREADY_ENABLED), "dane already enabled"},
{ERR_REASON(SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL),
"dane cannot override mtype full"},
@ -576,9 +589,11 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"required compresssion algorithm missing"},
{ERR_REASON(SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING),
"scsv received when renegotiating"},
{ERR_REASON(SSL_R_SCT_VERIFICATION_FAILED), "sct verification failed"},
{ERR_REASON(SSL_R_SERVERHELLO_TLSEXT), "serverhello tlsext"},
{ERR_REASON(SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED),
"session id context uninitialized"},
{ERR_REASON(SSL_R_SET_FAILED), "set failed"},
{ERR_REASON(SSL_R_SHUTDOWN_WHILE_IN_INIT), "shutdown while in init"},
{ERR_REASON(SSL_R_SIGNATURE_ALGORITHMS_ERROR),
"signature algorithms error"},

View File

@ -159,6 +159,9 @@
# include <openssl/engine.h>
#endif
#include <openssl/async.h>
#ifndef OPENSSL_NO_CT
# include <openssl/ct.h>
#endif
const char SSL_version_str[] = OPENSSL_VERSION_TEXT;
@ -740,6 +743,12 @@ SSL *SSL_new(SSL_CTX *ctx)
s->job = NULL;
#ifndef OPENSSL_NO_CT
if (!SSL_set_ct_validation_callback(s, ctx->ct_validation_callback,
ctx->ct_validation_callback_arg))
goto err;
#endif
return (s);
err:
SSL_free(s);
@ -1041,6 +1050,10 @@ void SSL_free(SSL *s)
#endif /* OPENSSL_NO_EC */
sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, X509_EXTENSION_free);
sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
#ifndef OPENSSL_NO_CT
SCT_LIST_free(s->scts);
OPENSSL_free(s->tlsext_scts);
#endif
OPENSSL_free(s->tlsext_ocsp_resp);
OPENSSL_free(s->alpn_client_proto_list);
@ -2321,7 +2334,11 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
ret->cert_store = X509_STORE_new();
if (ret->cert_store == NULL)
goto err;
#ifndef OPENSSL_NO_CT
ret->ctlog_store = CTLOG_STORE_new();
if (ret->ctlog_store == NULL)
goto err;
#endif
if (!ssl_create_cipher_list(ret->method,
&ret->cipher_list, &ret->cipher_list_by_id,
SSL_DEFAULT_CIPHER_LIST, ret->cert)
@ -2439,6 +2456,9 @@ void SSL_CTX_free(SSL_CTX *a)
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data);
lh_SSL_SESSION_free(a->sessions);
X509_STORE_free(a->cert_store);
#ifndef OPENSSL_NO_CT
CTLOG_STORE_free(a->ctlog_store);
#endif
sk_SSL_CIPHER_free(a->cipher_list);
sk_SSL_CIPHER_free(a->cipher_list_by_id);
ssl_cert_free(a->cert);
@ -3796,3 +3816,276 @@ STACK_OF(X509) *SSL_get0_verified_chain(const SSL *s)
}
IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER, ssl_cipher_id);
#ifndef OPENSSL_NO_CT
/*
* Moves SCTs from the |src| stack to the |dst| stack.
* The source of each SCT will be set to |origin|.
* If |dst| points to a NULL pointer, a new stack will be created and owned by
* the caller.
* Returns the number of SCTs moved, or a negative integer if an error occurs.
*/
static int ct_move_scts(STACK_OF(SCT) **dst, STACK_OF(SCT) *src, sct_source_t origin)
{
int scts_moved = 0;
SCT *sct = NULL;
if (*dst == NULL) {
*dst = sk_SCT_new_null();
if (*dst == NULL) {
SSLerr(SSL_F_CT_MOVE_SCTS, ERR_R_MALLOC_FAILURE);
goto err;
}
}
while ((sct = sk_SCT_pop(src)) != NULL) {
if (SCT_set_source(sct, origin) != 1)
goto err;
if (sk_SCT_push(*dst, sct) <= 0)
goto err;
scts_moved += 1;
}
return scts_moved;
err:
if (sct != NULL)
sk_SCT_push(src, sct); /* Put the SCT back */
return scts_moved;
}
/*
* Look for data collected during ServerHello and parse if found.
* Return 1 on success, 0 on failure.
*/
static int ct_extract_tls_extension_scts(SSL *s)
{
int scts_extracted = 0;
if (s->tlsext_scts != NULL) {
const unsigned char *p = s->tlsext_scts;
STACK_OF(SCT) *scts = o2i_SCT_LIST(NULL, &p, s->tlsext_scts_len);
scts_extracted = ct_move_scts(&s->scts, scts, SCT_SOURCE_TLS_EXTENSION);
SCT_LIST_free(scts);
}
return scts_extracted;
}
/*
* Checks for an OCSP response and then attempts to extract any SCTs found if it
* contains an SCT X509 extension. They will be stored in |s->scts|.
* Returns:
* - The number of SCTs extracted, assuming an OCSP response exists.
* - 0 if no OCSP response exists or it contains no SCTs.
* - A negative integer if an error occurs.
*/
static int ct_extract_ocsp_response_scts(SSL *s)
{
int scts_extracted = 0;
const unsigned char *p;
OCSP_BASICRESP *br = NULL;
OCSP_RESPONSE *rsp = NULL;
STACK_OF(SCT) *scts = NULL;
int i;
if (s->tlsext_ocsp_resp == NULL || s->tlsext_ocsp_resplen == 0)
goto err;
p = s->tlsext_ocsp_resp;
rsp = d2i_OCSP_RESPONSE(NULL, &p, s->tlsext_ocsp_resplen);
if (rsp == NULL)
goto err;
br = OCSP_response_get1_basic(rsp);
if (br == NULL)
goto err;
for (i = 0; i < OCSP_resp_count(br); ++i) {
OCSP_SINGLERESP *single = OCSP_resp_get0(br, i);
if (single == NULL)
continue;
scts = OCSP_SINGLERESP_get1_ext_d2i(single, NID_ct_cert_scts, NULL, NULL);
scts_extracted = ct_move_scts(&s->scts, scts,
SCT_SOURCE_OCSP_STAPLED_RESPONSE);
if (scts_extracted < 0)
goto err;
}
err:
SCT_LIST_free(scts);
OCSP_BASICRESP_free(br);
OCSP_RESPONSE_free(rsp);
return scts_extracted;
}
/*
* Attempts to extract SCTs from the peer certificate.
* Return the number of SCTs extracted, or a negative integer if an error
* occurs.
*/
static int ct_extract_x509v3_extension_scts(SSL *s)
{
int scts_extracted = 0;
X509 *cert = SSL_get_peer_certificate(s);
if (cert != NULL) {
STACK_OF(SCT) *scts =
X509_get_ext_d2i(cert, NID_ct_precert_scts, NULL, NULL);
scts_extracted =
ct_move_scts(&s->scts, scts, SCT_SOURCE_X509V3_EXTENSION);
SCT_LIST_free(scts);
}
return scts_extracted;
}
/*
* Attempts to find all received SCTs by checking TLS extensions, the OCSP
* response (if it exists) and X509v3 extensions in the certificate.
* Returns NULL if an error occurs.
*/
const STACK_OF(SCT) *SSL_get0_peer_scts(SSL *s)
{
if (!s->scts_parsed) {
if (ct_extract_tls_extension_scts(s) < 0 ||
ct_extract_ocsp_response_scts(s) < 0 ||
ct_extract_x509v3_extension_scts(s) < 0)
goto err;
s->scts_parsed = 1;
}
return s->scts;
err:
return NULL;
}
int SSL_set_ct_validation_callback(SSL *s, ct_validation_cb callback, void *arg)
{
int ret = 0;
/*
* Since code exists that uses the custom extension handler for CT, look
* for this and throw an error if they have already registered to use CT.
*/
if (callback != NULL && SSL_CTX_has_client_custom_ext(s->ctx,
TLSEXT_TYPE_signed_certificate_timestamp)) {
SSLerr(SSL_F_SSL_SET_CT_VALIDATION_CALLBACK,
SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED);
goto err;
}
s->ct_validation_callback = callback;
s->ct_validation_callback_arg = arg;
if (callback != NULL) {
/* If we are validating CT, then we MUST accept SCTs served via OCSP */
if (!SSL_set_tlsext_status_type(s, TLSEXT_STATUSTYPE_ocsp))
goto err;
}
ret = 1;
err:
return ret;
}
int SSL_CTX_set_ct_validation_callback(SSL_CTX *ctx, ct_validation_cb callback,
void *arg)
{
int ret = 0;
/*
* Since code exists that uses the custom extension handler for CT, look for
* this and throw an error if they have already registered to use CT.
*/
if (callback != NULL && SSL_CTX_has_client_custom_ext(ctx,
TLSEXT_TYPE_signed_certificate_timestamp)) {
SSLerr(SSL_F_SSL_CTX_SET_CT_VALIDATION_CALLBACK,
SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED);
goto err;
}
ctx->ct_validation_callback = callback;
ctx->ct_validation_callback_arg = arg;
ret = 1;
err:
return ret;
}
ct_validation_cb SSL_get_ct_validation_callback(const SSL *s)
{
return s->ct_validation_callback;
}
ct_validation_cb SSL_CTX_get_ct_validation_callback(const SSL_CTX *ctx)
{
return ctx->ct_validation_callback;
}
int SSL_validate_ct(SSL *s)
{
int ret = 0;
X509 *cert = SSL_get_peer_certificate(s);
X509 *issuer = NULL;
CT_POLICY_EVAL_CTX *ctx = NULL;
const STACK_OF(SCT) *scts;
/* If no callback is set, attempt no validation - just return success */
if (s->ct_validation_callback == NULL)
return 1;
if (cert == NULL) {
SSLerr(SSL_F_SSL_VALIDATE_CT, SSL_R_NO_CERTIFICATE_ASSIGNED);
goto end;
}
if (s->verified_chain != NULL && sk_X509_num(s->verified_chain) > 1)
issuer = sk_X509_value(s->verified_chain, 1);
ctx = CT_POLICY_EVAL_CTX_new();
if (ctx == NULL) {
SSLerr(SSL_F_SSL_VALIDATE_CT, ERR_R_MALLOC_FAILURE);
goto end;
}
CT_POLICY_EVAL_CTX_set0_cert(ctx, cert);
CT_POLICY_EVAL_CTX_set0_issuer(ctx, issuer);
CT_POLICY_EVAL_CTX_set0_log_store(ctx, s->ctx->ctlog_store);
scts = SSL_get0_peer_scts(s);
if (SCT_LIST_validate(scts, ctx) != 1) {
SSLerr(SSL_F_SSL_VALIDATE_CT, SSL_R_SCT_VERIFICATION_FAILED);
goto end;
}
ret = s->ct_validation_callback(ctx, scts, s->ct_validation_callback_arg);
if (ret < 0)
ret = 0; /* This function returns 0 on failure */
end:
CT_POLICY_EVAL_CTX_free(ctx);
return ret;
}
int SSL_CTX_set_default_ctlog_list_file(SSL_CTX *ctx)
{
int ret = CTLOG_STORE_load_default_file(ctx->ctlog_store);
/* Clear any errors if the default file does not exist */
ERR_clear_error();
return ret;
}
int SSL_CTX_set_ctlog_list_file(SSL_CTX *ctx, const char *path)
{
return CTLOG_STORE_load_file(ctx->ctlog_store, path);
}
#endif

View File

@ -164,7 +164,9 @@
# include <openssl/ssl.h>
# include <openssl/async.h>
# include <openssl/symhacks.h>
# ifndef OPENSSL_NO_CT
# include <openssl/ct.h>
# endif
#include "record/record.h"
#include "statem/statem.h"
#include "packet_locl.h"
@ -815,6 +817,16 @@ struct ssl_ctx_st {
int quiet_shutdown;
# ifndef OPENSSL_NO_CT
CTLOG_STORE *ctlog_store; /* CT Log Store */
/*
* Validates that the SCTs (Signed Certificate Timestamps) are sufficient.
* If they are not, the connection should be aborted.
*/
ct_validation_cb ct_validation_callback;
void *ct_validation_callback_arg;
# endif
/*
* Maximum amount of data to send in one fragment. actual record size can
* be more than this due to padding and MAC overheads.
@ -1088,6 +1100,26 @@ struct ssl_st {
/* certificate status request info */
/* Status type or -1 if no status type */
int tlsext_status_type;
# ifndef OPENSSL_NO_CT
/*
* Validates that the SCTs (Signed Certificate Timestamps) are sufficient.
* If they are not, the connection should be aborted.
*/
ct_validation_cb ct_validation_callback;
/* User-supplied argument tha tis passed to the ct_validation_callback */
void *ct_validation_callback_arg;
/*
* Consolidated stack of SCTs from all sources.
* Lazily populated by CT_get_peer_scts(SSL*)
*/
STACK_OF(SCT) *scts;
/* Raw extension data, if seen */
unsigned char *tlsext_scts;
/* Length of raw extension data, if seen */
uint16_t tlsext_scts_len;
/* Have we attempted to find/parse SCTs yet? */
int scts_parsed;
# endif
/* Expect OCSP CertificateStatus message */
int tlsext_status_expected;
/* OCSP status request only */
@ -2037,6 +2069,10 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain,
int idx);
void tls1_set_cert_validity(SSL *s);
#ifndef OPENSSL_NO_CT
__owur int SSL_validate_ct(SSL *s);
#endif
# ifndef OPENSSL_NO_DH
__owur DH *ssl_get_auto_dh(SSL *s);
# endif

View File

@ -2058,6 +2058,15 @@ MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt)
}
}
#ifndef OPENSSL_NO_CT
if (s->ct_validation_callback != NULL) {
if (!SSL_validate_ct(s)) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
return MSG_PROCESS_ERROR;
}
}
#endif
#ifndef OPENSSL_NO_SCTP
/* Only applies to renegotiation */
if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))

View File

@ -54,11 +54,14 @@
/* Custom extension utility functions */
#ifndef OPENSSL_NO_CT
# include <openssl/ct.h>
#endif
#include "ssl_locl.h"
/* Find a custom extension from the list. */
static custom_ext_method *custom_ext_find(custom_ext_methods *exts,
static custom_ext_method *custom_ext_find(const custom_ext_methods *exts,
unsigned int ext_type)
{
size_t i;
@ -211,8 +214,12 @@ static int custom_ext_meth_add(custom_ext_methods *exts,
*/
if (!add_cb && free_cb)
return 0;
/* Don't add if extension supported internally. */
if (SSL_extension_supported(ext_type))
/*
* Don't add if extension supported internally, but make exception
* for extension types that previously were not supported, but now are.
*/
if (SSL_extension_supported(ext_type) &&
ext_type != TLSEXT_TYPE_signed_certificate_timestamp)
return 0;
/* Extension type must fit in 16 bits */
if (ext_type > 0xffff)
@ -241,6 +248,12 @@ static int custom_ext_meth_add(custom_ext_methods *exts,
return 1;
}
/* Return true if a client custom extension exists, false otherwise */
int SSL_CTX_has_client_custom_ext(const SSL_CTX *ctx, unsigned int ext_type)
{
return custom_ext_find(&ctx->cert->cli_ext, ext_type) != NULL;
}
/* Application level functions to add custom extension callbacks */
int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
custom_ext_add_cb add_cb,
@ -249,8 +262,25 @@ int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
custom_ext_parse_cb parse_cb,
void *parse_arg)
{
return custom_ext_meth_add(&ctx->cert->cli_ext, ext_type,
add_cb, free_cb, add_arg, parse_cb, parse_arg);
int ret = custom_ext_meth_add(&ctx->cert->cli_ext, ext_type, add_cb,
free_cb, add_arg, parse_cb, parse_arg);
if (ret != 1)
goto end;
#ifndef OPENSSL_NO_CT
/*
* We don't want applications registering callbacks for SCT extensions
* whilst simultaneously using the built-in SCT validation features, as
* these two things may not play well together.
*/
if (ext_type == TLSEXT_TYPE_signed_certificate_timestamp &&
SSL_CTX_get_ct_validation_callback(ctx) != NULL) {
ret = 0;
}
#endif
end:
return ret;
}
int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
@ -280,6 +310,7 @@ int SSL_extension_supported(unsigned int ext_type)
case TLSEXT_TYPE_signature_algorithms:
case TLSEXT_TYPE_srp:
case TLSEXT_TYPE_status_request:
case TLSEXT_TYPE_signed_certificate_timestamp:
case TLSEXT_TYPE_use_srtp:
#ifdef TLSEXT_TYPE_encrypt_then_mac
case TLSEXT_TYPE_encrypt_then_mac:

View File

@ -120,6 +120,9 @@
# include <openssl/bn.h>
#endif
#include "ssl_locl.h"
#ifndef OPENSSL_NO_CT
# include <openssl/ct.h>
#endif
static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
const unsigned char *sess_id, int sesslen,
@ -1449,6 +1452,12 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
#ifdef TLSEXT_TYPE_encrypt_then_mac
s2n(TLSEXT_TYPE_encrypt_then_mac, ret);
s2n(0, ret);
#endif
#ifndef OPENSSL_NO_CT
if (s->ct_validation_callback != NULL) {
s2n(TLSEXT_TYPE_signed_certificate_timestamp, ret);
s2n(0, ret);
}
#endif
s2n(TLSEXT_TYPE_extended_master_secret, ret);
s2n(0, ret);
@ -2414,6 +2423,30 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
/* Set flag to expect CertificateStatus message */
s->tlsext_status_expected = 1;
}
#ifndef OPENSSL_NO_CT
/*
* Only take it if we asked for it - i.e if there is no CT validation
* callback set, then a custom extension MAY be processing it, so we
* need to let control continue to flow to that.
*/
else if (type == TLSEXT_TYPE_signed_certificate_timestamp &&
s->ct_validation_callback != NULL) {
/* Simply copy it off for later processing */
if (s->tlsext_scts != NULL) {
OPENSSL_free(s->tlsext_scts);
s->tlsext_scts = NULL;
}
s->tlsext_scts_len = size;
if (size > 0) {
s->tlsext_scts = OPENSSL_malloc(size);
if (s->tlsext_scts == NULL) {
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
}
memcpy(s->tlsext_scts, data, size);
}
}
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
else if (type == TLSEXT_TYPE_next_proto_neg &&
s->s3->tmp.finish_md_len == 0) {

View File

@ -498,6 +498,7 @@ static ssl_trace_tbl ssl_exts_tbl[] = {
{TLSEXT_TYPE_session_ticket, "session_ticket"},
{TLSEXT_TYPE_renegotiate, "renegotiate"},
{TLSEXT_TYPE_next_proto_neg, "next_proto_neg"},
{TLSEXT_TYPE_signed_certificate_timestamp, "signed_certificate_timestamps"},
{TLSEXT_TYPE_padding, "padding"},
{TLSEXT_TYPE_encrypt_then_mac, "encrypt_then_mac"},
{TLSEXT_TYPE_extended_master_secret, "extended_master_secret"}

View File

@ -1586,8 +1586,10 @@ int main(int argc, char *argv[])
if ((!SSL_CTX_load_verify_locations(s_ctx, CAfile, CApath)) ||
(!SSL_CTX_set_default_verify_paths(s_ctx)) ||
(!SSL_CTX_set_default_ctlog_list_file(s_ctx)) ||
(!SSL_CTX_load_verify_locations(c_ctx, CAfile, CApath)) ||
(!SSL_CTX_set_default_verify_paths(c_ctx))) {
(!SSL_CTX_set_default_verify_paths(c_ctx)) ||
(!SSL_CTX_set_default_ctlog_list_file(c_ctx))) {
/* fprintf(stderr,"SSL_load_verify_locations\n"); */
ERR_print_errors(bio_err);
/* goto end; */

View File

@ -422,3 +422,11 @@ SSL_get_default_passwd_cb_userdata 477 1_1_0 EXIST::FUNCTION:
SSL_get_default_passwd_cb 478 1_1_0 EXIST::FUNCTION:
SSL_CTX_get_default_passwd_cb_userdata 479 1_1_0 EXIST::FUNCTION:
SSL_CTX_get_default_passwd_cb 480 1_1_0 EXIST::FUNCTION:
SSL_CTX_get_ct_validation_callback 481 1_1_0 EXIST::FUNCTION:CT
SSL_get_ct_validation_callback 482 1_1_0 EXIST::FUNCTION:CT
SSL_CTX_has_client_custom_ext 483 1_1_0 EXIST::FUNCTION:
SSL_CTX_set_ctlog_list_file 484 1_1_0 EXIST::FUNCTION:CT
SSL_CTX_set_default_ctlog_list_file 485 1_1_0 EXIST::FUNCTION:CT
SSL_set_ct_validation_callback 486 1_1_0 EXIST::FUNCTION:CT
SSL_get0_peer_scts 487 1_1_0 EXIST::FUNCTION:CT
SSL_CTX_set_ct_validation_callback 488 1_1_0 EXIST::FUNCTION:CT