Commit ed29e82a authored by Rob Percival's avatar Rob Percival Committed by Rich Salz
Browse files

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: default avatarBen Laurie <ben@openssl.org>
Reviewed-by: default avatarRich Salz <rsalz@openssl.org>
parent ddb4c047
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
@@ -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
+6 −0
Original line number Diff line number Diff line
@@ -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
+15 −0
Original line number Diff line number Diff line
@@ -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"},
+294 −1
Original line number Diff line number Diff line
@@ -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
+37 −1
Original line number Diff line number Diff line
@@ -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
Loading