summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTodd Short <tshort@akamai.com>2017-03-15 13:25:55 -0400
committerMatt Caswell <matt@openssl.org>2018-03-12 10:31:09 +0000
commitdf0fed9aab239e2e9a269d06637a6442051dee3b (patch)
treec2c6c9ea189603c90dad7bd60814143f2c267800
parentf1c00b93e2138e5a45e8b500dec6bb3b2e035771 (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.pod149
-rw-r--r--include/openssl/ssl.h32
-rw-r--r--ssl/ssl_asn1.c20
-rw-r--r--ssl/ssl_lib.c11
-rw-r--r--ssl/ssl_locl.h37
-rw-r--r--ssl/ssl_sess.c48
-rw-r--r--ssl/statem/extensions_srvr.c6
-rw-r--r--ssl/statem/statem_srvr.c4
-rw-r--r--ssl/t1_lib.c84
-rw-r--r--test/handshake_helper.c44
-rw-r--r--test/handshake_helper.h2
-rw-r--r--test/recipes/80-test_ssl_new.t2
-rw-r--r--test/ssl-tests/27-ticket-appdata.conf146
-rw-r--r--test/ssl-tests/27-ticket-appdata.conf.in99
-rw-r--r--test/ssl_test.c22
-rw-r--r--test/ssl_test_ctx.c10
-rw-r--r--test/ssl_test_ctx.h3
-rw-r--r--test/ssl_test_ctx_test.c4
-rw-r--r--util/libssl.num3
-rw-r--r--util/private.num2
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