summaryrefslogtreecommitdiff
path: root/lib/handshake.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/handshake.c')
-rw-r--r--lib/handshake.c274
1 files changed, 172 insertions, 102 deletions
diff --git a/lib/handshake.c b/lib/handshake.c
index e756574277..30e229f3d0 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -54,6 +54,7 @@
#include <random.h>
#include <dtls.h>
#include "secrets.h"
+#include "tls13/session_ticket.h"
#define TRUE 1
#define FALSE 0
@@ -81,6 +82,7 @@ handshake_hash_buffer_reset(gnutls_session_t session)
session->internals.handshake_hash_buffer_client_kx_len = 0;
session->internals.handshake_hash_buffer_server_finished_len = 0;
+ session->internals.handshake_hash_buffer_client_finished_len = 0;
session->internals.handshake_hash_buffer_prev_len = 0;
session->internals.handshake_hash_buffer.length = 0;
session->internals.full_client_hello.length = 0;
@@ -510,6 +512,28 @@ _gnutls_user_hello_func(gnutls_session_t session,
return sret;
}
+static int set_auth_types(gnutls_session_t session)
+{
+ const version_entry_st *ver = get_version(session);
+ gnutls_kx_algorithm_t kx;
+
+ kx = session->security_parameters.cs->kx_algorithm;
+ if (kx == 0 && ver->tls13_sem) {
+ /* if we are resuming then the KX seen doesn't match the original */
+ if (session->internals.resumed == RESUME_FALSE)
+ kx = gnutls_kx_get(session);
+ }
+
+ if (kx) {
+ session->security_parameters.server_auth_type = _gnutls_map_kx_get_cred(kx, 1);
+ session->security_parameters.client_auth_type = _gnutls_map_kx_get_cred(kx, 0);
+ } else if (session->internals.resumed == RESUME_FALSE) {
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ }
+
+ return 0;
+}
+
/* Read a client hello packet.
* A client hello must be a known version client hello
* or version 2.0 client hello (only for compatibility
@@ -699,7 +723,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data,
}
/* resumed by session_ticket extension */
- if (session->internals.resumed != RESUME_FALSE) {
+ if (!vers->tls13_sem && session->internals.resumed != RESUME_FALSE) {
/* to indicate the client that the current session is resumed */
memcpy(session->internals.resumed_security_parameters.
session_id, session_id, session_id_len);
@@ -753,6 +777,12 @@ read_client_hello(gnutls_session_t session, uint8_t * data,
return ret;
}
+ ret = set_auth_types(session);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
return sret;
}
@@ -770,7 +800,7 @@ int _gnutls_send_finished(gnutls_session_t session, int again)
if (again == 0) {
bufel =
- _gnutls_handshake_alloc(session,
+ _gnutls_handshake_alloc(session,
MAX_VERIFY_DATA_SIZE);
if (bufel == NULL) {
gnutls_assert();
@@ -952,6 +982,7 @@ _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data,
unsigned int i;
ciphersuite_list_st peer_clist;
const gnutls_cipher_suite_entry_st *selected;
+ gnutls_kx_algorithm_t kx;
int retval;
const version_entry_st *vers = get_version(session);
@@ -1015,7 +1046,8 @@ _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data,
if (!vers->tls13_sem) {
/* check if the credentials (username, public key etc.) are ok
*/
- if (_gnutls_get_kx_cred(session, selected->kx_algorithm) == NULL) {
+ kx = selected->kx_algorithm;
+ if (_gnutls_get_kx_cred(session, kx) == NULL) {
gnutls_assert();
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
@@ -1024,7 +1056,7 @@ _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data,
* according to the KX algorithm. This is needed since all the
* handshake functions are read from there;
*/
- session->internals.auth_struct = _gnutls_kx_auth_struct(selected->kx_algorithm);
+ session->internals.auth_struct = _gnutls_kx_auth_struct(kx);
if (session->internals.auth_struct == NULL) {
_gnutls_handshake_log
("HSK[%p]: Cannot find the appropriate handler for the KX algorithm\n",
@@ -1084,11 +1116,10 @@ _gnutls_send_empty_handshake(gnutls_session_t session,
return _gnutls_send_handshake(session, bufel, type);
}
-inline
- static int call_hook_func(gnutls_session_t session,
- gnutls_handshake_description_t type,
- int post, unsigned incoming,
- const uint8_t *data, unsigned data_size)
+int _gnutls_call_hook_func(gnutls_session_t session,
+ gnutls_handshake_description_t type,
+ int post, unsigned incoming,
+ const uint8_t *data, unsigned data_size)
{
gnutls_datum_t msg = {(void*)data, data_size};
@@ -1116,6 +1147,13 @@ inline
return 0;
}
+/* Note that the "New session ticket" handshake packet behaves differently under
+ * TLS 1.2 or 1.3. In 1.2 it is included in the handshake process, while in 1.3
+ * it is sent asynchronously */
+#define IS_ASYNC(t, v) \
+ (t == GNUTLS_HANDSHAKE_HELLO_REQUEST || t == GNUTLS_HANDSHAKE_KEY_UPDATE || \
+ (t == GNUTLS_HANDSHAKE_NEW_SESSION_TICKET && v->tls13_sem))
+
/* This function sends a handshake message of type 'type' containing the
* data specified here. If the previous _gnutls_send_handshake() returned
* GNUTLS_E_AGAIN or GNUTLS_E_INTERRUPTED, then it must be called again
@@ -1173,7 +1211,7 @@ _gnutls_send_handshake(gnutls_session_t session, mbuffer_st * bufel,
/* Here we keep the handshake messages in order to hash them...
*/
- if (type != GNUTLS_HANDSHAKE_HELLO_REQUEST)
+ if (!IS_ASYNC(type, vers))
if ((ret =
handshake_hash_add_sent(session, type, data,
datasize)) < 0) {
@@ -1182,8 +1220,8 @@ _gnutls_send_handshake(gnutls_session_t session, mbuffer_st * bufel,
return ret;
}
- ret = call_hook_func(session, type, GNUTLS_HOOK_PRE, 0,
- _mbuffer_get_udata_ptr(bufel), _mbuffer_get_udata_size(bufel));
+ ret = _gnutls_call_hook_func(session, type, GNUTLS_HOOK_PRE, 0,
+ _mbuffer_get_udata_ptr(bufel), _mbuffer_get_udata_size(bufel));
if (ret < 0) {
gnutls_assert();
_mbuffer_xfree(&bufel);
@@ -1199,42 +1237,60 @@ _gnutls_send_handshake(gnutls_session_t session, mbuffer_st * bufel,
return ret;
}
- ret = call_hook_func(session, type, GNUTLS_HOOK_POST, 0,
- _mbuffer_get_udata_ptr(bufel), _mbuffer_get_udata_size(bufel));
+ ret = _gnutls_call_hook_func(session, type, GNUTLS_HOOK_POST, 0,
+ _mbuffer_get_udata_ptr(bufel), _mbuffer_get_udata_size(bufel));
if (ret < 0) {
gnutls_assert();
return ret;
}
- if (vers && vers->tls13_sem &&
- session->internals.initial_negotiation_completed) {
- /* we are under TLS1.3 in a re-authentication phase.
- * we don't attempt to cache any messages */
- goto force_send;
- }
+ /* Decide when to cache and when to send */
+ if (vers && vers->tls13_sem) {
- /* The messages which are followed by another are not sent by default
- * but are cached instead */
- switch (type) {
- case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: /* this one is followed by ServerHelloDone
- * or ClientKeyExchange always.
- */
- case GNUTLS_HANDSHAKE_CERTIFICATE_STATUS:
- case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE: /* as above */
- case GNUTLS_HANDSHAKE_SERVER_HELLO: /* as above */
- case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST: /* as above */
- case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: /* followed by ChangeCipherSpec */
+ if (session->internals.initial_negotiation_completed) {
+ /* we are under TLS1.3 in a re-authentication phase.
+ * we don't attempt to cache any messages */
+ goto force_send;
+ }
- /* now for client Certificate, ClientKeyExchange and
- * CertificateVerify are always followed by ChangeCipherSpec
- */
- case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY:
- case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE:
- ret = 0;
- break;
- default:
- /* send cached messages */
- goto force_send;
+ /* The messages which are followed by another are not sent by default
+ * but are cached instead */
+ switch (type) {
+ case GNUTLS_HANDSHAKE_SERVER_HELLO: /* always followed by something */
+ case GNUTLS_HANDSHAKE_ENCRYPTED_EXTENSIONS: /* followed by finished or cert */
+ case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST: /* followed by certificate */
+ case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: /* this one is followed by cert verify */
+ case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY: /* followed by finished */
+ ret = 0; /* cache */
+ break;
+ default:
+ /* send this and any cached messages */
+ goto force_send;
+ }
+ } else {
+ /* The messages which are followed by another are not sent by default
+ * but are cached instead */
+ switch (type) {
+ case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: /* this one is followed by ServerHelloDone
+ * or ClientKeyExchange always.
+ */
+ case GNUTLS_HANDSHAKE_CERTIFICATE_STATUS:
+ case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE: /* as above */
+ case GNUTLS_HANDSHAKE_SERVER_HELLO: /* as above */
+ case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST: /* as above */
+ case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: /* followed by ChangeCipherSpec */
+
+ /* now for client Certificate, ClientKeyExchange and
+ * CertificateVerify are always followed by ChangeCipherSpec
+ */
+ case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY:
+ case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE:
+ ret = 0;
+ break;
+ default:
+ /* send this and any cached messages */
+ goto force_send;
+ }
}
return ret;
@@ -1251,6 +1307,7 @@ _gnutls_send_handshake(gnutls_session_t session, mbuffer_st * bufel,
return gnutls_assert_val(GNUTLS_E_HANDSHAKE_TOO_LARGE); \
}
+
/* This function add the handshake headers and the
* handshake data to the handshake hash buffers. Needed
* for the finished messages calculations.
@@ -1269,7 +1326,7 @@ handshake_hash_add_recvd(gnutls_session_t session,
if ((vers->id != GNUTLS_DTLS0_9 &&
recv_type == GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST) ||
- recv_type == GNUTLS_HANDSHAKE_HELLO_REQUEST)
+ IS_ASYNC(recv_type, vers))
return 0;
CHECK_SIZE(header_size + datalen);
@@ -1303,6 +1360,9 @@ handshake_hash_add_recvd(gnutls_session_t session,
if (recv_type == GNUTLS_HANDSHAKE_FINISHED && session->security_parameters.entity == GNUTLS_CLIENT)
session->internals.handshake_hash_buffer_server_finished_len =
session->internals.handshake_hash_buffer.length;
+ if (recv_type == GNUTLS_HANDSHAKE_FINISHED && session->security_parameters.entity == GNUTLS_SERVER)
+ session->internals.handshake_hash_buffer_client_finished_len =
+ session->internals.handshake_hash_buffer.length;
return 0;
}
@@ -1320,41 +1380,40 @@ handshake_hash_add_sent(gnutls_session_t session,
if (unlikely(vers == NULL))
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
- /* We don't check for GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST because it
- * is not sent via that channel.
- */
- if (type != GNUTLS_HANDSHAKE_HELLO_REQUEST) {
- CHECK_SIZE(datalen);
+ if (IS_ASYNC(type, vers))
+ return 0;
- if (vers->id == GNUTLS_DTLS0_9) {
- /* Old DTLS doesn't include the header in the MAC */
- if (datalen < 12) {
- gnutls_assert();
- return GNUTLS_E_INTERNAL_ERROR;
- }
- dataptr += 12;
- datalen -= 12;
+ CHECK_SIZE(datalen);
- if (datalen == 0)
- return 0;
+ if (vers->id == GNUTLS_DTLS0_9) {
+ /* Old DTLS doesn't include the header in the MAC */
+ if (datalen < 12) {
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
}
+ dataptr += 12;
+ datalen -= 12;
- ret =
- _gnutls_buffer_append_data(&session->internals.
- handshake_hash_buffer,
- dataptr, datalen);
- if (ret < 0)
- return gnutls_assert_val(ret);
+ if (datalen == 0)
+ return 0;
+ }
- if (type == GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE)
- session->internals.handshake_hash_buffer_client_kx_len =
- session->internals.handshake_hash_buffer.length;
- if (type == GNUTLS_HANDSHAKE_FINISHED && session->security_parameters.entity == GNUTLS_SERVER)
- session->internals.handshake_hash_buffer_server_finished_len =
- session->internals.handshake_hash_buffer.length;
+ ret =
+ _gnutls_buffer_append_data(&session->internals.
+ handshake_hash_buffer,
+ dataptr, datalen);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
- return 0;
- }
+ if (type == GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE)
+ session->internals.handshake_hash_buffer_client_kx_len =
+ session->internals.handshake_hash_buffer.length;
+ if (type == GNUTLS_HANDSHAKE_FINISHED && session->security_parameters.entity == GNUTLS_SERVER)
+ session->internals.handshake_hash_buffer_server_finished_len =
+ session->internals.handshake_hash_buffer.length;
+ if (type == GNUTLS_HANDSHAKE_FINISHED && session->security_parameters.entity == GNUTLS_CLIENT)
+ session->internals.handshake_hash_buffer_client_finished_len =
+ session->internals.handshake_hash_buffer.length;
return 0;
}
@@ -1385,7 +1444,7 @@ _gnutls_recv_handshake(gnutls_session_t session,
}
session->internals.last_handshake_in = hsk.htype;
- ret = call_hook_func(session, hsk.htype, GNUTLS_HOOK_PRE, 1, hsk.data.data, hsk.data.length);
+ ret = _gnutls_call_hook_func(session, hsk.htype, GNUTLS_HOOK_PRE, 1, hsk.data.data, hsk.data.length);
if (ret < 0) {
gnutls_assert();
goto cleanup;
@@ -1511,7 +1570,7 @@ _gnutls_recv_handshake(gnutls_session_t session,
goto cleanup;
}
- ret2 = call_hook_func(session, hsk.htype, GNUTLS_HOOK_POST, 1, hsk.data.data, hsk.data.length);
+ ret2 = _gnutls_call_hook_func(session, hsk.htype, GNUTLS_HOOK_POST, 1, hsk.data.data, hsk.data.length);
if (ret2 < 0) {
ret = ret2;
gnutls_assert();
@@ -1538,6 +1597,7 @@ set_client_ciphersuite(gnutls_session_t session, uint8_t suite[2])
int ret;
const gnutls_cipher_suite_entry_st *selected = NULL;
const version_entry_st *vers = get_version(session);
+ gnutls_kx_algorithm_t kx;
for (j = 0; j < session->internals.priorities->cs.size; j++) {
if (suite[0] == session->internals.priorities->cs.entry[j]->id[0] &&
@@ -1568,20 +1628,21 @@ set_client_ciphersuite(gnutls_session_t session, uint8_t suite[2])
* Actually checks if they exist.
*/
if (!vers->tls13_sem) {
+ kx = selected->kx_algorithm;
+
if (!session->internals.premaster_set &&
_gnutls_get_kx_cred
- (session, selected->kx_algorithm) == NULL) {
+ (session, kx) == NULL) {
gnutls_assert();
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
-
/* set the mod_auth_st to the appropriate struct
* according to the KX algorithm. This is needed since all the
* handshake functions are read from there;
*/
session->internals.auth_struct =
- _gnutls_kx_auth_struct(selected->kx_algorithm);
+ _gnutls_kx_auth_struct(kx);
if (session->internals.auth_struct == NULL) {
_gnutls_handshake_log
@@ -1592,11 +1653,12 @@ set_client_ciphersuite(gnutls_session_t session, uint8_t suite[2])
}
} else {
if (session->internals.hsk_flags & HSK_PSK_SELECTED) {
- if (session->key.proto.tls13.binder_prf->id != selected->prf) {
+ if (session->key.binders[0].prf->id != selected->prf) {
_gnutls_handshake_log
("HSK[%p]: PRF of ciphersuite differs with the PSK identity (cs: %s, id: %s)\n",
- session, selected->name, session->key.proto.tls13.binder_prf->name);
+ session, selected->name, session->key.binders[0].prf->name);
gnutls_assert();
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
}
}
}
@@ -1843,8 +1905,11 @@ read_server_hello(gnutls_session_t session,
/* Calculate TLS 1.3 Early Secret */
if (vers->tls13_sem) {
if (session->internals.hsk_flags & HSK_PSK_SELECTED) {
- psk = session->key.psk.data;
- psk_size = session->key.psk.size;
+ psk = session->key.binders[0].psk.data;
+ psk_size = session->key.binders[0].psk.size;
+
+ if (psk_size == 0)
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
}
ret = _tls13_init_secret(session, psk, psk_size);
@@ -1856,8 +1921,16 @@ read_server_hello(gnutls_session_t session,
ret = _tls13_derive_secret(session, DERIVED_LABEL, sizeof(DERIVED_LABEL)-1,
NULL, 0, session->key.proto.tls13.temp_secret,
session->key.proto.tls13.temp_secret);
- if (ret < 0)
+ if (ret < 0) {
gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ ret = set_auth_types(session);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
}
cleanup:
@@ -1925,6 +1998,9 @@ static int send_client_hello(gnutls_session_t session, int again)
hver =
session->internals.resumed_security_parameters.
pversion;
+
+ if (hver && hver->tls13_sem)
+ hver = _gnutls_legacy_version_max(session);
}
if (hver == NULL) {
@@ -2113,6 +2189,7 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again)
unsigned extflag = 0;
const uint8_t *psk = NULL;
size_t psk_size = 0;
+ gnutls_ext_parse_type_t etype;
_gnutls_buffer_init(&buf);
@@ -2124,8 +2201,8 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again)
if (vers->tls13_sem) {
/* TLS 1.3 Early Secret */
if (session->internals.hsk_flags & HSK_PSK_SELECTED) {
- psk = session->key.psk.data;
- psk_size = session->key.psk.size;
+ psk = session->key.binders[0].psk.data;
+ psk_size = session->key.binders[0].psk.size;
}
ret = _tls13_init_secret(session, psk, psk_size);
@@ -2192,13 +2269,12 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again)
goto fail;
}
+ if (!vers->tls13_sem && session->internals.resumed != RESUME_FALSE)
+ etype = GNUTLS_EXT_MANDATORY;
+ else
+ etype = GNUTLS_EXT_ANY;
ret =
- _gnutls_gen_hello_extensions(session, &buf,
- extflag,
- (session->internals.resumed ==
- RESUME_TRUE) ?
- GNUTLS_EXT_MANDATORY :
- GNUTLS_EXT_ANY);
+ _gnutls_gen_hello_extensions(session, &buf, extflag, etype);
if (ret < 0) {
gnutls_assert();
goto fail;
@@ -2494,11 +2570,10 @@ static int _gnutls_recv_supplemental(gnutls_session_t session)
**/
int gnutls_handshake(gnutls_session_t session)
{
+ const version_entry_st *vers = get_version(session);
int ret;
if (unlikely(session->internals.initial_negotiation_completed)) {
- const version_entry_st *vers = get_version(session);
-
if (vers->tls13_sem) {
if (session->security_parameters.entity == GNUTLS_CLIENT) {
return gnutls_session_key_update(session, GNUTLS_KU_PEER);
@@ -2546,6 +2621,7 @@ int gnutls_handshake(gnutls_session_t session)
} else {
ret = handshake_server(session);
}
+
if (ret < 0) {
/* In the case of a rehandshake abort
* we should reset the handshake's internal state.
@@ -2848,12 +2924,10 @@ static int handshake_client(gnutls_session_t session)
if (session->internals.resumed == RESUME_FALSE) {
ret = send_handshake_final(session, TRUE);
IMED_RET("send handshake final 2", ret, 1);
-#ifdef ENABLE_SESSION_TICKETS
} else {
ret = _gnutls_recv_new_session_ticket(session);
IMED_RET("recv handshake new session ticket", ret,
1);
-#endif
}
/* fall through */
case STATE17:
@@ -2874,11 +2948,9 @@ static int handshake_client(gnutls_session_t session)
STATE = STATE18;
if (session->internals.resumed == RESUME_FALSE) {
-#ifdef ENABLE_SESSION_TICKETS
ret = _gnutls_recv_new_session_ticket(session);
IMED_RET("recv handshake new session ticket", ret,
1);
-#endif
} else {
ret = recv_handshake_final(session, TRUE);
IMED_RET("recv handshake final", ret, 1);
@@ -2942,8 +3014,8 @@ ssize_t _gnutls_send_change_cipher_spec(gnutls_session_t session, int again)
session->internals.dtls.hsk_write_seq++;
}
- ret = call_hook_func(session, GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC, GNUTLS_HOOK_PRE, 0,
- data, 1);
+ ret = _gnutls_call_hook_func(session, GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC, GNUTLS_HOOK_PRE, 0,
+ data, 1);
if (ret < 0) {
_mbuffer_xfree(&bufel);
return gnutls_assert_val(ret);
@@ -2958,8 +3030,8 @@ ssize_t _gnutls_send_change_cipher_spec(gnutls_session_t session, int again)
return gnutls_assert_val(ret);
}
- ret = call_hook_func(session, GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC, GNUTLS_HOOK_POST, 0,
- data, 1);
+ ret = _gnutls_call_hook_func(session, GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC, GNUTLS_HOOK_POST, 0,
+ data, 1);
if (ret < 0) {
return gnutls_assert_val(ret);
}
@@ -3279,13 +3351,11 @@ static int handshake_server(gnutls_session_t session)
}
/* fall through */
case STATE16:
-#ifdef ENABLE_SESSION_TICKETS
ret =
_gnutls_send_new_session_ticket(session,
AGAIN(STATE16));
STATE = STATE16;
IMED_RET("send handshake new session ticket", ret, 0);
-#endif
/* fall through */
case STATE17:
STATE = STATE17;
@@ -3295,7 +3365,7 @@ static int handshake_server(gnutls_session_t session)
if (session->security_parameters.entity ==
GNUTLS_SERVER
- && session->internals.ticket_sent == 0) {
+ && !(session->internals.hsk_flags & HSK_TLS12_TICKET_SENT)) {
/* if no ticket, save session data */
_gnutls_server_register_current_session
(session);