Support asynchronous ticket decryption with TLS 1.0–1.2.
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>
diff --git a/ssl/ssl_session.c b/ssl/ssl_session.c
index e11238f..05ae059 100644
--- a/ssl/ssl_session.c
+++ b/ssl/ssl_session.c
@@ -581,16 +581,11 @@
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;
- /* 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_init(&ctx);
HMAC_CTX hctx;
@@ -667,12 +662,60 @@
ret = 1;
err:
- OPENSSL_free(session_buf);
EVP_CIPHER_CTX_cleanup(&ctx);
HMAC_CTX_cleanup(&hctx);
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) {
if (session == NULL) {
return 0;
@@ -811,10 +854,18 @@
SSL_early_callback_ctx_extension_get(
client_hello, TLSEXT_TYPE_session_ticket, &ticket, &ticket_len);
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 {
/* The client didn't send a ticket, so the session ID is a real ID. */