|SSL_SESSION_from_bytes| now takes an |SSL_CTX*|, from which it uses the |X509_METHOD| and buffer pool. This is our API so we can do this. This also requires adding an |SSL_CTX*| argument to |SSL_SESSION_new| for the same reason. However, |SSL_SESSION_new| already has very few callers (and none in third-party code that I can see) so I think we can get away with this. Change-Id: I1337cd2bd8cff03d4b9405ea3146b3b59584aa72 Reviewed-on: https://boringssl-review.googlesource.com/13584 Reviewed-by: Adam Langley <alangley@gmail.com> Commit-Queue: Adam Langley <alangley@gmail.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>kris/onging/CECPQ3_patch15
@@ -17,9 +17,18 @@ | |||||
#include <openssl/mem.h> | #include <openssl/mem.h> | ||||
#include <openssl/ssl.h> | #include <openssl/ssl.h> | ||||
struct GlobalState { | |||||
GlobalState() : ctx(SSL_CTX_new(TLS_method())) {} | |||||
bssl::UniquePtr<SSL_CTX> ctx; | |||||
}; | |||||
static GlobalState g_state; | |||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { | ||||
// Parse in our session. | // Parse in our session. | ||||
bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(buf, len)); | |||||
bssl::UniquePtr<SSL_SESSION> session( | |||||
SSL_SESSION_from_bytes(buf, len, g_state.ctx.get())); | |||||
// If the format was invalid, just return. | // If the format was invalid, just return. | ||||
if (!session) { | if (!session) { | ||||
@@ -1570,9 +1570,9 @@ DECLARE_LHASH_OF(SSL_SESSION) | |||||
DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) | DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) | ||||
/* SSL_SESSION_new returns a newly-allocated blank |SSL_SESSION| or NULL on | /* SSL_SESSION_new returns a newly-allocated blank |SSL_SESSION| or NULL on | ||||
* error. This may be useful in writing tests but otherwise should not be | |||||
* used outside the library. */ | |||||
OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_new(void); | |||||
* error. This may be useful when writing tests but should otherwise not be | |||||
* used. */ | |||||
OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx); | |||||
/* SSL_SESSION_up_ref increments the reference count of |session| and returns | /* SSL_SESSION_up_ref increments the reference count of |session| and returns | ||||
* one. */ | * one. */ | ||||
@@ -1597,8 +1597,8 @@ OPENSSL_EXPORT int SSL_SESSION_to_bytes_for_ticket(const SSL_SESSION *in, | |||||
/* SSL_SESSION_from_bytes parses |in_len| bytes from |in| as an SSL_SESSION. It | /* SSL_SESSION_from_bytes parses |in_len| bytes from |in| as an SSL_SESSION. It | ||||
* returns a newly-allocated |SSL_SESSION| on success or NULL on error. */ | * returns a newly-allocated |SSL_SESSION| on success or NULL on error. */ | ||||
OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, | |||||
size_t in_len); | |||||
OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_from_bytes( | |||||
const uint8_t *in, size_t in_len, const SSL_CTX *ctx); | |||||
/* SSL_SESSION_get_version returns a string describing the TLS version |session| | /* SSL_SESSION_get_version returns a string describing the TLS version |session| | ||||
* was established at. For example, "TLSv1.2" or "SSLv3". */ | * was established at. For example, "TLSv1.2" or "SSLv3". */ | ||||
@@ -3734,6 +3734,8 @@ struct ssl_session_st { | |||||
* certificate. */ | * certificate. */ | ||||
STACK_OF(CRYPTO_BUFFER) *certs; | STACK_OF(CRYPTO_BUFFER) *certs; | ||||
const SSL_X509_METHOD *x509_method; | |||||
/* x509_peer is the peer's certificate. */ | /* x509_peer is the peer's certificate. */ | ||||
X509 *x509_peer; | X509 *x509_peer; | ||||
@@ -1077,7 +1077,7 @@ static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) { | |||||
if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0 || | if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0 || | ||||
CBS_len(&cbs) != 0 || | CBS_len(&cbs) != 0 || | ||||
!ssl_session_x509_cache_objects(ssl->s3->new_session)) { | |||||
!ssl->ctx->x509_method->session_cache_objects(ssl->s3->new_session)) { | |||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | ||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | ||||
return -1; | return -1; | ||||
@@ -483,10 +483,10 @@ int ssl3_accept(SSL_HANDSHAKE *hs) { | |||||
* now. */ | * now. */ | ||||
if (ssl->s3->new_session != NULL && | if (ssl->s3->new_session != NULL && | ||||
ssl->retain_only_sha256_of_client_certs) { | ssl->retain_only_sha256_of_client_certs) { | ||||
X509_free(ssl->s3->new_session->x509_peer); | |||||
ssl->s3->new_session->x509_peer = NULL; | |||||
sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free); | |||||
ssl->s3->new_session->x509_chain = NULL; | |||||
sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, | |||||
CRYPTO_BUFFER_free); | |||||
ssl->s3->new_session->certs = NULL; | |||||
ssl->ctx->x509_method->session_clear(ssl->s3->new_session); | |||||
} | } | ||||
SSL_SESSION_free(ssl->s3->established_session); | SSL_SESSION_free(ssl->s3->established_session); | ||||
@@ -1472,7 +1472,7 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { | |||||
} | } | ||||
if (CBS_len(&certificate_msg) != 0 || | if (CBS_len(&certificate_msg) != 0 || | ||||
!ssl_session_x509_cache_objects(ssl->s3->new_session)) { | |||||
!ssl->ctx->x509_method->session_cache_objects(ssl->s3->new_session)) { | |||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | ||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | ||||
return -1; | return -1; | ||||
@@ -804,12 +804,6 @@ void ssl_write_buffer_clear(SSL *ssl); | |||||
* configured and zero otherwise. */ | * configured and zero otherwise. */ | ||||
int ssl_has_certificate(const SSL *ssl); | int ssl_has_certificate(const SSL *ssl); | ||||
/* ssl_session_x509_cache_objects fills out |sess->x509_peer| and | |||||
* |sess->x509_chain| from |sess->certs| and erases | |||||
* |sess->x509_chain_without_leaf|. It returns one on success or zero on | |||||
* error. */ | |||||
int ssl_session_x509_cache_objects(SSL_SESSION *sess); | |||||
/* ssl_parse_cert_chain parses a certificate list from |cbs| in the format used | /* ssl_parse_cert_chain parses a certificate list from |cbs| in the format used | ||||
* by a TLS Certificate message. On success, it returns a newly-allocated | * by a TLS Certificate message. On success, it returns a newly-allocated | ||||
* |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets | * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets | ||||
@@ -1433,8 +1427,22 @@ struct ssl_x509_method_st { | |||||
/* cert_flush_cached_chain drops any cached |X509|-based leaf certificate | /* cert_flush_cached_chain drops any cached |X509|-based leaf certificate | ||||
* from |cert|. */ | * from |cert|. */ | ||||
void (*cert_flush_cached_leaf)(CERT *cert); | void (*cert_flush_cached_leaf)(CERT *cert); | ||||
/* session_cache_objects fills out |sess->x509_peer| and |sess->x509_chain| | |||||
* from |sess->certs| and erases |sess->x509_chain_without_leaf|. It returns | |||||
* one on success or zero on error. */ | |||||
int (*session_cache_objects)(SSL_SESSION *session); | |||||
/* session_dup duplicates any needed fields from |session| to |new_session|. | |||||
* It returns one on success or zero on error. */ | |||||
int (*session_dup)(SSL_SESSION *new_session, const SSL_SESSION *session); | |||||
/* session_clear frees any X509-related state from |session|. */ | |||||
void (*session_clear)(SSL_SESSION *session); | |||||
}; | }; | ||||
/* ssl_noop_x509_method is implements the |ssl_x509_method_st| functions by | |||||
* doing nothing. */ | |||||
extern const struct ssl_x509_method_st ssl_noop_x509_method; | |||||
/* ssl_crypto_x509_method provides the |ssl_x509_method_st| functions using | /* ssl_crypto_x509_method provides the |ssl_x509_method_st| functions using | ||||
* crypto/x509. */ | * crypto/x509. */ | ||||
extern const struct ssl_x509_method_st ssl_crypto_x509_method; | extern const struct ssl_x509_method_st ssl_crypto_x509_method; | ||||
@@ -1911,6 +1919,15 @@ int ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey); | |||||
int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server); | int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server); | ||||
int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session); | int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session); | ||||
/* ssl_session_new returns a newly-allocated blank |SSL_SESSION| or NULL on | |||||
* error. */ | |||||
SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method); | |||||
/* SSL_SESSION_parse parses an |SSL_SESSION| from |cbs| and advances |cbs| over | |||||
* the parsed data. */ | |||||
SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, | |||||
CRYPTO_BUFFER_POOL *pool); | |||||
/* ssl_session_is_context_valid returns one if |session|'s session ID context | /* ssl_session_is_context_valid returns one if |session|'s session ID context | ||||
* matches the one set on |ssl| and zero otherwise. */ | * matches the one set on |ssl| and zero otherwise. */ | ||||
int ssl_session_is_context_valid(const SSL *ssl, const SSL_SESSION *session); | int ssl_session_is_context_valid(const SSL *ssl, const SSL_SESSION *session); | ||||
@@ -575,8 +575,9 @@ static int SSL_SESSION_parse_u16(CBS *cbs, uint16_t *out, unsigned tag, | |||||
return 1; | return 1; | ||||
} | } | ||||
static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { | |||||
SSL_SESSION *ret = SSL_SESSION_new(); | |||||
SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, | |||||
CRYPTO_BUFFER_POOL *pool) { | |||||
SSL_SESSION *ret = ssl_session_new(x509_method); | |||||
if (ret == NULL) { | if (ret == NULL) { | ||||
goto err; | goto err; | ||||
} | } | ||||
@@ -738,7 +739,7 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { | |||||
if (has_peer) { | if (has_peer) { | ||||
/* TODO(agl): this should use the |SSL_CTX|'s pool. */ | /* TODO(agl): this should use the |SSL_CTX|'s pool. */ | ||||
CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, NULL); | |||||
CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, pool); | |||||
if (buffer == NULL || | if (buffer == NULL || | ||||
!sk_CRYPTO_BUFFER_push(ret->certs, buffer)) { | !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) { | ||||
CRYPTO_BUFFER_free(buffer); | CRYPTO_BUFFER_free(buffer); | ||||
@@ -756,7 +757,7 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { | |||||
} | } | ||||
/* TODO(agl): this should use the |SSL_CTX|'s pool. */ | /* TODO(agl): this should use the |SSL_CTX|'s pool. */ | ||||
CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, NULL); | |||||
CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, pool); | |||||
if (buffer == NULL || | if (buffer == NULL || | ||||
!sk_CRYPTO_BUFFER_push(ret->certs, buffer)) { | !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) { | ||||
CRYPTO_BUFFER_free(buffer); | CRYPTO_BUFFER_free(buffer); | ||||
@@ -766,7 +767,7 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { | |||||
} | } | ||||
} | } | ||||
if (!ssl_session_x509_cache_objects(ret)) { | |||||
if (!x509_method->session_cache_objects(ret)) { | |||||
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); | ||||
goto err; | goto err; | ||||
} | } | ||||
@@ -811,10 +812,11 @@ err: | |||||
return NULL; | return NULL; | ||||
} | } | ||||
SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len) { | |||||
SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len, | |||||
const SSL_CTX *ctx) { | |||||
CBS cbs; | CBS cbs; | ||||
CBS_init(&cbs, in, in_len); | CBS_init(&cbs, in, in_len); | ||||
SSL_SESSION *ret = SSL_SESSION_parse(&cbs); | |||||
SSL_SESSION *ret = SSL_SESSION_parse(&cbs, ctx->x509_method, ctx->pool); | |||||
if (ret == NULL) { | if (ret == NULL) { | ||||
return NULL; | return NULL; | ||||
} | } | ||||
@@ -825,25 +827,3 @@ SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len) { | |||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { | |||||
if (length < 0) { | |||||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |||||
return NULL; | |||||
} | |||||
CBS cbs; | |||||
CBS_init(&cbs, *pp, length); | |||||
SSL_SESSION *ret = SSL_SESSION_parse(&cbs); | |||||
if (ret == NULL) { | |||||
return NULL; | |||||
} | |||||
if (a) { | |||||
SSL_SESSION_free(*a); | |||||
*a = ret; | |||||
} | |||||
*pp = CBS_data(&cbs); | |||||
return ret; | |||||
} |
@@ -573,14 +573,3 @@ void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) { | |||||
void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *data) { | void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *data) { | ||||
ctx->default_passwd_callback_userdata = data; | ctx->default_passwd_callback_userdata = data; | ||||
} | } | ||||
SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) { | |||||
return ASN1_d2i_bio_of(SSL_SESSION, SSL_SESSION_new, d2i_SSL_SESSION, bio, | |||||
out); | |||||
} | |||||
int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session) { | |||||
return ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bio, session); | |||||
} | |||||
IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION) |
@@ -160,7 +160,7 @@ static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session); | |||||
static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session); | static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session); | ||||
static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock); | static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock); | ||||
SSL_SESSION *SSL_SESSION_new(void) { | |||||
SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method) { | |||||
SSL_SESSION *session = OPENSSL_malloc(sizeof(SSL_SESSION)); | SSL_SESSION *session = OPENSSL_malloc(sizeof(SSL_SESSION)); | ||||
if (session == NULL) { | if (session == NULL) { | ||||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | ||||
@@ -168,6 +168,7 @@ SSL_SESSION *SSL_SESSION_new(void) { | |||||
} | } | ||||
OPENSSL_memset(session, 0, sizeof(SSL_SESSION)); | OPENSSL_memset(session, 0, sizeof(SSL_SESSION)); | ||||
session->x509_method = x509_method; | |||||
session->verify_result = X509_V_ERR_INVALID_CALL; | session->verify_result = X509_V_ERR_INVALID_CALL; | ||||
session->references = 1; | session->references = 1; | ||||
session->timeout = SSL_DEFAULT_SESSION_TIMEOUT; | session->timeout = SSL_DEFAULT_SESSION_TIMEOUT; | ||||
@@ -177,8 +178,12 @@ SSL_SESSION *SSL_SESSION_new(void) { | |||||
return session; | return session; | ||||
} | } | ||||
SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx) { | |||||
return ssl_session_new(ctx->x509_method); | |||||
} | |||||
SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { | SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { | ||||
SSL_SESSION *new_session = SSL_SESSION_new(); | |||||
SSL_SESSION *new_session = ssl_session_new(session->x509_method); | |||||
if (new_session == NULL) { | if (new_session == NULL) { | ||||
goto err; | goto err; | ||||
} | } | ||||
@@ -214,16 +219,11 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { | |||||
CRYPTO_BUFFER_up_ref(buffer); | CRYPTO_BUFFER_up_ref(buffer); | ||||
} | } | ||||
} | } | ||||
if (session->x509_peer != NULL) { | |||||
X509_up_ref(session->x509_peer); | |||||
new_session->x509_peer = session->x509_peer; | |||||
} | |||||
if (session->x509_chain != NULL) { | |||||
new_session->x509_chain = X509_chain_up_ref(session->x509_chain); | |||||
if (new_session->x509_chain == NULL) { | |||||
goto err; | |||||
} | |||||
if (!session->x509_method->session_dup(new_session, session)) { | |||||
goto err; | |||||
} | } | ||||
new_session->verify_result = session->verify_result; | new_session->verify_result = session->verify_result; | ||||
new_session->ocsp_response_length = session->ocsp_response_length; | new_session->ocsp_response_length = session->ocsp_response_length; | ||||
@@ -367,9 +367,7 @@ void SSL_SESSION_free(SSL_SESSION *session) { | |||||
OPENSSL_cleanse(session->master_key, sizeof(session->master_key)); | OPENSSL_cleanse(session->master_key, sizeof(session->master_key)); | ||||
OPENSSL_cleanse(session->session_id, sizeof(session->session_id)); | OPENSSL_cleanse(session->session_id, sizeof(session->session_id)); | ||||
sk_CRYPTO_BUFFER_pop_free(session->certs, CRYPTO_BUFFER_free); | sk_CRYPTO_BUFFER_pop_free(session->certs, CRYPTO_BUFFER_free); | ||||
X509_free(session->x509_peer); | |||||
sk_X509_pop_free(session->x509_chain, X509_free); | |||||
sk_X509_pop_free(session->x509_chain_without_leaf, X509_free); | |||||
session->x509_method->session_clear(session); | |||||
OPENSSL_free(session->tlsext_hostname); | OPENSSL_free(session->tlsext_hostname); | ||||
OPENSSL_free(session->tlsext_tick); | OPENSSL_free(session->tlsext_tick); | ||||
OPENSSL_free(session->tlsext_signed_cert_timestamp_list); | OPENSSL_free(session->tlsext_signed_cert_timestamp_list); | ||||
@@ -511,7 +509,7 @@ int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) { | |||||
return 0; | return 0; | ||||
} | } | ||||
SSL_SESSION *session = SSL_SESSION_new(); | |||||
SSL_SESSION *session = ssl_session_new(ssl->ctx->x509_method); | |||||
if (session == NULL) { | if (session == NULL) { | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -573,53 +571,6 @@ err: | |||||
return 0; | return 0; | ||||
} | } | ||||
int ssl_session_x509_cache_objects(SSL_SESSION *sess) { | |||||
STACK_OF(X509) *chain = NULL; | |||||
const size_t num_certs = sk_CRYPTO_BUFFER_num(sess->certs); | |||||
if (num_certs > 0) { | |||||
chain = sk_X509_new_null(); | |||||
if (chain == NULL) { | |||||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||||
goto err; | |||||
} | |||||
} | |||||
X509 *leaf = NULL; | |||||
for (size_t i = 0; i < num_certs; i++) { | |||||
X509 *x509 = X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(sess->certs, i)); | |||||
if (x509 == NULL) { | |||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||||
goto err; | |||||
} | |||||
if (!sk_X509_push(chain, x509)) { | |||||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||||
X509_free(x509); | |||||
goto err; | |||||
} | |||||
if (i == 0) { | |||||
leaf = x509; | |||||
} | |||||
} | |||||
sk_X509_pop_free(sess->x509_chain, X509_free); | |||||
sess->x509_chain = chain; | |||||
sk_X509_pop_free(sess->x509_chain_without_leaf, X509_free); | |||||
sess->x509_chain_without_leaf = NULL; | |||||
X509_free(sess->x509_peer); | |||||
if (leaf != NULL) { | |||||
X509_up_ref(leaf); | |||||
} | |||||
sess->x509_peer = leaf; | |||||
return 1; | |||||
err: | |||||
sk_X509_pop_free(chain, X509_free); | |||||
return 0; | |||||
} | |||||
int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) { | int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) { | ||||
int ret = 0; | int ret = 0; | ||||
@@ -753,7 +704,8 @@ int ssl_session_is_resumable(const SSL *ssl, const SSL_SESSION *session) { | |||||
/* If the session contains a client certificate (either the full | /* If the session contains a client certificate (either the full | ||||
* certificate or just the hash) then require that the form of the | * certificate or just the hash) then require that the form of the | ||||
* certificate matches the current configuration. */ | * certificate matches the current configuration. */ | ||||
((session->x509_peer == NULL && !session->peer_sha256_valid) || | |||||
((sk_CRYPTO_BUFFER_num(session->certs) == 0 && | |||||
!session->peer_sha256_valid) || | |||||
session->peer_sha256_valid == | session->peer_sha256_valid == | ||||
ssl->retain_only_sha256_of_client_certs); | ssl->retain_only_sha256_of_client_certs); | ||||
} | } | ||||
@@ -634,7 +634,12 @@ static bool TestSSL_SESSIONEncoding(const char *input_b64) { | |||||
} | } | ||||
// Verify the SSL_SESSION decodes. | // Verify the SSL_SESSION decodes. | ||||
bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(input.data(), input.size())); | |||||
bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); | |||||
if (!ssl_ctx) { | |||||
return false; | |||||
} | |||||
bssl::UniquePtr<SSL_SESSION> session( | |||||
SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get())); | |||||
if (!session) { | if (!session) { | ||||
fprintf(stderr, "SSL_SESSION_from_bytes failed\n"); | fprintf(stderr, "SSL_SESSION_from_bytes failed\n"); | ||||
return false; | return false; | ||||
@@ -703,7 +708,12 @@ static bool TestBadSSL_SESSIONEncoding(const char *input_b64) { | |||||
} | } | ||||
// Verify that the SSL_SESSION fails to decode. | // Verify that the SSL_SESSION fails to decode. | ||||
bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(input.data(), input.size())); | |||||
bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); | |||||
if (!ssl_ctx) { | |||||
return false; | |||||
} | |||||
bssl::UniquePtr<SSL_SESSION> session( | |||||
SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get())); | |||||
if (session) { | if (session) { | ||||
fprintf(stderr, "SSL_SESSION_from_bytes unexpectedly succeeded\n"); | fprintf(stderr, "SSL_SESSION_from_bytes unexpectedly succeeded\n"); | ||||
return false; | return false; | ||||
@@ -795,8 +805,13 @@ static bssl::UniquePtr<SSL_SESSION> CreateSessionWithTicket(uint16_t version, | |||||
if (!DecodeBase64(&der, kOpenSSLSession)) { | if (!DecodeBase64(&der, kOpenSSLSession)) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); | |||||
if (!ssl_ctx) { | |||||
return nullptr; | |||||
} | |||||
bssl::UniquePtr<SSL_SESSION> session( | bssl::UniquePtr<SSL_SESSION> session( | ||||
SSL_SESSION_from_bytes(der.data(), der.size())); | |||||
SSL_SESSION_from_bytes(der.data(), der.size(), ssl_ctx.get())); | |||||
if (!session) { | if (!session) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
@@ -989,7 +1004,11 @@ static bool ExpectCache(SSL_CTX *ctx, | |||||
} | } | ||||
static bssl::UniquePtr<SSL_SESSION> CreateTestSession(uint32_t number) { | static bssl::UniquePtr<SSL_SESSION> CreateTestSession(uint32_t number) { | ||||
bssl::UniquePtr<SSL_SESSION> ret(SSL_SESSION_new()); | |||||
bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); | |||||
if (!ssl_ctx) { | |||||
return nullptr; | |||||
} | |||||
bssl::UniquePtr<SSL_SESSION> ret(SSL_SESSION_new(ssl_ctx.get())); | |||||
if (!ret) { | if (!ret) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
@@ -2166,8 +2185,12 @@ static bool GetServerTicketTime(long *out, const SSL_SESSION *session) { | |||||
len = static_cast<size_t>(len1 + len2); | len = static_cast<size_t>(len1 + len2); | ||||
#endif | #endif | ||||
bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); | |||||
if (!ssl_ctx) { | |||||
return false; | |||||
} | |||||
bssl::UniquePtr<SSL_SESSION> server_session( | bssl::UniquePtr<SSL_SESSION> server_session( | ||||
SSL_SESSION_from_bytes(plaintext.get(), len)); | |||||
SSL_SESSION_from_bytes(plaintext.get(), len, ssl_ctx.get())); | |||||
if (!server_session) { | if (!server_session) { | ||||
return false; | return false; | ||||
} | } | ||||
@@ -142,6 +142,10 @@ | |||||
#include <assert.h> | #include <assert.h> | ||||
#include <openssl/asn1.h> | |||||
#include <openssl/bytestring.h> | |||||
#include <openssl/err.h> | |||||
#include <openssl/pem.h> | |||||
#include <openssl/stack.h> | #include <openssl/stack.h> | ||||
#include <openssl/x509.h> | #include <openssl/x509.h> | ||||
#include <openssl/x509v3.h> | #include <openssl/x509v3.h> | ||||
@@ -334,10 +338,85 @@ static void ssl_crypto_x509_clear(CERT *cert) { | |||||
cert->x509_stash = NULL; | cert->x509_stash = NULL; | ||||
} | } | ||||
static int ssl_crypto_x509_session_cache_objects(SSL_SESSION *sess) { | |||||
STACK_OF(X509) *chain = NULL; | |||||
const size_t num_certs = sk_CRYPTO_BUFFER_num(sess->certs); | |||||
if (num_certs > 0) { | |||||
chain = sk_X509_new_null(); | |||||
if (chain == NULL) { | |||||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||||
goto err; | |||||
} | |||||
} | |||||
X509 *leaf = NULL; | |||||
for (size_t i = 0; i < num_certs; i++) { | |||||
X509 *x509 = X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(sess->certs, i)); | |||||
if (x509 == NULL) { | |||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||||
goto err; | |||||
} | |||||
if (!sk_X509_push(chain, x509)) { | |||||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||||
X509_free(x509); | |||||
goto err; | |||||
} | |||||
if (i == 0) { | |||||
leaf = x509; | |||||
} | |||||
} | |||||
sk_X509_pop_free(sess->x509_chain, X509_free); | |||||
sess->x509_chain = chain; | |||||
sk_X509_pop_free(sess->x509_chain_without_leaf, X509_free); | |||||
sess->x509_chain_without_leaf = NULL; | |||||
X509_free(sess->x509_peer); | |||||
if (leaf != NULL) { | |||||
X509_up_ref(leaf); | |||||
} | |||||
sess->x509_peer = leaf; | |||||
return 1; | |||||
err: | |||||
sk_X509_pop_free(chain, X509_free); | |||||
return 0; | |||||
} | |||||
static int ssl_crypto_x509_session_dup(SSL_SESSION *new_session, | |||||
const SSL_SESSION *session) { | |||||
if (session->x509_peer != NULL) { | |||||
X509_up_ref(session->x509_peer); | |||||
new_session->x509_peer = session->x509_peer; | |||||
} | |||||
if (session->x509_chain != NULL) { | |||||
new_session->x509_chain = X509_chain_up_ref(session->x509_chain); | |||||
if (new_session->x509_chain == NULL) { | |||||
return 0; | |||||
} | |||||
} | |||||
return 1; | |||||
} | |||||
static void ssl_crypto_x509_session_clear(SSL_SESSION *session) { | |||||
X509_free(session->x509_peer); | |||||
session->x509_peer = NULL; | |||||
sk_X509_pop_free(session->x509_chain, X509_free); | |||||
session->x509_chain = NULL; | |||||
sk_X509_pop_free(session->x509_chain_without_leaf, X509_free); | |||||
session->x509_chain_without_leaf = NULL; | |||||
} | |||||
const SSL_X509_METHOD ssl_crypto_x509_method = { | const SSL_X509_METHOD ssl_crypto_x509_method = { | ||||
ssl_crypto_x509_clear, | ssl_crypto_x509_clear, | ||||
ssl_crypto_x509_flush_cached_chain, | ssl_crypto_x509_flush_cached_chain, | ||||
ssl_crypto_x509_flush_cached_leaf, | ssl_crypto_x509_flush_cached_leaf, | ||||
ssl_crypto_x509_session_cache_objects, | |||||
ssl_crypto_x509_session_dup, | |||||
ssl_crypto_x509_session_clear, | |||||
}; | }; | ||||
/* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised | /* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised | ||||
@@ -696,3 +775,41 @@ int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) { | |||||
*out_chain = ssl->cert->x509_chain; | *out_chain = ssl->cert->x509_chain; | ||||
return 1; | return 1; | ||||
} | } | ||||
static SSL_SESSION *ssl_session_new_with_crypto_x509(void) { | |||||
return ssl_session_new(&ssl_crypto_x509_method); | |||||
} | |||||
SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) { | |||||
return ASN1_d2i_bio_of(SSL_SESSION, ssl_session_new_with_crypto_x509, | |||||
d2i_SSL_SESSION, bio, out); | |||||
} | |||||
int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session) { | |||||
return ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bio, session); | |||||
} | |||||
IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION) | |||||
SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { | |||||
if (length < 0) { | |||||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |||||
return NULL; | |||||
} | |||||
CBS cbs; | |||||
CBS_init(&cbs, *pp, length); | |||||
SSL_SESSION *ret = SSL_SESSION_parse(&cbs, &ssl_crypto_x509_method, | |||||
NULL /* no buffer pool */); | |||||
if (ret == NULL) { | |||||
return NULL; | |||||
} | |||||
if (a) { | |||||
SSL_SESSION_free(*a); | |||||
*a = ret; | |||||
} | |||||
*pp = CBS_data(&cbs); | |||||
return ret; | |||||
} |
@@ -3213,7 +3213,8 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, | |||||
#endif | #endif | ||||
/* Decode the session. */ | /* Decode the session. */ | ||||
SSL_SESSION *session = SSL_SESSION_from_bytes(plaintext, plaintext_len); | |||||
SSL_SESSION *session = | |||||
SSL_SESSION_from_bytes(plaintext, plaintext_len, ssl->ctx); | |||||
if (session == NULL) { | if (session == NULL) { | ||||
ERR_clear_error(); /* Don't leave an error on the queue. */ | ERR_clear_error(); /* Don't leave an error on the queue. */ | ||||
goto done; | goto done; | ||||
@@ -1477,7 +1477,7 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) { | |||||
} | } | ||||
if (expected_sha256_client_cert && | if (expected_sha256_client_cert && | ||||
SSL_get_session(ssl)->x509_peer != nullptr) { | |||||
SSL_get_session(ssl)->certs != nullptr) { | |||||
fprintf(stderr, "Have both client cert and SHA-256 hash: is_resume:%d.\n", | fprintf(stderr, "Have both client cert and SHA-256 hash: is_resume:%d.\n", | ||||
is_resume); | is_resume); | ||||
return false; | return false; | ||||
@@ -307,7 +307,7 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { | |||||
ssl->s3->new_session->certs = certs; | ssl->s3->new_session->certs = certs; | ||||
certs = NULL; | certs = NULL; | ||||
if (!ssl_session_x509_cache_objects(ssl->s3->new_session)) { | |||||
if (!ssl->ctx->x509_method->session_cache_objects(ssl->s3->new_session)) { | |||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | ||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | ||||
goto err; | goto err; | ||||
@@ -615,9 +615,8 @@ enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs) { | |||||
int tls13_process_new_session_ticket(SSL *ssl) { | int tls13_process_new_session_ticket(SSL *ssl) { | ||||
int ret = 0; | int ret = 0; | ||||
SSL_SESSION *session = | |||||
SSL_SESSION_dup(ssl->s3->established_session, | |||||
SSL_SESSION_INCLUDE_NONAUTH); | |||||
SSL_SESSION *session = SSL_SESSION_dup(ssl->s3->established_session, | |||||
SSL_SESSION_INCLUDE_NONAUTH); | |||||
if (session == NULL) { | if (session == NULL) { | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -495,7 +495,7 @@ static enum ssl_hs_wait_t do_process_client_certificate(SSL_HANDSHAKE *hs) { | |||||
static enum ssl_hs_wait_t do_process_client_certificate_verify( | static enum ssl_hs_wait_t do_process_client_certificate_verify( | ||||
SSL_HANDSHAKE *hs) { | SSL_HANDSHAKE *hs) { | ||||
SSL *const ssl = hs->ssl; | SSL *const ssl = hs->ssl; | ||||
if (ssl->s3->new_session->x509_peer == NULL) { | |||||
if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0) { | |||||
/* Skip this state. */ | /* Skip this state. */ | ||||
hs->tls13_state = state_process_channel_id; | hs->tls13_state = state_process_channel_id; | ||||
return ssl_hs_ok; | return ssl_hs_ok; | ||||
@@ -257,3 +257,24 @@ const SSL_METHOD *TLS_server_method(void) { | |||||
const SSL_METHOD *TLS_client_method(void) { | const SSL_METHOD *TLS_client_method(void) { | ||||
return TLS_method(); | return TLS_method(); | ||||
} | } | ||||
static void ssl_noop_x509_clear(CERT *cert) {} | |||||
static void ssl_noop_x509_flush_cached_leaf(CERT *cert) {} | |||||
static void ssl_noop_x509_flush_cached_chain(CERT *cert) {} | |||||
static int ssl_noop_x509_session_cache_objects(SSL_SESSION *sess) { | |||||
return 1; | |||||
} | |||||
static int ssl_noop_x509_session_dup(SSL_SESSION *new_session, | |||||
const SSL_SESSION *session) { | |||||
return 1; | |||||
} | |||||
static void ssl_noop_x509_session_clear(SSL_SESSION *session) {} | |||||
const SSL_X509_METHOD ssl_noop_x509_method = { | |||||
ssl_noop_x509_clear, | |||||
ssl_noop_x509_flush_cached_chain, | |||||
ssl_noop_x509_flush_cached_leaf, | |||||
ssl_noop_x509_session_cache_objects, | |||||
ssl_noop_x509_session_dup, | |||||
ssl_noop_x509_session_clear, | |||||
}; |