summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnder Juaristi <a@juaristi.eus>2018-01-06 13:06:41 +0100
committerAnder Juaristi <a@juaristi.eus>2018-01-06 13:21:13 +0100
commitc47be2df8073b516d22e7dfd0e2dbd405567f34b (patch)
treef856840996497b8f2a73bb97cc50e6c93b0aafc4
parent3633d385f87db4177ef3de806501d69f07d55689 (diff)
downloadgnutls-c47be2df8073b516d22e7dfd0e2dbd405567f34b.tar.gz
TLS 1.3: Session resumption: unpack ticket
Signed-off-by: Ander Juaristi <a@juaristi.eus>
-rw-r--r--lib/tls13/session_ticket.c105
-rw-r--r--lib/tls13/session_ticket.h6
2 files changed, 90 insertions, 21 deletions
diff --git a/lib/tls13/session_ticket.c b/lib/tls13/session_ticket.c
index 21781f030c..fbbac36701 100644
--- a/lib/tls13/session_ticket.c
+++ b/lib/tls13/session_ticket.c
@@ -66,20 +66,37 @@ static int unpack_ticket(gnutls_datum_t *state,
gnutls_mac_algorithm_t *kdf_id,
gnutls_datum_t *rms)
{
+ int kdf;
unsigned rms_len;
unsigned char *p;
+ size_t expected_len = sizeof(uint16_t) + sizeof(uint32_t);
if (unlikely(state == NULL || kdf_id == NULL || rms == NULL))
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ if (state->size <= expected_len)
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
p = state->data;
- *kdf_id = (gnutls_mac_algorithm_t) _gnutls_read_uint16(p);
+ kdf = _gnutls_read_uint16(p);
p += sizeof(uint16_t);
rms_len = (unsigned) _gnutls_read_uint32(p);
p += sizeof(uint32_t);
+ /* Check if the MAC ID we got is valid */
+ *kdf_id = (gnutls_mac_algorithm_t) kdf;
+ if (_gnutls_mac_to_entry(*kdf_id) == NULL)
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ /* Check if the whole ticket is large enough */
+ expected_len += rms_len;
+
+ if (state->size != expected_len)
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+ /* Read the rest of the ticket (the resumption master secret, basically) */
rms->size = rms_len;
rms->data = gnutls_malloc(rms->size);
if (!rms->data)
@@ -428,32 +445,84 @@ cleanup:
return ret;
}
-int _gnutls13_recv_session_ticket2(gnutls_session_t session, gnutls_datum_t *dat,
- struct tls13_nst_st *ticket)
+/*
+ * Parse the ticket in 'ticket' and return the resumption master secret
+ * and the KDF ID associated to it.
+ */
+int _gnutls13_unpack_session_ticket(gnutls_session_t session,
+ gnutls_datum_t *data,
+ gnutls_datum_t *rms, gnutls_mac_algorithm_t *kdf_id)
{
int ret;
- gnutls_buffer_st buf;
+ const unsigned char *p = data->data;
+ ssize_t data_size = data->size;
+ struct ticket_st ticket;
+ gnutls_datum_t decrypted;
- if (unlikely(dat == NULL))
+ if (unlikely(data == NULL || rms == NULL || kdf_id == NULL))
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ if (data_size == 0)
+ return 0;
- _gnutls_buffer_init(&buf);
- _gnutls_buffer_append_data(&buf, dat->data, dat->size);
- ret = _gnutls13_recv_session_ticket(session, &buf, ticket);
- _gnutls_buffer_clear(&buf);
+ memset(&ticket, 0, sizeof(struct ticket_st));
+ memset(&decrypted, 0, sizeof(gnutls_datum_t));
+
+ /* Parse the ticket fields.
+ * Format:
+ * Key name
+ * IV
+ * data length
+ * encrypted data
+ * MAC
+ */
+ DECR_LEN(data_size, KEY_NAME_SIZE);
+ memcpy(ticket.key_name, p, KEY_NAME_SIZE);
+ p += KEY_NAME_SIZE;
- if (ret < 0)
- gnutls_assert();
- return ret;
-}
+ if (memcmp(ticket.key_name,
+ &session->key.session_ticket_key[NAME_POS],
+ KEY_NAME_SIZE)) {
+ session->internals.session_ticket_renew = 1;
+ return 0;
+ }
-int _gnutls13_parse_session_ticket(struct tls13_nst_st *ticket)
-{
- int ret;
+ DECR_LEN(data_size, IV_SIZE);
+ memcpy(ticket.IV, p, IV_SIZE);
+ p += IV_SIZE;
+
+ DECR_LEN(data_size, 2);
+ ticket.encrypted_state_len = _gnutls_read_uint16(p);
+ p += 2;
- /* TODO implement this */
+ ticket.encrypted_state = gnutls_malloc(ticket.encrypted_state_len);
+ if (!ticket.encrypted_state)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
- return 0;
+ DECR_LEN(data_size, ticket.encrypted_state_len);
+ memcpy(ticket.encrypted_state, p, ticket.encrypted_state_len);
+ p += ticket.encrypted_state_len;
+
+ DECR_LEN(data_size, MAC_SIZE);
+ memcpy(ticket.mac, p, MAC_SIZE);
+
+ /* Check MAC and decrypt ticket */
+ ret = decrypt_ticket(session, &ticket, &decrypted);
+ /* Do not free, as the ticket is decrypted in-place */
+// gnutls_free(ticket.encrypted_state);
+
+ if (ret < 0) {
+ session->internals.session_ticket_renew = 1;
+ return 0;
+ }
+
+ /* Return ticket parameters */
+ ret = unpack_ticket(&decrypted, kdf_id, rms);
+ if (ret < 0) {
+ session->internals.session_ticket_renew = 1;
+ return 0;
+ }
+
+ return decrypted.size;
}
static int parse_nst_extension(void *ctx, uint16_t tls_id, const uint8_t *data, int data_size)
diff --git a/lib/tls13/session_ticket.h b/lib/tls13/session_ticket.h
index 2058e1b113..41ecebc124 100644
--- a/lib/tls13/session_ticket.h
+++ b/lib/tls13/session_ticket.h
@@ -33,8 +33,8 @@ struct tls13_nst_st {
int _gnutls13_send_session_ticket(gnutls_session_t session, unsigned again);
int _gnutls13_recv_session_ticket(gnutls_session_t session, gnutls_buffer_st *buf, struct tls13_nst_st *ticket);
-/* TODO maybe we don't need these two */
-int _gnutls13_recv_session_ticket2(gnutls_session_t session, gnutls_datum_t *dat, struct tls13_nst_st *ticket);
-int _gnutls13_parse_session_ticket(struct tls13_nst_st *ticket);
+int _gnutls13_unpack_session_ticket(gnutls_session_t session,
+ gnutls_datum_t *data,
+ gnutls_datum_t *rms, gnutls_mac_algorithm_t *kdf_id);
#endif