This change adds support for setting an |SSL_TICKET_AEAD_METHOD| which allows a caller to control ticket encryption and decryption to a greater extent than previously possible and also permits asynchronous ticket decryption. This change only includes partial support: TLS 1.3 work remains to be done. Change-Id: Ia2e10ebb3257e1a119630c463b6bf389cf20ef18 Reviewed-on: https://boringssl-review.googlesource.com/14144 Commit-Queue: David Benjamin <davidben@google.com> Reviewed-by: Adam Langley <agl@google.com>kris/onging/CECPQ3_patch15
@@ -149,6 +149,7 @@ SSL,1043,SSLV3_ALERT_UNSUPPORTED_CERTIFICATE | |||||
SSL,214,SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION | SSL,214,SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION | ||||
SSL,215,SSL_HANDSHAKE_FAILURE | SSL,215,SSL_HANDSHAKE_FAILURE | ||||
SSL,216,SSL_SESSION_ID_CONTEXT_TOO_LONG | SSL,216,SSL_SESSION_ID_CONTEXT_TOO_LONG | ||||
SSL,276,TICKET_ENCRYPTION_FAILED | |||||
SSL,1049,TLSV1_ALERT_ACCESS_DENIED | SSL,1049,TLSV1_ALERT_ACCESS_DENIED | ||||
SSL,1050,TLSV1_ALERT_DECODE_ERROR | SSL,1050,TLSV1_ALERT_DECODE_ERROR | ||||
SSL,1021,TLSV1_ALERT_DECRYPTION_FAILED | SSL,1021,TLSV1_ALERT_DECRYPTION_FAILED | ||||
@@ -306,6 +306,7 @@ typedef struct ssl_method_st SSL_METHOD; | |||||
typedef struct ssl_private_key_method_st SSL_PRIVATE_KEY_METHOD; | typedef struct ssl_private_key_method_st SSL_PRIVATE_KEY_METHOD; | ||||
typedef struct ssl_session_st SSL_SESSION; | typedef struct ssl_session_st SSL_SESSION; | ||||
typedef struct ssl_st SSL; | typedef struct ssl_st SSL; | ||||
typedef struct ssl_ticket_aead_method_st SSL_TICKET_AEAD_METHOD; | |||||
typedef struct st_ERR_FNS ERR_FNS; | typedef struct st_ERR_FNS ERR_FNS; | ||||
typedef struct v3_ext_ctx X509V3_CTX; | typedef struct v3_ext_ctx X509V3_CTX; | ||||
typedef struct x509_attributes_st X509_ATTRIBUTE; | typedef struct x509_attributes_st X509_ATTRIBUTE; | ||||
@@ -506,6 +506,12 @@ OPENSSL_EXPORT int SSL_get_error(const SSL *ssl, int ret_code); | |||||
* |SSL_CTX_set_private_key_method|. */ | * |SSL_CTX_set_private_key_method|. */ | ||||
#define SSL_ERROR_WANT_PRIVATE_KEY_OPERATION 13 | #define SSL_ERROR_WANT_PRIVATE_KEY_OPERATION 13 | ||||
/* SSL_ERROR_PENDING_TICKET indicates that a ticket decryption is pending. The | |||||
* caller may retry the operation when the decryption is ready. | |||||
* | |||||
* See also |SSL_CTX_set_ticket_aead_method|. */ | |||||
#define SSL_ERROR_PENDING_TICKET 14 | |||||
/* SSL_set_mtu sets the |ssl|'s MTU in DTLS to |mtu|. It returns one on success | /* SSL_set_mtu sets the |ssl|'s MTU in DTLS to |mtu|. It returns one on success | ||||
* and zero on failure. */ | * and zero on failure. */ | ||||
OPENSSL_EXPORT int SSL_set_mtu(SSL *ssl, unsigned mtu); | OPENSSL_EXPORT int SSL_set_mtu(SSL *ssl, unsigned mtu); | ||||
@@ -1955,7 +1961,14 @@ OPENSSL_EXPORT SSL_SESSION *SSL_magic_pending_session_ptr(void); | |||||
* On the server, tickets are encrypted and authenticated with a secret key. By | * On the server, tickets are encrypted and authenticated with a secret key. By | ||||
* default, an |SSL_CTX| generates a key on creation. Tickets are minted and | * default, an |SSL_CTX| generates a key on creation. Tickets are minted and | ||||
* processed transparently. The following functions may be used to configure a | * processed transparently. The following functions may be used to configure a | ||||
* persistent key or implement more custom behavior. */ | |||||
* persistent key or implement more custom behavior. There are three levels of | |||||
* customisation possible: | |||||
* | |||||
* 1) One can simply set the keys with |SSL_CTX_set_tlsext_ticket_keys|. | |||||
* 2) One can configure an |EVP_CIPHER_CTX| and |HMAC_CTX| directly for | |||||
* encryption and authentication. | |||||
* 3) One can configure an |SSL_TICKET_ENCRYPTION_METHOD| to have more control | |||||
* and the option of asynchronous decryption. */ | |||||
/* SSL_CTX_get_tlsext_ticket_keys writes |ctx|'s session ticket key material to | /* SSL_CTX_get_tlsext_ticket_keys writes |ctx|'s session ticket key material to | ||||
* |len| bytes of |out|. It returns one on success and zero if |len| is not | * |len| bytes of |out|. It returns one on success and zero if |len| is not | ||||
@@ -2001,6 +2014,55 @@ OPENSSL_EXPORT int SSL_CTX_set_tlsext_ticket_key_cb( | |||||
EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx, | EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx, | ||||
int encrypt)); | int encrypt)); | ||||
/* ssl_ticket_aead_result_t enumerates the possible results from decrypting a | |||||
* ticket with an |SSL_TICKET_AEAD_METHOD|. */ | |||||
enum ssl_ticket_aead_result_t { | |||||
/* ssl_ticket_aead_success indicates the the ticket was successfully | |||||
* decrypted. */ | |||||
ssl_ticket_aead_success, | |||||
/* ssl_ticket_aead_retry indicates that the operation could not be | |||||
* immediately completed and must be reattempted, via |open|, at a later | |||||
* point. */ | |||||
ssl_ticket_aead_retry, | |||||
/* ssl_ticket_aead_ignore_ticket indicates that the ticket should be ignored | |||||
* (i.e. is corrupt or otherwise undecryptable). */ | |||||
ssl_ticket_aead_ignore_ticket, | |||||
/* ssl_ticket_aead_error indicates that a fatal error occured and the | |||||
* handshake should be terminated. */ | |||||
ssl_ticket_aead_error, | |||||
}; | |||||
/* ssl_ticket_aead_method_st (aka |SSL_TICKET_ENCRYPTION_METHOD|) contains | |||||
* methods for encrypting and decrypting session tickets. */ | |||||
struct ssl_ticket_aead_method_st { | |||||
/* max_overhead returns the maximum number of bytes of overhead that |seal| | |||||
* may add. */ | |||||
size_t (*max_overhead)(SSL *ssl); | |||||
/* seal encrypts and authenticates |in_len| bytes from |in|, writes, at most, | |||||
* |max_out_len| bytes to |out|, and puts the number of bytes written in | |||||
* |*out_len|. The |in| and |out| buffers may be equal but will not otherwise | |||||
* alias. It returns one on success or zero on error. */ | |||||
int (*seal)(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out_len, | |||||
const uint8_t *in, size_t in_len); | |||||
/* open authenticates and decrypts |in_len| bytes from |in|, writes, at most, | |||||
* |max_out_len| bytes of plaintext to |out|, and puts the number of bytes | |||||
* written in |*out_len|. The |in| and |out| buffers may be equal but will | |||||
* not otherwise alias. See |ssl_ticket_aead_result_t| for details of the | |||||
* return values. In the case that a retry is indicated, the caller should | |||||
* arrange for the high-level operation on |ssl| to be retried when the | |||||
* operation is completed, which will result in another call to |open|. */ | |||||
enum ssl_ticket_aead_result_t (*open)(SSL *ssl, uint8_t *out, size_t *out_len, | |||||
size_t max_out_len, const uint8_t *in, | |||||
size_t in_len); | |||||
}; | |||||
/* SSL_CTX_set_ticket_aead_method configures a custom ticket AEAD method table | |||||
* on |ctx|. |aead_method| must remain valid for the lifetime of |ctx|. */ | |||||
OPENSSL_EXPORT void SSL_CTX_set_ticket_aead_method( | |||||
SSL_CTX *ctx, const SSL_TICKET_AEAD_METHOD *aead_method); | |||||
/* Elliptic curve Diffie-Hellman. | /* Elliptic curve Diffie-Hellman. | ||||
* | * | ||||
@@ -3572,6 +3634,7 @@ OPENSSL_EXPORT void SSL_CTX_set_client_cert_cb( | |||||
#define SSL_PENDING_SESSION 7 | #define SSL_PENDING_SESSION 7 | ||||
#define SSL_CERTIFICATE_SELECTION_PENDING 8 | #define SSL_CERTIFICATE_SELECTION_PENDING 8 | ||||
#define SSL_PRIVATE_KEY_OPERATION 9 | #define SSL_PRIVATE_KEY_OPERATION 9 | ||||
#define SSL_PENDING_TICKET 10 | |||||
/* SSL_want returns one of the above values to determine what the most recent | /* SSL_want returns one of the above values to determine what the most recent | ||||
* operation on |ssl| was blocked on. Use |SSL_get_error| instead. */ | * operation on |ssl| was blocked on. Use |SSL_get_error| instead. */ | ||||
@@ -4144,6 +4207,10 @@ struct ssl_ctx_st { | |||||
* memory. */ | * memory. */ | ||||
CRYPTO_BUFFER_POOL *pool; | CRYPTO_BUFFER_POOL *pool; | ||||
/* ticket_aead_method contains function pointers for opening and sealing | |||||
* session tickets. */ | |||||
const SSL_TICKET_AEAD_METHOD *ticket_aead_method; | |||||
/* quiet_shutdown is true if the connection should not send a close_notify on | /* quiet_shutdown is true if the connection should not send a close_notify on | ||||
* shutdown. */ | * shutdown. */ | ||||
unsigned quiet_shutdown:1; | unsigned quiet_shutdown:1; | ||||
@@ -4509,6 +4576,7 @@ BORINGSSL_MAKE_DELETER(SSL_SESSION, SSL_SESSION_free) | |||||
#define SSL_R_SERVER_CERT_CHANGED 273 | #define SSL_R_SERVER_CERT_CHANGED 273 | ||||
#define SSL_R_CERTIFICATE_AND_PRIVATE_KEY_MISMATCH 274 | #define SSL_R_CERTIFICATE_AND_PRIVATE_KEY_MISMATCH 274 | ||||
#define SSL_R_CANNOT_HAVE_BOTH_PRIVKEY_AND_METHOD 275 | #define SSL_R_CANNOT_HAVE_BOTH_PRIVKEY_AND_METHOD 275 | ||||
#define SSL_R_TICKET_ENCRYPTION_FAILED 276 | |||||
#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000 | #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000 | ||||
#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 | #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 | ||||
#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 | #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 | ||||
@@ -930,6 +930,9 @@ static int ssl3_select_parameters(SSL_HANDSHAKE *hs) { | |||||
case ssl_session_retry: | case ssl_session_retry: | ||||
ssl->rwstate = SSL_PENDING_SESSION; | ssl->rwstate = SSL_PENDING_SESSION; | ||||
goto err; | goto err; | ||||
case ssl_session_ticket_retry: | |||||
ssl->rwstate = SSL_PENDING_TICKET; | |||||
goto err; | |||||
} | } | ||||
if (session != NULL) { | if (session != NULL) { | ||||
@@ -1991,13 +1991,15 @@ enum ssl_session_result_t { | |||||
ssl_session_success, | ssl_session_success, | ||||
ssl_session_error, | ssl_session_error, | ||||
ssl_session_retry, | ssl_session_retry, | ||||
ssl_session_ticket_retry, | |||||
}; | }; | ||||
/* ssl_get_prev_session looks up the previous session based on |client_hello|. | /* ssl_get_prev_session looks up the previous session based on |client_hello|. | ||||
* On success, it sets |*out_session| to the session or NULL if none was found. | * On success, it sets |*out_session| to the session or NULL if none was found. | ||||
* If the session could not be looked up synchronously, it returns | * If the session could not be looked up synchronously, it returns | ||||
* |ssl_session_retry| and should be called again. Otherwise, it returns | |||||
* |ssl_session_error|. */ | |||||
* |ssl_session_retry| and should be called again. If a ticket could not be | |||||
* decrypted immediately it returns |ssl_session_ticket_retry| and should also | |||||
* be called again. Otherwise, it returns |ssl_session_error|. */ | |||||
enum ssl_session_result_t ssl_get_prev_session( | enum ssl_session_result_t ssl_get_prev_session( | ||||
SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported, | SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported, | ||||
int *out_renew_ticket, const SSL_CLIENT_HELLO *client_hello); | int *out_renew_ticket, const SSL_CLIENT_HELLO *client_hello); | ||||
@@ -2165,15 +2167,19 @@ int ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs); | |||||
#define tlsext_tick_md EVP_sha256 | #define tlsext_tick_md EVP_sha256 | ||||
/* tls_process_ticket processes a session ticket from the client. On success, | |||||
* it sets |*out_session| to the decrypted session or NULL if the ticket was | |||||
* rejected. If the ticket was valid, it sets |*out_renew_ticket| to whether | |||||
* the ticket should be renewed. It returns one on success and zero on fatal | |||||
* error. */ | |||||
int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, | |||||
int *out_renew_ticket, const uint8_t *ticket, | |||||
size_t ticket_len, const uint8_t *session_id, | |||||
size_t session_id_len); | |||||
/* ssl_process_ticket processes a session ticket from the client. It returns | |||||
* one of: | |||||
* |ssl_ticket_aead_success|: |*out_session| is set to the parsed session and | |||||
* |*out_renew_ticket| is set to whether the ticket should be renewed. | |||||
* |ssl_ticket_aead_ignore_ticket|: |*out_renew_ticket| is set to whether a | |||||
* fresh ticket should be sent, but the given ticket cannot be used. | |||||
* |ssl_ticket_aead_retry|: the ticket could not be immediately decrypted. | |||||
* Retry later. | |||||
* |ssl_ticket_aead_error|: an error occured that is fatal to the connection. */ | |||||
enum ssl_ticket_aead_result_t ssl_process_ticket( | |||||
SSL *ssl, SSL_SESSION **out_session, int *out_renew_ticket, | |||||
const uint8_t *ticket, size_t ticket_len, const uint8_t *session_id, | |||||
size_t session_id_len); | |||||
/* tls1_verify_channel_id processes the current message as a Channel ID message, | /* tls1_verify_channel_id processes the current message as a Channel ID message, | ||||
* and verifies the signature. If the key is valid, it saves the Channel ID and | * and verifies the signature. If the key is valid, it saves the Channel ID and | ||||
@@ -910,6 +910,9 @@ int SSL_get_error(const SSL *ssl, int ret_code) { | |||||
case SSL_PRIVATE_KEY_OPERATION: | case SSL_PRIVATE_KEY_OPERATION: | ||||
return SSL_ERROR_WANT_PRIVATE_KEY_OPERATION; | return SSL_ERROR_WANT_PRIVATE_KEY_OPERATION; | ||||
case SSL_PENDING_TICKET: | |||||
return SSL_ERROR_PENDING_TICKET; | |||||
} | } | ||||
return SSL_ERROR_SYSCALL; | return SSL_ERROR_SYSCALL; | ||||
@@ -2699,3 +2702,8 @@ int SSL_set_min_version(SSL *ssl, uint16_t version) { | |||||
int SSL_set_max_version(SSL *ssl, uint16_t version) { | int SSL_set_max_version(SSL *ssl, uint16_t version) { | ||||
return SSL_set_max_proto_version(ssl, version); | return SSL_set_max_proto_version(ssl, version); | ||||
} | } | ||||
void SSL_CTX_set_ticket_aead_method(SSL_CTX *ctx, | |||||
const SSL_TICKET_AEAD_METHOD *aead_method) { | |||||
ctx->ticket_aead_method = aead_method; | |||||
} |
@@ -581,16 +581,11 @@ err: | |||||
return 0; | return 0; | ||||
} | } | ||||
int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) { | |||||
static int ssl_encrypt_ticket_with_cipher_ctx(SSL *ssl, CBB *out, | |||||
const uint8_t *session_buf, | |||||
size_t session_len) { | |||||
int ret = 0; | int ret = 0; | ||||
/* Serialize the SSL_SESSION to be encoded into the ticket. */ | |||||
uint8_t *session_buf = NULL; | |||||
size_t session_len; | |||||
if (!SSL_SESSION_to_bytes_for_ticket(session, &session_buf, &session_len)) { | |||||
return -1; | |||||
} | |||||
EVP_CIPHER_CTX ctx; | EVP_CIPHER_CTX ctx; | ||||
EVP_CIPHER_CTX_init(&ctx); | EVP_CIPHER_CTX_init(&ctx); | ||||
HMAC_CTX hctx; | HMAC_CTX hctx; | ||||
@@ -667,12 +662,60 @@ int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) { | |||||
ret = 1; | ret = 1; | ||||
err: | err: | ||||
OPENSSL_free(session_buf); | |||||
EVP_CIPHER_CTX_cleanup(&ctx); | EVP_CIPHER_CTX_cleanup(&ctx); | ||||
HMAC_CTX_cleanup(&hctx); | HMAC_CTX_cleanup(&hctx); | ||||
return ret; | return ret; | ||||
} | } | ||||
static int ssl_encrypt_ticket_with_method(SSL *ssl, CBB *out, | |||||
const uint8_t *session_buf, | |||||
size_t session_len) { | |||||
const SSL_TICKET_AEAD_METHOD *method = ssl->session_ctx->ticket_aead_method; | |||||
const size_t max_overhead = method->max_overhead(ssl); | |||||
const size_t max_out = session_len + max_overhead; | |||||
if (max_out < max_overhead) { | |||||
OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); | |||||
return 0; | |||||
} | |||||
uint8_t *ptr; | |||||
if (!CBB_reserve(out, &ptr, max_out)) { | |||||
return 0; | |||||
} | |||||
size_t out_len; | |||||
if (!method->seal(ssl, ptr, &out_len, max_out, session_buf, session_len)) { | |||||
OPENSSL_PUT_ERROR(SSL, SSL_R_TICKET_ENCRYPTION_FAILED); | |||||
return 0; | |||||
} | |||||
if (!CBB_did_write(out, out_len)) { | |||||
return 0; | |||||
} | |||||
return 1; | |||||
} | |||||
int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) { | |||||
/* Serialize the SSL_SESSION to be encoded into the ticket. */ | |||||
uint8_t *session_buf = NULL; | |||||
size_t session_len; | |||||
if (!SSL_SESSION_to_bytes_for_ticket(session, &session_buf, &session_len)) { | |||||
return -1; | |||||
} | |||||
int ret = 0; | |||||
if (ssl->session_ctx->ticket_aead_method) { | |||||
ret = ssl_encrypt_ticket_with_method(ssl, out, session_buf, session_len); | |||||
} else { | |||||
ret = | |||||
ssl_encrypt_ticket_with_cipher_ctx(ssl, out, session_buf, session_len); | |||||
} | |||||
OPENSSL_free(session_buf); | |||||
return ret; | |||||
} | |||||
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) { | ||||
if (session == NULL) { | if (session == NULL) { | ||||
return 0; | return 0; | ||||
@@ -811,10 +854,18 @@ enum ssl_session_result_t ssl_get_prev_session( | |||||
SSL_early_callback_ctx_extension_get( | SSL_early_callback_ctx_extension_get( | ||||
client_hello, TLSEXT_TYPE_session_ticket, &ticket, &ticket_len); | client_hello, TLSEXT_TYPE_session_ticket, &ticket, &ticket_len); | ||||
if (tickets_supported && ticket_len > 0) { | if (tickets_supported && ticket_len > 0) { | ||||
if (!tls_process_ticket(ssl, &session, &renew_ticket, ticket, ticket_len, | |||||
client_hello->session_id, | |||||
client_hello->session_id_len)) { | |||||
return ssl_session_error; | |||||
switch (ssl_process_ticket(ssl, &session, &renew_ticket, ticket, ticket_len, | |||||
client_hello->session_id, | |||||
client_hello->session_id_len)) { | |||||
case ssl_ticket_aead_success: | |||||
break; | |||||
case ssl_ticket_aead_ignore_ticket: | |||||
assert(session == NULL); | |||||
break; | |||||
case ssl_ticket_aead_error: | |||||
return ssl_session_error; | |||||
case ssl_ticket_aead_retry: | |||||
return ssl_session_ticket_retry; | |||||
} | } | ||||
} else { | } else { | ||||
/* The client didn't send a ticket, so the session ID is a real ID. */ | /* The client didn't send a ticket, so the session ID is a real ID. */ | ||||
@@ -1352,7 +1352,8 @@ static bool CompleteHandshakes(SSL *client, SSL *server) { | |||||
int client_err = SSL_get_error(client, client_ret); | int client_err = SSL_get_error(client, client_ret); | ||||
if (client_err != SSL_ERROR_NONE && | if (client_err != SSL_ERROR_NONE && | ||||
client_err != SSL_ERROR_WANT_READ && | client_err != SSL_ERROR_WANT_READ && | ||||
client_err != SSL_ERROR_WANT_WRITE) { | |||||
client_err != SSL_ERROR_WANT_WRITE && | |||||
client_err != SSL_ERROR_PENDING_TICKET) { | |||||
fprintf(stderr, "Client error: %d\n", client_err); | fprintf(stderr, "Client error: %d\n", client_err); | ||||
return false; | return false; | ||||
} | } | ||||
@@ -1361,7 +1362,8 @@ static bool CompleteHandshakes(SSL *client, SSL *server) { | |||||
int server_err = SSL_get_error(server, server_ret); | int server_err = SSL_get_error(server, server_ret); | ||||
if (server_err != SSL_ERROR_NONE && | if (server_err != SSL_ERROR_NONE && | ||||
server_err != SSL_ERROR_WANT_READ && | server_err != SSL_ERROR_WANT_READ && | ||||
server_err != SSL_ERROR_WANT_WRITE) { | |||||
server_err != SSL_ERROR_WANT_WRITE && | |||||
server_err != SSL_ERROR_PENDING_TICKET) { | |||||
fprintf(stderr, "Server error: %d\n", server_err); | fprintf(stderr, "Server error: %d\n", server_err); | ||||
return false; | return false; | ||||
} | } | ||||
@@ -3246,6 +3248,238 @@ TEST(SSLTest, EmptyCipherList) { | |||||
EXPECT_EQ(0u, sk_SSL_CIPHER_num(SSL_CTX_get_ciphers(ctx.get()))); | EXPECT_EQ(0u, sk_SSL_CIPHER_num(SSL_CTX_get_ciphers(ctx.get()))); | ||||
} | } | ||||
// ssl_test_ticket_aead_failure_mode enumerates the possible ways in which the | |||||
// test |SSL_TICKET_AEAD_METHOD| can fail. | |||||
enum ssl_test_ticket_aead_failure_mode { | |||||
ssl_test_ticket_aead_ok = 0, | |||||
ssl_test_ticket_aead_seal_fail, | |||||
ssl_test_ticket_aead_open_soft_fail, | |||||
ssl_test_ticket_aead_open_hard_fail, | |||||
}; | |||||
struct ssl_test_ticket_aead_state { | |||||
unsigned retry_count; | |||||
ssl_test_ticket_aead_failure_mode failure_mode; | |||||
}; | |||||
static int ssl_test_ticket_aead_ex_index_dup(CRYPTO_EX_DATA *to, | |||||
const CRYPTO_EX_DATA *from, | |||||
void **from_d, int index, | |||||
long argl, void *argp) { | |||||
abort(); | |||||
} | |||||
static void ssl_test_ticket_aead_ex_index_free(void *parent, void *ptr, | |||||
CRYPTO_EX_DATA *ad, int index, | |||||
long argl, void *argp) { | |||||
auto state = reinterpret_cast<ssl_test_ticket_aead_state*>(ptr); | |||||
if (state == nullptr) { | |||||
return; | |||||
} | |||||
OPENSSL_free(state); | |||||
} | |||||
static CRYPTO_once_t g_ssl_test_ticket_aead_ex_index_once = CRYPTO_ONCE_INIT; | |||||
static int g_ssl_test_ticket_aead_ex_index; | |||||
static int ssl_test_ticket_aead_get_ex_index() { | |||||
CRYPTO_once(&g_ssl_test_ticket_aead_ex_index_once, [] { | |||||
g_ssl_test_ticket_aead_ex_index = SSL_get_ex_new_index( | |||||
0, nullptr, nullptr, ssl_test_ticket_aead_ex_index_dup, | |||||
ssl_test_ticket_aead_ex_index_free); | |||||
}); | |||||
return g_ssl_test_ticket_aead_ex_index; | |||||
} | |||||
static size_t ssl_test_ticket_aead_max_overhead(SSL *ssl) { | |||||
return 1; | |||||
} | |||||
static int ssl_test_ticket_aead_seal(SSL *ssl, uint8_t *out, size_t *out_len, | |||||
size_t max_out_len, const uint8_t *in, | |||||
size_t in_len) { | |||||
auto state = reinterpret_cast<ssl_test_ticket_aead_state *>( | |||||
SSL_get_ex_data(ssl, ssl_test_ticket_aead_get_ex_index())); | |||||
if (state->failure_mode == ssl_test_ticket_aead_seal_fail || | |||||
max_out_len < in_len + 1) { | |||||
return 0; | |||||
} | |||||
OPENSSL_memmove(out, in, in_len); | |||||
out[in_len] = 0xff; | |||||
*out_len = in_len + 1; | |||||
return 1; | |||||
} | |||||
static ssl_ticket_aead_result_t ssl_test_ticket_aead_open( | |||||
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out_len, | |||||
const uint8_t *in, size_t in_len) { | |||||
auto state = reinterpret_cast<ssl_test_ticket_aead_state *>( | |||||
SSL_get_ex_data(ssl, ssl_test_ticket_aead_get_ex_index())); | |||||
if (state->retry_count > 0) { | |||||
state->retry_count--; | |||||
return ssl_ticket_aead_retry; | |||||
} | |||||
switch (state->failure_mode) { | |||||
case ssl_test_ticket_aead_ok: | |||||
break; | |||||
case ssl_test_ticket_aead_seal_fail: | |||||
// If |seal| failed then there shouldn't be any ticket to try and | |||||
// decrypt. | |||||
abort(); | |||||
break; | |||||
case ssl_test_ticket_aead_open_soft_fail: | |||||
return ssl_ticket_aead_ignore_ticket; | |||||
case ssl_test_ticket_aead_open_hard_fail: | |||||
return ssl_ticket_aead_error; | |||||
} | |||||
if (in_len == 0 || in[in_len - 1] != 0xff) { | |||||
return ssl_ticket_aead_ignore_ticket; | |||||
} | |||||
if (max_out_len < in_len - 1) { | |||||
return ssl_ticket_aead_error; | |||||
} | |||||
OPENSSL_memmove(out, in, in_len - 1); | |||||
*out_len = in_len - 1; | |||||
return ssl_ticket_aead_success; | |||||
} | |||||
static const SSL_TICKET_AEAD_METHOD kSSLTestTicketMethod = { | |||||
ssl_test_ticket_aead_max_overhead, | |||||
ssl_test_ticket_aead_seal, | |||||
ssl_test_ticket_aead_open, | |||||
}; | |||||
static void ConnectClientAndServerWithTicketMethod( | |||||
bssl::UniquePtr<SSL> *out_client, bssl::UniquePtr<SSL> *out_server, | |||||
SSL_CTX *client_ctx, SSL_CTX *server_ctx, unsigned retry_count, | |||||
ssl_test_ticket_aead_failure_mode failure_mode, SSL_SESSION *session) { | |||||
bssl::UniquePtr<SSL> client(SSL_new(client_ctx)), server(SSL_new(server_ctx)); | |||||
ASSERT_TRUE(client); | |||||
ASSERT_TRUE(server); | |||||
SSL_set_connect_state(client.get()); | |||||
SSL_set_accept_state(server.get()); | |||||
auto state = reinterpret_cast<ssl_test_ticket_aead_state *>( | |||||
OPENSSL_malloc(sizeof(ssl_test_ticket_aead_state))); | |||||
ASSERT_TRUE(state); | |||||
OPENSSL_memset(state, 0, sizeof(ssl_test_ticket_aead_state)); | |||||
state->retry_count = retry_count; | |||||
state->failure_mode = failure_mode; | |||||
ASSERT_TRUE(SSL_set_ex_data(server.get(), ssl_test_ticket_aead_get_ex_index(), | |||||
state)); | |||||
SSL_set_session(client.get(), session); | |||||
BIO *bio1, *bio2; | |||||
ASSERT_TRUE(BIO_new_bio_pair(&bio1, 0, &bio2, 0)); | |||||
// SSL_set_bio takes ownership. | |||||
SSL_set_bio(client.get(), bio1, bio1); | |||||
SSL_set_bio(server.get(), bio2, bio2); | |||||
if (CompleteHandshakes(client.get(), server.get())) { | |||||
*out_client = std::move(client); | |||||
*out_server = std::move(server); | |||||
} else { | |||||
out_client->reset(); | |||||
out_server->reset(); | |||||
} | |||||
} | |||||
class TicketAEADMethodTest | |||||
: public ::testing::TestWithParam<testing::tuple< | |||||
uint16_t, unsigned, ssl_test_ticket_aead_failure_mode>> {}; | |||||
TEST_P(TicketAEADMethodTest, Resume) { | |||||
bssl::UniquePtr<X509> cert = GetTestCertificate(); | |||||
ASSERT_TRUE(cert); | |||||
bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); | |||||
ASSERT_TRUE(key); | |||||
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method())); | |||||
ASSERT_TRUE(server_ctx); | |||||
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method())); | |||||
ASSERT_TRUE(client_ctx); | |||||
const uint16_t version = testing::get<0>(GetParam()); | |||||
const unsigned retry_count = testing::get<1>(GetParam()); | |||||
const ssl_test_ticket_aead_failure_mode failure_mode = | |||||
testing::get<2>(GetParam()); | |||||
ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get())); | |||||
ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())); | |||||
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), version)); | |||||
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), version)); | |||||
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), version)); | |||||
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), version)); | |||||
SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH); | |||||
SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH); | |||||
SSL_CTX_set_current_time_cb(client_ctx.get(), FrozenTimeCallback); | |||||
SSL_CTX_set_current_time_cb(server_ctx.get(), FrozenTimeCallback); | |||||
SSL_CTX_set_ticket_aead_method(server_ctx.get(), &kSSLTestTicketMethod); | |||||
bssl::UniquePtr<SSL> client, server; | |||||
ConnectClientAndServerWithTicketMethod(&client, &server, client_ctx.get(), | |||||
server_ctx.get(), retry_count, | |||||
failure_mode, nullptr); | |||||
switch (failure_mode) { | |||||
case ssl_test_ticket_aead_ok: | |||||
case ssl_test_ticket_aead_open_hard_fail: | |||||
case ssl_test_ticket_aead_open_soft_fail: | |||||
ASSERT_TRUE(client); | |||||
break; | |||||
case ssl_test_ticket_aead_seal_fail: | |||||
EXPECT_FALSE(client); | |||||
return; | |||||
} | |||||
EXPECT_FALSE(SSL_session_reused(client.get())); | |||||
EXPECT_FALSE(SSL_session_reused(server.get())); | |||||
SSL_SESSION *session = SSL_get_session(client.get()); | |||||
ConnectClientAndServerWithTicketMethod(&client, &server, client_ctx.get(), | |||||
server_ctx.get(), retry_count, | |||||
failure_mode, session); | |||||
switch (failure_mode) { | |||||
case ssl_test_ticket_aead_ok: | |||||
ASSERT_TRUE(client); | |||||
EXPECT_TRUE(SSL_session_reused(client.get())); | |||||
EXPECT_TRUE(SSL_session_reused(server.get())); | |||||
break; | |||||
case ssl_test_ticket_aead_seal_fail: | |||||
abort(); | |||||
break; | |||||
case ssl_test_ticket_aead_open_hard_fail: | |||||
EXPECT_FALSE(client); | |||||
break; | |||||
case ssl_test_ticket_aead_open_soft_fail: | |||||
ASSERT_TRUE(client); | |||||
EXPECT_FALSE(SSL_session_reused(client.get())); | |||||
EXPECT_FALSE(SSL_session_reused(server.get())); | |||||
} | |||||
} | |||||
INSTANTIATE_TEST_CASE_P( | |||||
TicketAEADMethodTests, TicketAEADMethodTest, | |||||
testing::Combine( | |||||
testing::Values(TLS1_2_VERSION /*, TLS1_3_VERSION TODO: enable */), | |||||
testing::Values(0, 1, 2), | |||||
testing::Values(ssl_test_ticket_aead_ok, | |||||
ssl_test_ticket_aead_seal_fail, | |||||
ssl_test_ticket_aead_open_soft_fail, | |||||
ssl_test_ticket_aead_open_hard_fail))); | |||||
// TODO(davidben): Convert this file to GTest properly. | // TODO(davidben): Convert this file to GTest properly. | ||||
TEST(SSLTest, AllTests) { | TEST(SSLTest, AllTests) { | ||||
if (!TestCipherRules() || | if (!TestCipherRules() || | ||||
@@ -2017,10 +2017,18 @@ int ssl_ext_pre_shared_key_parse_clienthello( | |||||
/* TLS 1.3 session tickets are renewed separately as part of the | /* TLS 1.3 session tickets are renewed separately as part of the | ||||
* NewSessionTicket. */ | * NewSessionTicket. */ | ||||
int unused_renew; | int unused_renew; | ||||
if (!tls_process_ticket(ssl, out_session, &unused_renew, CBS_data(&ticket), | |||||
CBS_len(&ticket), NULL, 0)) { | |||||
*out_alert = SSL_AD_INTERNAL_ERROR; | |||||
return 0; | |||||
switch (ssl_process_ticket(ssl, out_session, &unused_renew, CBS_data(&ticket), | |||||
CBS_len(&ticket), NULL, 0)) { | |||||
case ssl_ticket_aead_success: | |||||
break; | |||||
case ssl_ticket_aead_ignore_ticket: | |||||
assert(*out_session == NULL); | |||||
break; | |||||
case ssl_ticket_aead_retry: | |||||
/* TODO: async tickets for TLS 1.3. */ | |||||
case ssl_ticket_aead_error: | |||||
*out_alert = SSL_AD_INTERNAL_ERROR; | |||||
return 0; | |||||
} | } | ||||
return 1; | return 1; | ||||
@@ -3043,12 +3051,12 @@ int ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs) { | |||||
return 1; | return 1; | ||||
} | } | ||||
int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, | |||||
int *out_renew_ticket, const uint8_t *ticket, | |||||
size_t ticket_len, const uint8_t *session_id, | |||||
size_t session_id_len) { | |||||
int ret = 1; /* Most errors are non-fatal. */ | |||||
SSL_CTX *ssl_ctx = ssl->session_ctx; | |||||
static enum ssl_ticket_aead_result_t | |||||
ssl_decrypt_ticket_with_cipher_ctx(SSL *ssl, uint8_t **out, size_t *out_len, | |||||
int *out_renew_ticket, const uint8_t *ticket, | |||||
size_t ticket_len) { | |||||
enum ssl_ticket_aead_result_t ret = ssl_ticket_aead_ignore_ticket; | |||||
const SSL_CTX *const ssl_ctx = ssl->session_ctx; | |||||
uint8_t *plaintext = NULL; | uint8_t *plaintext = NULL; | ||||
HMAC_CTX hmac_ctx; | HMAC_CTX hmac_ctx; | ||||
@@ -3056,23 +3064,12 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, | |||||
EVP_CIPHER_CTX cipher_ctx; | EVP_CIPHER_CTX cipher_ctx; | ||||
EVP_CIPHER_CTX_init(&cipher_ctx); | EVP_CIPHER_CTX_init(&cipher_ctx); | ||||
*out_renew_ticket = 0; | |||||
*out_session = NULL; | |||||
if (SSL_get_options(ssl) & SSL_OP_NO_TICKET) { | |||||
goto done; | |||||
} | |||||
if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { | |||||
goto done; | |||||
} | |||||
/* Ensure there is room for the key name and the largest IV | /* Ensure there is room for the key name and the largest IV | ||||
* |tlsext_ticket_key_cb| may try to consume. The real limit may be lower, but | * |tlsext_ticket_key_cb| may try to consume. The real limit may be lower, but | ||||
* the maximum IV length should be well under the minimum size for the | * the maximum IV length should be well under the minimum size for the | ||||
* session material and HMAC. */ | * session material and HMAC. */ | ||||
if (ticket_len < SSL_TICKET_KEY_NAME_LEN + EVP_MAX_IV_LENGTH) { | if (ticket_len < SSL_TICKET_KEY_NAME_LEN + EVP_MAX_IV_LENGTH) { | ||||
goto done; | |||||
goto out; | |||||
} | } | ||||
const uint8_t *iv = ticket + SSL_TICKET_KEY_NAME_LEN; | const uint8_t *iv = ticket + SSL_TICKET_KEY_NAME_LEN; | ||||
@@ -3081,28 +3078,26 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, | |||||
ssl, (uint8_t *)ticket /* name */, (uint8_t *)iv, &cipher_ctx, | ssl, (uint8_t *)ticket /* name */, (uint8_t *)iv, &cipher_ctx, | ||||
&hmac_ctx, 0 /* decrypt */); | &hmac_ctx, 0 /* decrypt */); | ||||
if (cb_ret < 0) { | if (cb_ret < 0) { | ||||
ret = 0; | |||||
goto done; | |||||
} | |||||
if (cb_ret == 0) { | |||||
goto done; | |||||
} | |||||
if (cb_ret == 2) { | |||||
ret = ssl_ticket_aead_error; | |||||
goto out; | |||||
} else if (cb_ret == 0) { | |||||
goto out; | |||||
} else if (cb_ret == 2) { | |||||
*out_renew_ticket = 1; | *out_renew_ticket = 1; | ||||
} | } | ||||
} else { | } else { | ||||
/* Check the key name matches. */ | /* Check the key name matches. */ | ||||
if (OPENSSL_memcmp(ticket, ssl_ctx->tlsext_tick_key_name, | if (OPENSSL_memcmp(ticket, ssl_ctx->tlsext_tick_key_name, | ||||
SSL_TICKET_KEY_NAME_LEN) != 0) { | SSL_TICKET_KEY_NAME_LEN) != 0) { | ||||
goto done; | |||||
goto out; | |||||
} | } | ||||
if (!HMAC_Init_ex(&hmac_ctx, ssl_ctx->tlsext_tick_hmac_key, | if (!HMAC_Init_ex(&hmac_ctx, ssl_ctx->tlsext_tick_hmac_key, | ||||
sizeof(ssl_ctx->tlsext_tick_hmac_key), tlsext_tick_md(), | sizeof(ssl_ctx->tlsext_tick_hmac_key), tlsext_tick_md(), | ||||
NULL) || | NULL) || | ||||
!EVP_DecryptInit_ex(&cipher_ctx, EVP_aes_128_cbc(), NULL, | !EVP_DecryptInit_ex(&cipher_ctx, EVP_aes_128_cbc(), NULL, | ||||
ssl_ctx->tlsext_tick_aes_key, iv)) { | ssl_ctx->tlsext_tick_aes_key, iv)) { | ||||
ret = 0; | |||||
goto done; | |||||
ret = ssl_ticket_aead_error; | |||||
goto out; | |||||
} | } | ||||
} | } | ||||
size_t iv_len = EVP_CIPHER_CTX_iv_length(&cipher_ctx); | size_t iv_len = EVP_CIPHER_CTX_iv_length(&cipher_ctx); | ||||
@@ -3112,7 +3107,7 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, | |||||
size_t mac_len = HMAC_size(&hmac_ctx); | size_t mac_len = HMAC_size(&hmac_ctx); | ||||
if (ticket_len < SSL_TICKET_KEY_NAME_LEN + iv_len + 1 + mac_len) { | if (ticket_len < SSL_TICKET_KEY_NAME_LEN + iv_len + 1 + mac_len) { | ||||
/* The ticket must be large enough for key name, IV, data, and MAC. */ | /* The ticket must be large enough for key name, IV, data, and MAC. */ | ||||
goto done; | |||||
goto out; | |||||
} | } | ||||
HMAC_Update(&hmac_ctx, ticket, ticket_len - mac_len); | HMAC_Update(&hmac_ctx, ticket, ticket_len - mac_len); | ||||
HMAC_Final(&hmac_ctx, mac, NULL); | HMAC_Final(&hmac_ctx, mac, NULL); | ||||
@@ -3122,7 +3117,7 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, | |||||
mac_ok = 1; | mac_ok = 1; | ||||
#endif | #endif | ||||
if (!mac_ok) { | if (!mac_ok) { | ||||
goto done; | |||||
goto out; | |||||
} | } | ||||
/* Decrypt the session data. */ | /* Decrypt the session data. */ | ||||
@@ -3131,8 +3126,8 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, | |||||
mac_len; | mac_len; | ||||
plaintext = OPENSSL_malloc(ciphertext_len); | plaintext = OPENSSL_malloc(ciphertext_len); | ||||
if (plaintext == NULL) { | if (plaintext == NULL) { | ||||
ret = 0; | |||||
goto done; | |||||
ret = ssl_ticket_aead_error; | |||||
goto out; | |||||
} | } | ||||
size_t plaintext_len; | size_t plaintext_len; | ||||
#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) | #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) | ||||
@@ -3140,24 +3135,89 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, | |||||
plaintext_len = ciphertext_len; | plaintext_len = ciphertext_len; | ||||
#else | #else | ||||
if (ciphertext_len >= INT_MAX) { | if (ciphertext_len >= INT_MAX) { | ||||
goto done; | |||||
goto out; | |||||
} | } | ||||
int len1, len2; | int len1, len2; | ||||
if (!EVP_DecryptUpdate(&cipher_ctx, plaintext, &len1, ciphertext, | if (!EVP_DecryptUpdate(&cipher_ctx, plaintext, &len1, ciphertext, | ||||
(int)ciphertext_len) || | (int)ciphertext_len) || | ||||
!EVP_DecryptFinal_ex(&cipher_ctx, plaintext + len1, &len2)) { | !EVP_DecryptFinal_ex(&cipher_ctx, plaintext + len1, &len2)) { | ||||
ERR_clear_error(); /* Don't leave an error on the queue. */ | |||||
goto done; | |||||
ERR_clear_error(); | |||||
goto out; | |||||
} | } | ||||
plaintext_len = (size_t)(len1 + len2); | |||||
plaintext_len = (size_t)(len1) + len2; | |||||
#endif | #endif | ||||
*out = plaintext; | |||||
plaintext = NULL; | |||||
*out_len = plaintext_len; | |||||
ret = ssl_ticket_aead_success; | |||||
out: | |||||
OPENSSL_free(plaintext); | |||||
HMAC_CTX_cleanup(&hmac_ctx); | |||||
EVP_CIPHER_CTX_cleanup(&cipher_ctx); | |||||
return ret; | |||||
} | |||||
static enum ssl_ticket_aead_result_t ssl_decrypt_ticket_with_method( | |||||
SSL *ssl, uint8_t **out, size_t *out_len, int *out_renew_ticket, | |||||
const uint8_t *ticket, size_t ticket_len) { | |||||
uint8_t *plaintext = OPENSSL_malloc(ticket_len); | |||||
if (plaintext == NULL) { | |||||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||||
return ssl_ticket_aead_error; | |||||
} | |||||
size_t plaintext_len; | |||||
const enum ssl_ticket_aead_result_t result = | |||||
ssl->session_ctx->ticket_aead_method->open( | |||||
ssl, plaintext, &plaintext_len, ticket_len, ticket, ticket_len); | |||||
if (result == ssl_ticket_aead_success) { | |||||
*out = plaintext; | |||||
plaintext = NULL; | |||||
*out_len = plaintext_len; | |||||
} | |||||
OPENSSL_free(plaintext); | |||||
return result; | |||||
} | |||||
enum ssl_ticket_aead_result_t ssl_process_ticket( | |||||
SSL *ssl, SSL_SESSION **out_session, int *out_renew_ticket, | |||||
const uint8_t *ticket, size_t ticket_len, const uint8_t *session_id, | |||||
size_t session_id_len) { | |||||
*out_renew_ticket = 0; | |||||
*out_session = NULL; | |||||
if ((SSL_get_options(ssl) & SSL_OP_NO_TICKET) || | |||||
session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { | |||||
return ssl_ticket_aead_ignore_ticket; | |||||
} | |||||
uint8_t *plaintext = NULL; | |||||
size_t plaintext_len; | |||||
enum ssl_ticket_aead_result_t result; | |||||
if (ssl->session_ctx->ticket_aead_method != NULL) { | |||||
result = ssl_decrypt_ticket_with_method( | |||||
ssl, &plaintext, &plaintext_len, out_renew_ticket, ticket, ticket_len); | |||||
} else { | |||||
result = ssl_decrypt_ticket_with_cipher_ctx( | |||||
ssl, &plaintext, &plaintext_len, out_renew_ticket, ticket, ticket_len); | |||||
} | |||||
if (result != ssl_ticket_aead_success) { | |||||
return result; | |||||
} | |||||
/* Decode the session. */ | /* Decode the session. */ | ||||
SSL_SESSION *session = | SSL_SESSION *session = | ||||
SSL_SESSION_from_bytes(plaintext, plaintext_len, ssl->ctx); | SSL_SESSION_from_bytes(plaintext, plaintext_len, ssl->ctx); | ||||
OPENSSL_free(plaintext); | |||||
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; | |||||
return ssl_ticket_aead_ignore_ticket; | |||||
} | } | ||||
/* Copy the client's session ID into the new session, to denote the ticket has | /* Copy the client's session ID into the new session, to denote the ticket has | ||||
@@ -3166,12 +3226,7 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, | |||||
session->session_id_length = session_id_len; | session->session_id_length = session_id_len; | ||||
*out_session = session; | *out_session = session; | ||||
done: | |||||
OPENSSL_free(plaintext); | |||||
HMAC_CTX_cleanup(&hmac_ctx); | |||||
EVP_CIPHER_CTX_cleanup(&cipher_ctx); | |||||
return ret; | |||||
return ssl_ticket_aead_success; | |||||
} | } | ||||
int tls1_parse_peer_sigalgs(SSL_HANDSHAKE *hs, const CBS *in_sigalgs) { | int tls1_parse_peer_sigalgs(SSL_HANDSHAKE *hs, const CBS *in_sigalgs) { | ||||