diff options
author | Todd Short <tshort@akamai.com> | 2017-03-15 13:25:55 -0400 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2018-03-12 10:31:09 +0000 |
commit | df0fed9aab239e2e9a269d06637a6442051dee3b (patch) | |
tree | c2c6c9ea189603c90dad7bd60814143f2c267800 | |
parent | f1c00b93e2138e5a45e8b500dec6bb3b2e035771 (diff) |
Session Ticket app data
Adds application data into the encrypted session ticket
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3802)
-rw-r--r-- | doc/man3/SSL_CTX_set_session_ticket_cb.pod | 149 | ||||
-rw-r--r-- | include/openssl/ssl.h | 32 | ||||
-rw-r--r-- | ssl/ssl_asn1.c | 20 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 11 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 37 | ||||
-rw-r--r-- | ssl/ssl_sess.c | 48 | ||||
-rw-r--r-- | ssl/statem/extensions_srvr.c | 6 | ||||
-rw-r--r-- | ssl/statem/statem_srvr.c | 4 | ||||
-rw-r--r-- | ssl/t1_lib.c | 84 | ||||
-rw-r--r-- | test/handshake_helper.c | 44 | ||||
-rw-r--r-- | test/handshake_helper.h | 2 | ||||
-rw-r--r-- | test/recipes/80-test_ssl_new.t | 2 | ||||
-rw-r--r-- | test/ssl-tests/27-ticket-appdata.conf | 146 | ||||
-rw-r--r-- | test/ssl-tests/27-ticket-appdata.conf.in | 99 | ||||
-rw-r--r-- | test/ssl_test.c | 22 | ||||
-rw-r--r-- | test/ssl_test_ctx.c | 10 | ||||
-rw-r--r-- | test/ssl_test_ctx.h | 3 | ||||
-rw-r--r-- | test/ssl_test_ctx_test.c | 4 | ||||
-rw-r--r-- | util/libssl.num | 3 | ||||
-rw-r--r-- | util/private.num | 2 |
20 files changed, 661 insertions, 67 deletions
diff --git a/doc/man3/SSL_CTX_set_session_ticket_cb.pod b/doc/man3/SSL_CTX_set_session_ticket_cb.pod new file mode 100644 index 0000000000..e9aeb909f0 --- /dev/null +++ b/doc/man3/SSL_CTX_set_session_ticket_cb.pod @@ -0,0 +1,149 @@ +=pod + +=head1 NAME + +SSL_CTX_set_session_ticket_cb, +SSL_SESSION_get0_ticket_appdata, +SSL_SESSION_set1_ticket_appdata, +SSL_CTX_generate_session_ticket_fn, +SSL_CTX_decrypt_session_ticket_fn - manage session ticket application data + +=head1 SYNOPSIS + + #include <openssl/ssl.h> + + typedef int (*SSL_CTX_generate_session_ticket_fn)(SSL *s, void *arg); + typedef SSL_TICKET_RETURN (*SSL_CTX_decrypt_session_ticket_fn)(SSL *s, SSL_SESSION *ss, + const unsigned char *keyname, + size_t keyname_len, + SSL_TICKET_RETURN retv, + void *arg); + int SSL_CTX_set_session_ticket_cb(SSL_CTX *ctx, + SSL_CTX_generate_session_ticket_fn gen_cb, + SSL_CTX_decrypt_session_ticket_fn dec_cb, + void *arg); + int SSL_SESSION_set1_ticket_appdata(SSL_SESSION *ss, const void *data, size_t len); + int SSL_SESSION_get0_ticket_appdata(SSL_SESSION *ss, void **data, size_t *len); + +=head1 DESCRIPTION + +SSL_CTX_set_set_session_ticket_cb() sets the application callbacks B<gen_cb> +and B<dec_cb> that are used by a server to set and get application data stored +with a session, and placed into a session ticket. Either callback function may +be set to NULL. The value of B<arg> is passed to the callbacks. + +B<gen_cb> is the application defined callback invoked when a session ticket is +about to be created. The application can call SSL_SESSION_set1_ticket_appdata() +at this time to add application data to the session ticket. The value of B<arg> +is the same as that given to SSL_CTX_set_session_ticket_cb(). The B<gen_cb> +callback is defined as type B<SSL_CTX_generate_session_ticket_fn>. + +B<dec_cb> is the application defined callback invoked after session ticket +decryption has been attempted and any session ticket application data is available. +The application can call SSL_SESSION_get_ticket_appdata() at this time to retrieve +the application data. The value of B<arg> is the same as that given to +SSL_CTX_set_session_ticket_cb(). The B<retv> arguement is the result of the ticket +decryption. The B<keyname> and B<keyname_len> identify the key used to decrypt the +session ticket. The B<dec_cb> callback is defined as type +B<SSL_CTX_decrypt_session_ticket_fn>. + +SSL_SESSION_set1_ticket_appdata() sets the application data specified by +B<data> and B<len> into B<ss> which is then placed into any generated session +tickets. It can be called at any time before a session ticket is created to +update the data placed into the session ticket. However, given that sessions +and tickets are created by the handshake, the B<gen_cb> is provided to notify +the application that a session ticket is about to be generated. + +SSL_SESSION_get0_ticket_appdata() assigns B<data> to the session ticket +application data and assigns B<len> to the length of the session ticket +application data from B<ss>. The application data can be set via +SSL_SESSION_set1_ticket_appdata() or by a session ticket. NULL will be assigned +to B<data> and 0 will be assigned to B<len> if there is no session ticket +application data. SSL_SESSION_get0_ticket_appdata() can be called any time +after a session has been created. The B<dec_cb> is provided to notify the +application that a session ticket has just been decrypted. + +=head1 NOTES + +When the B<dec_cb> callback is invoked, the SSL_SESSION B<ss> has not yet been +assigned to the SSL B<s>. The B<retv> indicates the result of the ticket +decryption which can be modified by the callback before being returned. The +callback must check the B<retv> value before performing any action, as it's +called even if ticket decryption fails. + +The B<keyname> and B<keyname_len> arguments to B<dec_cb> may be used to identify +the key that was used to encrypt the session ticket. + +When the B<gen_cb> callback is invoked, the SSL_get_session() function can be +used to retrieve the SSL_SESSION for SSL_SESSION_set1_ticket_appdata(). + +=head1 RETURN VALUES + +The SSL_CTX_set_session_ticket_cb(), SSL_SESSION_set1_ticket_appdata() and +SSL_SESSION_get0_ticket_appdata() functions return 1 on success and 0 on +failure. + +The B<gen_cb> callback must return 1 to continue the connection. A return of 0 +will terminate the connection with an INTERNAL_ERROR alert. + +The B<dec_cb> callback must return one of the following B<SSL_TICKET_RETURN> +values. Under normal circumstances the B<retv> value is returned unmodified, +but the callback can change the behavior of the post-ticket decryption code +by returning something different. The B<dec_cb> callback must check the B<retv> +value before performing any action. + + typedef int SSL_TICKET_RETURN; + +=over 4 + +=item SSL_TICKET_FATAL_ERR_MALLOC + +Fatal error, malloc failure. + +=item SSL_TICKET_FATAL_ERR_OTHER + +Fatal error, either from parsing or decrypting the ticket. + +=item SSL_TICKET_NONE + +No ticket present. + +=item SSL_TICKET_EMPTY + +Empty ticket present. + +=item SSL_TICKET_NO_DECRYPT + +The ticket couldn't be decrypted. + +=item SSL_TICKET_SUCCESS + +A ticket was successfully decrypted, any session ticket application data should +be available. + +=item TICKET_SUCCESS_RENEW + +Same as B<TICKET_SUCCESS>, but the ticket needs to be renewed. + +=back + +=head1 SEE ALSO + +L<ssl(7)>, +L<SSL_get_session(3)> + +=head1 HISTORY + +SSL_CTX_set_session_ticket_cb(), SSSL_SESSION_set1_ticket_appdata() and +SSL_SESSION_get_ticket_appdata() were added to OpenSSL 1.1.1. + +=head1 COPYRIGHT + +Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the OpenSSL license (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L<https://www.openssl.org/source/license.html>. + +=cut diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 3561dee33b..a47975d355 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2294,6 +2294,38 @@ __owur const struct openssl_ssl_test_functions *SSL_test_functions(void); __owur int SSL_free_buffers(SSL *ssl); __owur int SSL_alloc_buffers(SSL *ssl); +/* Return codes for tls_get_ticket_from_client() and tls_decrypt_ticket() */ +typedef int SSL_TICKET_RETURN; + +/* Support for ticket appdata */ +/* fatal error, malloc failure */ +# define SSL_TICKET_FATAL_ERR_MALLOC 0 +/* fatal error, either from parsing or decrypting the ticket */ +# define SSL_TICKET_FATAL_ERR_OTHER 1 +/* No ticket present */ +# define SSL_TICKET_NONE 2 +/* Empty ticket present */ +# define SSL_TICKET_EMPTY 3 +/* the ticket couldn't be decrypted */ +# define SSL_TICKET_NO_DECRYPT 4 +/* a ticket was successfully decrypted */ +# define SSL_TICKET_SUCCESS 5 +/* same as above but the ticket needs to be renewed */ +# define SSL_TICKET_SUCCESS_RENEW 6 + +typedef int (*SSL_CTX_generate_session_ticket_fn)(SSL *s, void *arg); +typedef SSL_TICKET_RETURN (*SSL_CTX_decrypt_session_ticket_fn)(SSL *s, SSL_SESSION *ss, + const unsigned char *keyname, + size_t keyname_length, + SSL_TICKET_RETURN retv, + void *arg); +int SSL_CTX_set_session_ticket_cb(SSL_CTX *ctx, + SSL_CTX_generate_session_ticket_fn gen_cb, + SSL_CTX_decrypt_session_ticket_fn dec_cb, + void *arg); +int SSL_SESSION_set1_ticket_appdata(SSL_SESSION *ss, const void *data, size_t len); +int SSL_SESSION_get0_ticket_appdata(SSL_SESSION *ss, void **data, size_t *len); + extern const char SSL_version_str[]; diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c index 9327b339ca..7d39ba15c0 100644 --- a/ssl/ssl_asn1.c +++ b/ssl/ssl_asn1.c @@ -43,6 +43,7 @@ typedef struct { ASN1_OCTET_STRING *alpn_selected; ASN1_OCTET_STRING *tick_nonce; uint32_t tlsext_max_fragment_len_mode; + ASN1_OCTET_STRING *ticket_appdata; } SSL_SESSION_ASN1; ASN1_SEQUENCE(SSL_SESSION_ASN1) = { @@ -73,7 +74,8 @@ ASN1_SEQUENCE(SSL_SESSION_ASN1) = { ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, max_early_data, ZUINT32, 15), ASN1_EXP_OPT(SSL_SESSION_ASN1, alpn_selected, ASN1_OCTET_STRING, 16), ASN1_EXP_OPT(SSL_SESSION_ASN1, tick_nonce, ASN1_OCTET_STRING, 17), - ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_max_fragment_len_mode, ZUINT32, 18) + ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_max_fragment_len_mode, ZUINT32, 18), + ASN1_EXP_OPT(SSL_SESSION_ASN1, ticket_appdata, ASN1_OCTET_STRING, 19) } static_ASN1_SEQUENCE_END(SSL_SESSION_ASN1) IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(SSL_SESSION_ASN1) @@ -123,6 +125,7 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) #endif ASN1_OCTET_STRING alpn_selected; ASN1_OCTET_STRING tick_nonce; + ASN1_OCTET_STRING ticket_appdata; long l; @@ -200,6 +203,12 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) as.tlsext_max_fragment_len_mode = in->ext.max_fragment_len_mode; + if (in->ticket_appdata == NULL) + as.ticket_appdata = NULL; + else + ssl_session_oinit(&as.ticket_appdata, &ticket_appdata, + in->ticket_appdata, in->ticket_appdata_len); + return i2d_SSL_SESSION_ASN1(&as, pp); } @@ -376,6 +385,15 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, ret->ext.max_fragment_len_mode = as->tlsext_max_fragment_len_mode; + if (as->ticket_appdata != NULL) { + ret->ticket_appdata = as->ticket_appdata->data; + ret->ticket_appdata_len = as->ticket_appdata->length; + as->ticket_appdata->data = NULL; + } else { + ret->ticket_appdata = NULL; + ret->ticket_appdata_len = 0; + } + M_ASN1_free_of(as, SSL_SESSION_ASN1); if ((a != NULL) && (*a == NULL)) diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index f5219c22d1..0814fb362b 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -5409,3 +5409,14 @@ int SSL_verify_client_post_handshake(SSL *ssl) ossl_statem_set_in_init(ssl, 1); return 1; } + +int SSL_CTX_set_session_ticket_cb(SSL_CTX *ctx, + SSL_CTX_generate_session_ticket_fn gen_cb, + SSL_CTX_decrypt_session_ticket_fn dec_cb, + void *arg) +{ + ctx->generate_ticket_cb = gen_cb; + ctx->decrypt_ticket_cb = dec_cb; + ctx->ticket_cb_data = arg; + return 1; +} diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index f179efa231..9eb58342a8 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -591,6 +591,8 @@ struct ssl_session_st { # ifndef OPENSSL_NO_SRP char *srp_username; # endif + unsigned char *ticket_appdata; + size_t ticket_appdata_len; uint32_t flags; CRYPTO_RWLOCK *lock; }; @@ -1025,6 +1027,11 @@ struct ssl_ctx_st { size_t (*record_padding_cb)(SSL *s, int type, size_t len, void *arg); void *record_padding_arg; size_t block_padding; + + /* Session ticket appdata */ + SSL_CTX_generate_session_ticket_fn generate_ticket_cb; + SSL_CTX_decrypt_session_ticket_fn decrypt_ticket_cb; + void *ticket_cb_data; }; struct ssl_st { @@ -2446,30 +2453,12 @@ void tls1_get_supported_groups(SSL *s, const uint16_t **pgroups, __owur int tls1_set_server_sigalgs(SSL *s); -/* Return codes for tls_get_ticket_from_client() and tls_decrypt_ticket() */ -typedef enum ticket_en { - /* fatal error, malloc failure */ - TICKET_FATAL_ERR_MALLOC, - /* fatal error, either from parsing or decrypting the ticket */ - TICKET_FATAL_ERR_OTHER, - /* No ticket present */ - TICKET_NONE, - /* Empty ticket present */ - TICKET_EMPTY, - /* the ticket couldn't be decrypted */ - TICKET_NO_DECRYPT, - /* a ticket was successfully decrypted */ - TICKET_SUCCESS, - /* same as above but the ticket needs to be renewed */ - TICKET_SUCCESS_RENEW -} TICKET_RETURN; - -__owur TICKET_RETURN tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, - SSL_SESSION **ret); -__owur TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, - size_t eticklen, - const unsigned char *sess_id, - size_t sesslen, SSL_SESSION **psess); +__owur SSL_TICKET_RETURN tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, + SSL_SESSION **ret); +__owur SSL_TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, + size_t eticklen, + const unsigned char *sess_id, + size_t sesslen, SSL_SESSION **psess); __owur int tls_use_ticket(SSL *s); diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index 5d2e1719be..f78c9cde5f 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -134,6 +134,7 @@ SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) dest->peer_chain = NULL; dest->peer = NULL; dest->ext.tick_nonce = NULL; + dest->ticket_appdata = NULL; memset(&dest->ex_data, 0, sizeof(dest->ex_data)); /* We deliberately don't copy the prev and next pointers */ @@ -244,6 +245,13 @@ SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) } #endif + if (src->ticket_appdata != NULL) { + dest->ticket_appdata = + OPENSSL_memdup(src->ticket_appdata, src->ticket_appdata_len); + if (dest->ticket_appdata == NULL) + goto err; + } + return dest; err: SSLerr(SSL_F_SSL_SESSION_DUP, ERR_R_MALLOC_FAILURE); @@ -471,7 +479,7 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) SSL_SESSION *ret = NULL; int fatal = 0, discard; int try_session_cache = 0; - TICKET_RETURN r; + SSL_TICKET_RETURN r; if (SSL_IS_TLS13(s)) { if (!tls_parse_extension(s, TLSEXT_IDX_psk_kex_modes, @@ -486,20 +494,20 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) /* sets s->ext.ticket_expected */ r = tls_get_ticket_from_client(s, hello, &ret); switch (r) { - case TICKET_FATAL_ERR_MALLOC: - case TICKET_FATAL_ERR_OTHER: + case SSL_TICKET_FATAL_ERR_MALLOC: + case SSL_TICKET_FATAL_ERR_OTHER: fatal = 1; SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GET_PREV_SESSION, ERR_R_INTERNAL_ERROR); goto err; - case TICKET_NONE: - case TICKET_EMPTY: + case SSL_TICKET_NONE: + case SSL_TICKET_EMPTY: if (hello->session_id_len > 0) try_session_cache = 1; break; - case TICKET_NO_DECRYPT: - case TICKET_SUCCESS: - case TICKET_SUCCESS_RENEW: + case SSL_TICKET_NO_DECRYPT: + case SSL_TICKET_SUCCESS: + case SSL_TICKET_SUCCESS_RENEW: break; } } @@ -806,6 +814,7 @@ void SSL_SESSION_free(SSL_SESSION *ss) #endif OPENSSL_free(ss->ext.alpn_selected); OPENSSL_free(ss->ext.tick_nonce); + OPENSSL_free(ss->ticket_appdata); CRYPTO_THREAD_lock_free(ss->lock); OPENSSL_clear_free(ss, sizeof(*ss)); } @@ -1269,4 +1278,27 @@ void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, ctx->app_verify_cookie_cb = cb; } +int SSL_SESSION_set1_ticket_appdata(SSL_SESSION *ss, const void *data, size_t len) +{ + OPENSSL_free(ss->ticket_appdata); + ss->ticket_appdata_len = 0; + if (data == NULL || len == 0) { + ss->ticket_appdata = NULL; + return 1; + } + ss->ticket_appdata = OPENSSL_memdup(data, len); + if (ss->ticket_appdata != NULL) { + ss->ticket_appdata_len = len; + return 1; + } + return 0; +} + +int SSL_SESSION_get0_ticket_appdata(SSL_SESSION *ss, void **data, size_t *len) +{ + *data = ss->ticket_appdata; + *len = ss->ticket_appdata_len; + return 1; +} + IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION) diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index b9692f46e4..74acdb2d21 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1124,13 +1124,13 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, PACKET_remaining(&identity), NULL, 0, &sess); - if (ret == TICKET_FATAL_ERR_MALLOC - || ret == TICKET_FATAL_ERR_OTHER) { + if (ret == SSL_TICKET_FATAL_ERR_MALLOC + || ret == SSL_TICKET_FATAL_ERR_OTHER) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK, ERR_R_INTERNAL_ERROR); return 0; } - if (ret == TICKET_NO_DECRYPT) + if (ret == SSL_TICKET_NO_DECRYPT) continue; ticket_age = (uint32_t)ticket_agel; diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 8092684af7..041089cf96 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -3728,6 +3728,10 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) s->session->ext.max_early_data = s->max_early_data; } + if (tctx->generate_ticket_cb != NULL && + tctx->generate_ticket_cb(s, tctx->ticket_cb_data) == 0) + goto err; + /* get session encoding length */ slen_full = i2d_SSL_SESSION(s->session, NULL); /* diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 8b0d9aa309..596fdd4c34 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -1205,8 +1205,8 @@ int tls1_set_server_sigalgs(SSL *s) * s->ctx->ext.ticket_key_cb asked to renew the client's ticket. * Otherwise, s->ext.ticket_expected is set to 0. */ -TICKET_RETURN tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, - SSL_SESSION **ret) +SSL_TICKET_RETURN tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, + SSL_SESSION **ret) { int retv; size_t size; @@ -1221,11 +1221,11 @@ TICKET_RETURN tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, * resumption. */ if (s->version <= SSL3_VERSION || !tls_use_ticket(s)) - return TICKET_NONE; + return SSL_TICKET_NONE; ticketext = &hello->pre_proc_exts[TLSEXT_IDX_session_ticket]; if (!ticketext->present) - return TICKET_NONE; + return SSL_TICKET_NONE; size = PACKET_remaining(&ticketext->data); if (size == 0) { @@ -1234,7 +1234,7 @@ TICKET_RETURN tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, * one. */ s->ext.ticket_expected = 1; - return TICKET_EMPTY; + return SSL_TICKET_EMPTY; } if (s->ext.session_secret_cb) { /* @@ -1243,25 +1243,49 @@ TICKET_RETURN tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, * abbreviated handshake based on external mechanism to * calculate the master secret later. */ - return TICKET_NO_DECRYPT; + return SSL_TICKET_NO_DECRYPT; } retv = tls_decrypt_ticket(s, PACKET_data(&ticketext->data), size, hello->session_id, hello->session_id_len, ret); + + /* + * If set, the decrypt_ticket_cb() is always called regardless of the + * return from tls_decrypt_ticket(). The callback is responsible for + * checking |retv| before it performs any action + */ + if (s->session_ctx->decrypt_ticket_cb != NULL) { + size_t keyname_len = size; + + if (keyname_len > TLSEXT_KEYNAME_LENGTH) + keyname_len = TLSEXT_KEYNAME_LENGTH; + retv = s->session_ctx->decrypt_ticket_cb(s, *ret, + PACKET_data(&ticketext->data), + keyname_len, + retv, s->session_ctx->ticket_cb_data); + } + switch (retv) { - case TICKET_NO_DECRYPT: + case SSL_TICKET_NO_DECRYPT: s->ext.ticket_expected = 1; - return TICKET_NO_DECRYPT; + return SSL_TICKET_NO_DECRYPT; + + case SSL_TICKET_SUCCESS: + return SSL_TICKET_SUCCESS; - case TICKET_SUCCESS: - return TICKET_SUCCESS; + case SSL_TICKET_SUCCESS_RENEW: + s->ext.ticket_expected = 1; + return SSL_TICKET_SUCCESS; - case TICKET_SUCCESS_RENEW: + case SSL_TICKET_EMPTY: s->ext.ticket_expected = 1; - return TICKET_SUCCESS; + return SSL_TICKET_EMPTY; + + case SSL_TICKET_NONE: + return SSL_TICKET_NONE; default: - return TICKET_FATAL_ERR_OTHER; + return SSL_TICKET_FATAL_ERR_OTHER; } } @@ -1275,15 +1299,15 @@ TICKET_RETURN tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, * psess: (output) on return, if a ticket was decrypted, then this is set to * point to the resulting session. */ -TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, - size_t eticklen, const unsigned char *sess_id, - size_t sesslen, SSL_SESSION **psess) +SSL_TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, + size_t eticklen, const unsigned char *sess_id, + size_t sesslen, SSL_SESSION **psess) { SSL_SESSION *sess; unsigned char *sdec; const unsigned char *p; int slen, renew_ticket = 0, declen; - TICKET_RETURN ret = TICKET_FATAL_ERR_OTHER; + SSL_TICKET_RETURN ret = SSL_TICKET_FATAL_ERR_OTHER; size_t mlen; unsigned char tick_hmac[EVP_MAX_MD_SIZE]; HMAC_CTX *hctx = NULL; @@ -1292,17 +1316,17 @@ TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, /* Need at least keyname + iv */ if (eticklen < TLSEXT_KEYNAME_LENGTH + EVP_MAX_IV_LENGTH) { - ret = TICKET_NO_DECRYPT; + ret = SSL_TICKET_NO_DECRYPT; goto err; } /* Initialize session ticket encryption and HMAC contexts */ hctx = HMAC_CTX_new(); if (hctx == NULL) - return TICKET_FATAL_ERR_MALLOC; + return SSL_TICKET_FATAL_ERR_MALLOC; ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { - ret = TICKET_FATAL_ERR_MALLOC; + ret = SSL_TICKET_FATAL_ERR_MALLOC; goto err; } if (tctx->ext.ticket_key_cb) { @@ -1313,7 +1337,7 @@ TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, if (rv < 0) goto err; if (rv == 0) { - ret = TICKET_NO_DECRYPT; + ret = SSL_TICKET_NO_DECRYPT; goto err; } if (rv == 2) @@ -1322,7 +1346,7 @@ TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, /* Check key name matches */ if (memcmp(etick, tctx->ext.tick_key_name, TLSEXT_KEYNAME_LENGTH) != 0) { - ret = TICKET_NO_DECRYPT; + ret = SSL_TICKET_NO_DECRYPT; goto err; } if (HMAC_Init_ex(hctx, tctx->ext.tick_hmac_key, @@ -1345,7 +1369,7 @@ TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, /* Sanity check ticket length: must exceed keyname + IV + HMAC */ if (eticklen <= TLSEXT_KEYNAME_LENGTH + EVP_CIPHER_CTX_iv_length(ctx) + mlen) { - ret = TICKET_NO_DECRYPT; + ret = SSL_TICKET_NO_DECRYPT; goto err; } eticklen -= mlen; @@ -1357,7 +1381,7 @@ TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, HMAC_CTX_free(hctx); if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen)) { EVP_CIPHER_CTX_free(ctx); - return TICKET_NO_DECRYPT; + return SSL_TICKET_NO_DECRYPT; } /* Attempt to decrypt session data */ /* Move p after IV to start of encrypted ticket, update length */ @@ -1368,12 +1392,12 @@ TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, (int)eticklen) <= 0) { EVP_CIPHER_CTX_free(ctx); OPENSSL_free(sdec); - return TICKET_FATAL_ERR_OTHER; + return SSL_TICKET_FATAL_ERR_OTHER; } if (EVP_DecryptFinal(ctx, sdec + slen, &declen) <= 0) { EVP_CIPHER_CTX_free(ctx); OPENSSL_free(sdec); - return TICKET_NO_DECRYPT; + return SSL_TICKET_NO_DECRYPT; } slen += declen; EVP_CIPHER_CTX_free(ctx); @@ -1387,7 +1411,7 @@ TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, /* Some additional consistency checks */ if (slen != 0 || sess->session_id_length != 0) { SSL_SESSION_free(sess); - return TICKET_NO_DECRYPT; + return SSL_TICKET_NO_DECRYPT; } /* * The session ID, if non-empty, is used by some clients to detect @@ -1400,15 +1424,15 @@ TICKET_RETURN tls_decrypt_ticket(SSL *s, const unsigned char *etick, sess->session_id_length = sesslen; *psess = sess; if (renew_ticket) - return TICKET_SUCCESS_RENEW; + return SSL_TICKET_SUCCESS_RENEW; else - return TICKET_SUCCESS; + return SSL_TICKET_SUCCESS; } ERR_clear_error(); /* * For session parse failure, indicate that we need to send a new ticket. */ - return TICKET_NO_DECRYPT; + return SSL_TICKET_NO_DECRYPT; err: EVP_CIPHER_CTX_free(ctx); HMAC_CTX_free(hctx); diff --git a/test/handshake_helper.c b/test/handshake_helper.c index c0265ab3c0..9b781b03c9 100644 --- a/test/handshake_helper.c +++ b/test/handshake_helper.c @@ -38,6 +38,7 @@ void HANDSHAKE_RESULT_free(HANDSHAKE_RESULT *result) OPENSSL_free(result->server_npn_negotiated); OPENSSL_free(result->client_alpn_negotiated); OPENSSL_free(result->server_alpn_negotiated); + OPENSSL_free(result->result_session_ticket_app_data); sk_X509_NAME_pop_free(result->server_ca_names, X509_NAME_free); sk_X509_NAME_pop_free(result->client_ca_names, X509_NAME_free); OPENSSL_free(result->cipher); @@ -64,6 +65,7 @@ typedef struct ctx_data_st { size_t alpn_protocols_len; char *srp_user; char *srp_password; + char *session_ticket_app_data; } CTX_DATA; /* |ctx_data| itself is stack-allocated. */ @@ -77,6 +79,8 @@ static void ctx_data_free_data(CTX_DATA *ctx_data) ctx_data->srp_user = NULL; OPENSSL_free(ctx_data->srp_password); ctx_data->srp_password = NULL; + OPENSSL_free(ctx_data->session_ticket_app_data); + ctx_data->session_ticket_app_data = NULL; } static int ex_data_idx; @@ -453,6 +457,26 @@ static int server_srp_cb(SSL *s, int *ad, void *arg) } #endif /* !OPENSSL_NO_SRP */ +static int generate_session_ticket_cb(SSL *s, void *arg) +{ + CTX_DATA *server_ctx_data = arg; + SSL_SESSION *ss = SSL_get_session(s); + char *app_data = server_ctx_data->session_ticket_app_data; + + if (ss == NULL || app_data == NULL) + return 0; + + return SSL_SESSION_set1_ticket_appdata(ss, app_data, strlen(app_data)); +} + +static SSL_TICKET_RETURN decrypt_session_ticket_cb(SSL *s, SSL_SESSION *ss, + const unsigned char *keyname, + size_t keyname_len, + SSL_TICKET_RETURN retv, void *arg) +{ + return retv; +} + /* * Configure callbacks and other properties that can't be set directly * in the server/client CONF. @@ -607,6 +631,21 @@ static int configure_handshake_ctx(SSL_CTX *server_ctx, SSL_CTX *server2_ctx, OPENSSL_free(alpn_protos); } + if (extra->server.session_ticket_app_data != NULL) { + server_ctx_data->session_ticket_app_data = + OPENSSL_strdup(extra->server.session_ticket_app_data); + SSL_CTX_set_session_ticket_cb(server_ctx, generate_session_ticket_cb, + decrypt_session_ticket_cb, server_ctx_data); + } + if (extra->server2.session_ticket_app_data != NULL) { + if (!TEST_ptr(server2_ctx)) + goto err; + server2_ctx_data->session_ticket_app_data = + OPENSSL_strdup(extra->server2.session_ticket_app_data); + SSL_CTX_set_session_ticket_cb(server2_ctx, NULL, + decrypt_session_ticket_cb, server2_ctx_data); + } + /* * Use fixed session ticket keys so that we can decrypt a ticket created with * one CTX in another CTX. Don't address server2 for the moment. @@ -1583,6 +1622,11 @@ static HANDSHAKE_RESULT *do_handshake_internal( SSL_get0_alpn_selected(server.ssl, &proto, &proto_len); ret->server_alpn_negotiated = dup_str(proto, proto_len); + if ((sess = SSL_get0_session(server.ssl)) != NULL) { + SSL_SESSION_get0_ticket_appdata(sess, (void**)&tick, &tick_len); + ret->result_session_ticket_app_data = OPENSSL_strndup((const char*)tick, tick_len); + } |