mirror of
https://github.com/openssl/openssl.git
synced 2024-11-27 20:14:20 +08:00
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)
This commit is contained in:
parent
f1c00b93e2
commit
df0fed9aab
149
doc/man3/SSL_CTX_set_session_ticket_cb.pod
Normal file
149
doc/man3/SSL_CTX_set_session_ticket_cb.pod
Normal file
@ -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
|
@ -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[];
|
||||
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
/*
|
||||
|
84
ssl/t1_lib.c
84
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 TICKET_SUCCESS:
|
||||
return TICKET_SUCCESS;
|
||||
case SSL_TICKET_SUCCESS:
|
||||
return SSL_TICKET_SUCCESS;
|
||||
|
||||
case TICKET_SUCCESS_RENEW:
|
||||
case SSL_TICKET_SUCCESS_RENEW:
|
||||
s->ext.ticket_expected = 1;
|
||||
return TICKET_SUCCESS;
|
||||
return SSL_TICKET_SUCCESS;
|
||||
|
||||
case SSL_TICKET_EMPTY:
|
||||
s->ext.ticket_expected = 1;
|
||||
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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
ret->client_resumed = SSL_session_reused(client.ssl);
|
||||
ret->server_resumed = SSL_session_reused(server.ssl);
|
||||
|
||||
|
@ -65,6 +65,8 @@ typedef struct handshake_result {
|
||||
/* Session id status */
|
||||
ssl_session_id_t session_id;
|
||||
char *cipher;
|
||||
/* session ticket application data */
|
||||
char *result_session_ticket_app_data;
|
||||
} HANDSHAKE_RESULT;
|
||||
|
||||
HANDSHAKE_RESULT *HANDSHAKE_RESULT_new(void);
|
||||
|
@ -28,7 +28,7 @@ map { s/\^// } @conf_files if $^O eq "VMS";
|
||||
|
||||
# We hard-code the number of tests to double-check that the globbing above
|
||||
# finds all files as expected.
|
||||
plan tests => 26; # = scalar @conf_srcs
|
||||
plan tests => 27; # = scalar @conf_srcs
|
||||
|
||||
# Some test results depend on the configuration of enabled protocols. We only
|
||||
# verify generated sources in the default configuration.
|
||||
|
146
test/ssl-tests/27-ticket-appdata.conf
Normal file
146
test/ssl-tests/27-ticket-appdata.conf
Normal file
@ -0,0 +1,146 @@
|
||||
# Generated with generate_ssl_tests.pl
|
||||
|
||||
num_tests = 4
|
||||
|
||||
test-0 = 0-session-ticket-app-data12
|
||||
test-1 = 1-session-ticket-app-data12
|
||||
test-2 = 2-session-ticket-app-data13
|
||||
test-3 = 3-session-ticket-app-data13
|
||||
# ===========================================================
|
||||
|
||||
[0-session-ticket-app-data12]
|
||||
ssl_conf = 0-session-ticket-app-data12-ssl
|
||||
|
||||
[0-session-ticket-app-data12-ssl]
|
||||
server = 0-session-ticket-app-data12-server
|
||||
client = 0-session-ticket-app-data12-client
|
||||
resume-server = 0-session-ticket-app-data12-server
|
||||
resume-client = 0-session-ticket-app-data12-client
|
||||
|
||||
[0-session-ticket-app-data12-server]
|
||||
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
|
||||
CipherString = DEFAULT
|
||||
Options = SessionTicket
|
||||
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
|
||||
|
||||
[0-session-ticket-app-data12-client]
|
||||
CipherString = DEFAULT
|
||||
MaxProtocol = TLSv1.2
|
||||
Options = SessionTicket
|
||||
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
|
||||
VerifyMode = Peer
|
||||
|
||||
[test-0]
|
||||
ExpectedResult = Success
|
||||
ExpectedSessionTicketAppData = HelloWorld
|
||||
HandshakeMode = Resume
|
||||
ResumptionExpected = Yes
|
||||
SessionTicketExpected = Yes
|
||||
server = 0-session-ticket-app-data12-server-extra
|
||||
resume-server = 0-session-ticket-app-data12-server-extra
|
||||
|
||||
[0-session-ticket-app-data12-server-extra]
|
||||
SessionTicketAppData = HelloWorld
|
||||
|
||||
|
||||
# ===========================================================
|
||||
|
||||
[1-session-ticket-app-data12]
|
||||
ssl_conf = 1-session-ticket-app-data12-ssl
|
||||
|
||||
[1-session-ticket-app-data12-ssl]
|
||||
server = 1-session-ticket-app-data12-server
|
||||
client = 1-session-ticket-app-data12-client
|
||||
resume-server = 1-session-ticket-app-data12-server
|
||||
resume-client = 1-session-ticket-app-data12-client
|
||||
|
||||
[1-session-ticket-app-data12-server]
|
||||
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
|
||||
CipherString = DEFAULT
|
||||
Options = SessionTicket
|
||||
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
|
||||
|
||||
[1-session-ticket-app-data12-client]
|
||||
CipherString = DEFAULT
|
||||
MaxProtocol = TLSv1.2
|
||||
Options = SessionTicket
|
||||
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
|
||||
VerifyMode = Peer
|
||||
|
||||
[test-1]
|
||||
ExpectedResult = Success
|
||||
ExpectedSessionTicketAppData =
|
||||
HandshakeMode = Resume
|
||||
ResumptionExpected = Yes
|
||||
SessionTicketExpected = Yes
|
||||
|
||||
|
||||
# ===========================================================
|
||||
|
||||
[2-session-ticket-app-data13]
|
||||
ssl_conf = 2-session-ticket-app-data13-ssl
|
||||
|
||||
[2-session-ticket-app-data13-ssl]
|
||||
server = 2-session-ticket-app-data13-server
|
||||
client = 2-session-ticket-app-data13-client
|
||||
resume-server = 2-session-ticket-app-data13-server
|
||||
resume-client = 2-session-ticket-app-data13-client
|
||||
|
||||
[2-session-ticket-app-data13-server]
|
||||
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
|
||||
CipherString = DEFAULT
|
||||
Options = SessionTicket
|
||||
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
|
||||
|
||||
[2-session-ticket-app-data13-client]
|
||||
CipherString = DEFAULT
|
||||
MaxProtocol = TLSv1.3
|
||||
Options = SessionTicket
|
||||
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
|
||||
VerifyMode = Peer
|
||||
|
||||
[test-2]
|
||||
ExpectedResult = Success
|
||||
ExpectedSessionTicketAppData = HelloWorld
|
||||
HandshakeMode = Resume
|
||||
ResumptionExpected = Yes
|
||||
SessionTicketExpected = Yes
|
||||
server = 2-session-ticket-app-data13-server-extra
|
||||
resume-server = 2-session-ticket-app-data13-server-extra
|
||||
|
||||
[2-session-ticket-app-data13-server-extra]
|
||||
SessionTicketAppData = HelloWorld
|
||||
|
||||
|
||||
# ===========================================================
|
||||
|
||||
[3-session-ticket-app-data13]
|
||||
ssl_conf = 3-session-ticket-app-data13-ssl
|
||||
|
||||
[3-session-ticket-app-data13-ssl]
|
||||
server = 3-session-ticket-app-data13-server
|
||||
client = 3-session-ticket-app-data13-client
|
||||
resume-server = 3-session-ticket-app-data13-server
|
||||
resume-client = 3-session-ticket-app-data13-client
|
||||
|
||||
[3-session-ticket-app-data13-server]
|
||||
Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
|
||||
CipherString = DEFAULT
|
||||
Options = SessionTicket
|
||||
PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
|
||||
|
||||
[3-session-ticket-app-data13-client]
|
||||
CipherString = DEFAULT
|
||||
MaxProtocol = TLSv1.3
|
||||
Options = SessionTicket
|
||||
VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
|
||||
VerifyMode = Peer
|
||||
|
||||
[test-3]
|
||||
ExpectedResult = Success
|
||||
ExpectedSessionTicketAppData =
|
||||
HandshakeMode = Resume
|
||||
ResumptionExpected = Yes
|
||||
SessionTicketExpected = Yes
|
||||
|
||||
|
99
test/ssl-tests/27-ticket-appdata.conf.in
Normal file
99
test/ssl-tests/27-ticket-appdata.conf.in
Normal file
@ -0,0 +1,99 @@
|
||||
# -*- mode: perl; -*-
|
||||
# Copyright 2018 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
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
|
||||
## Test session ticket app data
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
package ssltests;
|
||||
use OpenSSL::Test::Utils;
|
||||
|
||||
our @tests12 = (
|
||||
{
|
||||
"name" => "session-ticket-app-data12",
|
||||
"client" => {
|
||||
"MaxProtocol" => "TLSv1.2",
|
||||
"Options" => "SessionTicket",
|
||||
},
|
||||
"server" => {
|
||||
"Options" => "SessionTicket",
|
||||
"extra" => {
|
||||
"SessionTicketAppData" => "HelloWorld",
|
||||
},
|
||||
},
|
||||
"test" => {
|
||||
"HandshakeMode" => "Resume",
|
||||
"ExpectedResult" => "Success",
|
||||
"SessionTicketExpected" => "Yes",
|
||||
"ResumptionExpected" => "Yes",
|
||||
"ExpectedSessionTicketAppData" => "HelloWorld",
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" => "session-ticket-app-data12",
|
||||
"client" => {
|
||||
"MaxProtocol" => "TLSv1.2",
|
||||
"Options" => "SessionTicket",
|
||||
},
|
||||
"server" => {
|
||||
"Options" => "SessionTicket",
|
||||
},
|
||||
"test" => {
|
||||
"HandshakeMode" => "Resume",
|
||||
"ExpectedResult" => "Success",
|
||||
"SessionTicketExpected" => "Yes",
|
||||
"ResumptionExpected" => "Yes",
|
||||
"ExpectedSessionTicketAppData" => "",
|
||||
}
|
||||
}
|
||||
);
|
||||
our @tests13 = (
|
||||
{
|
||||
"name" => "session-ticket-app-data13",
|
||||
"client" => {
|
||||
"MaxProtocol" => "TLSv1.3",
|
||||
"Options" => "SessionTicket",
|
||||
},
|
||||
"server" => {
|
||||
"Options" => "SessionTicket",
|
||||
"extra" => {
|
||||
"SessionTicketAppData" => "HelloWorld",
|
||||
},
|
||||
},
|
||||
"test" => {
|
||||
"HandshakeMode" => "Resume",
|
||||
"ExpectedResult" => "Success",
|
||||
"SessionTicketExpected" => "Yes",
|
||||
"ResumptionExpected" => "Yes",
|
||||
"ExpectedSessionTicketAppData" => "HelloWorld",
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" => "session-ticket-app-data13",
|
||||
"client" => {
|
||||
"MaxProtocol" => "TLSv1.3",
|
||||
"Options" => "SessionTicket",
|
||||
},
|
||||
"server" => {
|
||||
"Options" => "SessionTicket",
|
||||
},
|
||||
"test" => {
|
||||
"HandshakeMode" => "Resume",
|
||||
"ExpectedResult" => "Success",
|
||||
"SessionTicketExpected" => "Yes",
|
||||
"ResumptionExpected" => "Yes",
|
||||
"ExpectedSessionTicketAppData" => "",
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
our @tests = ();
|
||||
push @tests, @tests12 unless disabled("tls1_2");
|
||||
push @tests, @tests13 unless disabled("tls1_3");
|
@ -188,6 +188,27 @@ static int check_alpn(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_session_ticket_app_data(HANDSHAKE_RESULT *result,
|
||||
SSL_TEST_CTX *test_ctx)
|
||||
{
|
||||
size_t result_len = 0;
|
||||
size_t expected_len = 0;
|
||||
|
||||
/* consider empty and NULL strings to be the same */
|
||||
if (result->result_session_ticket_app_data != NULL)
|
||||
result_len = strlen(result->result_session_ticket_app_data);
|
||||
if (test_ctx->expected_session_ticket_app_data != NULL)
|
||||
expected_len = strlen(test_ctx->expected_session_ticket_app_data);
|
||||
if (result_len == 0 && expected_len == 0)
|
||||
return 1;
|
||||
|
||||
if (!TEST_str_eq(result->result_session_ticket_app_data,
|
||||
test_ctx->expected_session_ticket_app_data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_resumption(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx)
|
||||
{
|
||||
if (!TEST_int_eq(result->client_resumed, result->server_resumed))
|
||||
@ -352,6 +373,7 @@ static int check_test(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx)
|
||||
#endif
|
||||
ret &= check_cipher(result, test_ctx);
|
||||
ret &= check_alpn(result, test_ctx);
|
||||
ret &= check_session_ticket_app_data(result, test_ctx);
|
||||
ret &= check_resumption(result, test_ctx);
|
||||
ret &= check_tmp_key(result, test_ctx);
|
||||
ret &= check_server_cert_type(result, test_ctx);
|
||||
|
@ -99,6 +99,7 @@ static const test_enum ssl_test_results[] = {
|
||||
{"ServerFail", SSL_TEST_SERVER_FAIL},
|
||||
{"ClientFail", SSL_TEST_CLIENT_FAIL},
|
||||
{"InternalError", SSL_TEST_INTERNAL_ERROR},
|
||||
{"FirstHandshakeFailed", SSL_TEST_FIRST_HANDSHAKE_FAILED},
|
||||
};
|
||||
|
||||
__owur static int parse_expected_result(SSL_TEST_CTX *test_ctx, const char *value)
|
||||
@ -360,6 +361,10 @@ IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_SERVER_CONF, server, srp_user)
|
||||
IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_CLIENT_CONF, client, srp_password)
|
||||
IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_SERVER_CONF, server, srp_password)
|
||||
|
||||
/* Session Ticket App Data options */
|
||||
IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_CTX, test, expected_session_ticket_app_data)
|
||||
IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_SERVER_CONF, server, session_ticket_app_data)
|
||||
|
||||
/* Handshake mode */
|
||||
|
||||
static const test_enum ssl_handshake_modes[] = {
|
||||
@ -664,6 +669,7 @@ static const ssl_test_ctx_option ssl_test_ctx_options[] = {
|
||||
{ "ExpectedClientCANames", &parse_expected_client_ca_names },
|
||||
{ "UseSCTP", &parse_test_use_sctp },
|
||||
{ "ExpectedCipher", &parse_test_expected_cipher },
|
||||
{ "ExpectedSessionTicketAppData", &parse_test_expected_session_ticket_app_data },
|
||||
};
|
||||
|
||||
/* Nested client options. */
|
||||
@ -700,6 +706,7 @@ static const ssl_test_server_option ssl_test_server_options[] = {
|
||||
{ "SRPUser", &parse_server_srp_user },
|
||||
{ "SRPPassword", &parse_server_srp_password },
|
||||
{ "ForcePHA", &parse_server_force_pha },
|
||||
{ "SessionTicketAppData", &parse_server_session_ticket_app_data },
|
||||
};
|
||||
|
||||
SSL_TEST_CTX *SSL_TEST_CTX_new()
|
||||
@ -729,6 +736,8 @@ static void ssl_test_extra_conf_free_data(SSL_TEST_EXTRA_CONF *conf)
|
||||
OPENSSL_free(conf->server2.srp_password);
|
||||
OPENSSL_free(conf->client.srp_user);
|
||||
OPENSSL_free(conf->client.srp_password);
|
||||
OPENSSL_free(conf->server.session_ticket_app_data);
|
||||
OPENSSL_free(conf->server2.session_ticket_app_data);
|
||||
}
|
||||
|
||||
static void ssl_test_ctx_free_extra_data(SSL_TEST_CTX *ctx)
|
||||
@ -742,6 +751,7 @@ void SSL_TEST_CTX_free(SSL_TEST_CTX *ctx)
|
||||
ssl_test_ctx_free_extra_data(ctx);
|
||||
OPENSSL_free(ctx->expected_npn_protocol);
|
||||
OPENSSL_free(ctx->expected_alpn_protocol);
|
||||
OPENSSL_free(ctx->expected_session_ticket_app_data);
|
||||
sk_X509_NAME_pop_free(ctx->expected_server_ca_names, X509_NAME_free);
|
||||
sk_X509_NAME_pop_free(ctx->expected_client_ca_names, X509_NAME_free);
|
||||
OPENSSL_free(ctx->expected_cipher);
|
||||
|
@ -127,6 +127,7 @@ typedef struct {
|
||||
char *srp_password;
|
||||
/* Forced PHA */
|
||||
int force_pha;
|
||||
char *session_ticket_app_data;
|
||||
} SSL_TEST_SERVER_CONF;
|
||||
|
||||
typedef struct {
|
||||
@ -216,6 +217,8 @@ typedef struct {
|
||||
/* Whether to expect a session id from the server */
|
||||
ssl_session_id_t session_id_expected;
|
||||
char *expected_cipher;
|
||||
/* Expected Session Ticket Application Data */
|
||||
char *expected_session_ticket_app_data;
|
||||
} SSL_TEST_CTX;
|
||||
|
||||
const char *ssl_test_result_name(ssl_test_result_t result);
|
||||
|
@ -55,6 +55,8 @@ static int serverconf_eq(SSL_TEST_SERVER_CONF *serv,
|
||||
|| !TEST_str_eq(serv->alpn_protocols, serv2->alpn_protocols)
|
||||
|| !TEST_int_eq(serv->broken_session_ticket,
|
||||
serv2->broken_session_ticket)
|
||||
|| !TEST_str_eq(serv->session_ticket_app_data,
|
||||
serv2->session_ticket_app_data)
|
||||
|| !TEST_int_eq(serv->cert_status, serv2->cert_status))
|
||||
return 0;
|
||||
return 1;
|
||||
@ -95,6 +97,8 @@ static int testctx_eq(SSL_TEST_CTX *ctx, SSL_TEST_CTX *ctx2)
|
||||
ctx2->expected_alpn_protocol)
|
||||
|| !TEST_str_eq(ctx->expected_cipher,
|
||||
ctx2->expected_cipher)
|
||||
|| !TEST_str_eq(ctx->expected_session_ticket_app_data,
|
||||
ctx2->expected_session_ticket_app_data)
|
||||
|| !TEST_int_eq(ctx->resumption_expected,
|
||||
ctx2->resumption_expected)
|
||||
|| !TEST_int_eq(ctx->session_id_expected,
|
||||
|
@ -479,3 +479,6 @@ SSL_force_post_handshake_auth 479 1_1_1 EXIST::FUNCTION:
|
||||
SSL_export_keying_material_early 480 1_1_1 EXIST::FUNCTION:
|
||||
SSL_CTX_use_cert_and_key 481 1_1_1 EXIST::FUNCTION:
|
||||
SSL_use_cert_and_key 482 1_1_1 EXIST::FUNCTION:
|
||||
SSL_SESSION_get0_ticket_appdata 483 1_1_1 EXIST::FUNCTION:
|
||||
SSL_SESSION_set1_ticket_appdata 484 1_1_1 EXIST::FUNCTION:
|
||||
SSL_CTX_set_session_ticket_cb 485 1_1_1 EXIST::FUNCTION:
|
||||
|
@ -248,7 +248,9 @@ SSL_CTX_build_cert_chain define
|
||||
SSL_CTX_clear_chain_certs define
|
||||
SSL_CTX_clear_extra_chain_certs define
|
||||
SSL_CTX_clear_mode define
|
||||
SSL_CTX_decrypt_session_ticket_fn define
|
||||
SSL_CTX_disable_ct define
|
||||
SSL_CTX_generate_session_ticket_fn define
|
||||
SSL_CTX_get0_chain_certs define
|
||||
SSL_CTX_get_default_read_ahead define
|
||||
SSL_CTX_get_max_cert_list define
|
||||
|
Loading…
Reference in New Issue
Block a user