diff options
-rw-r--r-- | lib/ext/pre_shared_key.c | 141 | ||||
-rw-r--r-- | lib/tls13/psk_parser.c | 133 | ||||
-rw-r--r-- | lib/tls13/psk_parser.h | 17 | ||||
-rw-r--r-- | lib/tls13/session_ticket.c | 5 | ||||
-rw-r--r-- | lib/tls13/session_ticket.h | 3 |
5 files changed, 168 insertions, 131 deletions
diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c index 3d835eef65..6ba985a829 100644 --- a/lib/ext/pre_shared_key.c +++ b/lib/ext/pre_shared_key.c @@ -41,7 +41,7 @@ typedef struct { static int compute_psk_from_ticket(const mac_entry_st *prf, const uint8_t *rms, - struct tls13_nst_st *ticket, gnutls_datum_t *key) + gnutls_datum_t *nonce, gnutls_datum_t *key) { int ret; unsigned hash_size = prf->output_size; @@ -54,7 +54,7 @@ compute_psk_from_ticket(const mac_entry_st *prf, ret = _tls13_expand_secret2(prf, label, strlen(label), - ticket->ticket_nonce.data, ticket->ticket_nonce.size, + nonce->data, nonce->size, rms, hash_size, key->data); @@ -255,7 +255,7 @@ client_send_params(gnutls_session_t session, rms = session->key.proto.tls13.ap_rms_original.data; ret = compute_psk_from_ticket(prf, rms, - &ticket, &key); + &ticket.ticket_nonce, &key); if (ret < 0) { gnutls_assert(); goto cleanup; @@ -362,74 +362,22 @@ server_send_params(gnutls_session_t session, gnutls_buffer_t extdata) return 2; } -static int -server_find_binder(const unsigned char **data_p, long *len_p, - int psk_index, gnutls_datum_t *binder_recvd) -{ - uint8_t binder_len; - int cur_index = 0, binder_found = 0; - const unsigned char *data = *data_p; - long len = *len_p; - - while (len > 0) { - binder_len = *data; - if (binder_len == 0) - return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); - - DECR_LEN(len, 1); - data++; - - if (cur_index == psk_index) { - binder_recvd->data = gnutls_malloc(binder_len); - if (!binder_recvd->data) - return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); - - binder_recvd->size = binder_len; - memcpy(binder_recvd->data, data, binder_len); - - DECR_LEN(len, binder_len); - data += binder_len; - - binder_found = 1; - break; - } - - DECR_LEN(len, binder_len); - data += binder_len; - - binder_len = 0; - cur_index++; - } - - *len_p = len; - *data_p = data; - - return (binder_found ? binder_len : gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS)); -} - static int server_recv_params(gnutls_session_t session, const unsigned char *data, long len, const gnutls_psk_server_credentials_t pskcred) { int ret; - const mac_entry_st *prf; + const mac_entry_st *prf = NULL; gnutls_datum_t full_client_hello; - psk_ext_st *priv = NULL; - uint16_t ttl_identities_len; uint8_t binder_value[MAX_HASH_SIZE]; int psk_index = -1; - gnutls_datum_t binder_recvd; - gnutls_datum_t username, key; - gnutls_datum_t ticket_data = { NULL, 0 }, rms = { NULL, 0 }; + gnutls_datum_t username = { NULL, 0 }, key = { NULL, 0 }; + gnutls_datum_t binder_recvd = { NULL, 0 }; + gnutls_datum_t ticket_data = { NULL, 0 }, rms = { NULL, 0 }, nonce = { NULL, 0 }; gnutls_mac_algorithm_t kdf_id; unsigned hash_size; - struct psk_parser_st psk_parser; + struct psk_ext_parser_st psk_parser; struct psk_st psk; - struct ticket_st *ticket = NULL; - - memset(&binder_recvd, 0, sizeof(gnutls_datum_t)); - memset(&username, 0, sizeof(gnutls_datum_t)); - memset(&key, 0, sizeof(gnutls_datum_t)); if (pskcred) { /* No credentials - this extension is not applicable */ @@ -442,51 +390,39 @@ static int server_recv_params(gnutls_session_t session, ret = _gnutls_psk_pwd_find_entry(session, pskcred->hint, &key); if (ret < 0) return ret; - - if (pskcred->hint) { - username.data = (unsigned char *) pskcred->hint; - username.size = strlen(pskcred->hint); - - ret = _gnutls_psk_pwd_find_entry(session, pskcred->hint, &key); - if (ret < 0) - return ret; - } } - ttl_identities_len = _gnutls_read_uint16(data); - /* The client advertised no PSKs */ - if (ttl_identities_len == 0) + ret = _gnutls13_psk_ext_parser_init(&psk_parser, data, len); + if (ret == 0) { + /* The client advertised no PSKs */ return 0; + } else if (ret < 0) { + return gnutls_assert_val(ret); + } - DECR_LEN(len, 2); - data += 2; - - _gnutls13_psk_parser_init(&psk_parser, data, len, ttl_identities_len); - - while (_gnutls13_psk_parser_next(&psk_parser, &psk) >= 0) { + while (_gnutls13_psk_ext_parser_next_psk(&psk_parser, &psk) >= 0) { /* * First check if this is an out-of-band PSK. * If it's not, try to decrypt it, as it might be a session ticket. */ - if (username.size == psk.identity.size && + if (pskcred && username.size == psk.identity.size && safe_memcmp(username.data, psk.identity.data, psk.identity.size) == 0) { psk_index = psk.selected_index; + prf = _gnutls_mac_to_entry(pskcred->tls13_binder_algo); break; } - if (psk.identity.size < sizeof(struct ticket_st)) - break; - - ticket = (struct ticket_st *) psk.identity.data; ticket_data.data = psk.identity.data; ticket_data.size = psk.identity.size; - if (_gnutls13_unpack_session_ticket(session, &ticket_data, &rms, &kdf_id) > 0) { + if (_gnutls13_unpack_session_ticket(session, &ticket_data, &rms, &nonce, &kdf_id) > 0) { psk_index = psk.selected_index; + prf = _gnutls_mac_to_entry(kdf_id); + if (!prf) + return gnutls_assert_val(GNUTLS_E_INVALID_SESSION); - key.data = ticket->encrypted_state; - key.size = ticket->encrypted_state_len; - gnutls_free(ticket->encrypted_state); - ticket->encrypted_state = NULL; + ret = compute_psk_from_ticket(prf, rms.data, &nonce, &key); + if (ret < 0) + return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); session->internals.resumption_requested = 1; @@ -494,25 +430,20 @@ static int server_recv_params(gnutls_session_t session, } } - _gnutls13_psk_parser_deinit(&psk_parser, &data, (size_t *) &len); - /* No suitable PSK found */ if (psk_index < 0) return 0; - DECR_LEN(len, 2); - data += 2; - - ret = server_find_binder(&data, &len, - psk_index, &binder_recvd); + /* Find the binder for the chosen PSK */ + ret = _gnutls13_psk_ext_parser_find_binder(&psk_parser, psk_index, + &binder_recvd); if (ret < 0) return gnutls_assert_val(ret); - if (binder_recvd.size == 0) - return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); - priv = gnutls_malloc(sizeof(psk_ext_st)); - if (!priv) { - ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + ret = _gnutls13_psk_ext_parser_deinit(&psk_parser, + &data, (size_t *) &len); + if (ret < 0) { + gnutls_assert(); goto cleanup; } @@ -523,15 +454,18 @@ static int server_recv_params(gnutls_session_t session, } /* Compute the binder value for this PSK */ - prf = _gnutls_mac_to_entry(pskcred->tls13_binder_algo); + if (!prf) { + ret = gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); + goto cleanup; + } hash_size = prf->output_size; compute_psk_binder(GNUTLS_SERVER, prf, hash_size, hash_size, 0, 0, 0, &key, &full_client_hello, binder_value); if (_gnutls_mac_get_algo_len(prf) != binder_recvd.size || safe_memcmp(binder_value, binder_recvd.data, binder_recvd.size)) { - _gnutls_free_datum(&binder_recvd); - return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); + ret = gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); + goto cleanup; } session->internals.hsk_flags |= HSK_PSK_SELECTED; @@ -539,7 +473,6 @@ static int server_recv_params(gnutls_session_t session, session->key.proto.tls13.psk = key.data; session->key.proto.tls13.psk_size = key.size; session->key.proto.tls13.psk_selected = 0; - _gnutls_free_datum(&binder_recvd); cleanup: _gnutls_free_datum(&binder_recvd); diff --git a/lib/tls13/psk_parser.c b/lib/tls13/psk_parser.c index 33f86c6cc5..86186eb215 100644 --- a/lib/tls13/psk_parser.c +++ b/lib/tls13/psk_parser.c @@ -21,52 +21,151 @@ */ #include "tls13/psk_parser.h" -void _gnutls13_psk_parser_init(struct psk_parser_st *p, - const unsigned char *data, size_t len, - uint16_t identities_len) +static int advance_to_end_of_object(struct psk_ext_parser_st *p) { - memset(p, 0, sizeof(struct psk_parser_st)); - p->identities_len = identities_len; - p->data = (unsigned char *) data; - p->len = len; + size_t adv; + + /* Advance the pointer to the end of the current object */ + if (p->obj_read < p->obj_len) { + adv = p->obj_len - p->obj_read; + DECR_LEN(p->len, adv); + p->data += adv; + } + + return 0; } -void _gnutls13_psk_parser_deinit(struct psk_parser_st *p, - const unsigned char **data, size_t *len) +int _gnutls13_psk_ext_parser_init(struct psk_ext_parser_st *p, + const unsigned char *data, size_t len) { + uint16_t identities_len; + + memset(p, 0, sizeof(struct psk_ext_parser_st)); + + identities_len = _gnutls_read_uint16(data); + + if (identities_len > 0) { + DECR_LEN(len, 2); + data += 2; + + p->obj_len = identities_len; + p->data = (unsigned char *) data; + p->len = len; + } + + return identities_len; +} + +int _gnutls13_psk_ext_parser_deinit(struct psk_ext_parser_st *p, + const unsigned char **data, size_t *len) +{ + if (p->obj_len == 0) + goto end; + + if (advance_to_end_of_object(p) < 0) + return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); + if (data) *data = p->data; if (len) *len = p->len; - memset(p, 0, sizeof(struct psk_parser_st)); + +end: + memset(p, 0, sizeof(struct psk_ext_parser_st)); + return 0; } -int _gnutls13_psk_parser_next(struct psk_parser_st *p, struct psk_st *psk) +int _gnutls13_psk_ext_parser_next_psk(struct psk_ext_parser_st *p, struct psk_st *psk) { - if (p->identities_read >= p->identities_len) - return -1; + if (p->obj_read >= p->obj_len) + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; /* Read a PskIdentity structure */ psk->identity.size = _gnutls_read_uint16(p->data); if (psk->identity.size == 0) - return -1; + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; DECR_LEN(p->len, 2); p->data += 2; - p->identities_read += 2; + p->obj_read += 2; psk->identity.data = p->data; DECR_LEN(p->len, psk->identity.size); p->data += psk->identity.size; - p->identities_read += psk->identity.size; + p->obj_read += psk->identity.size; psk->ob_ticket_age = _gnutls_read_uint32(p->data); DECR_LEN(p->len, 4); p->data += 4; - p->identities_read += 4; + p->obj_read += 4; psk->selected_index = p->next_index++; return psk->selected_index; } +int _gnutls13_psk_ext_parser_find_binder(struct psk_ext_parser_st *p, int psk_index, + gnutls_datum_t *binder_out) +{ + uint16_t binders_len; + uint8_t binder_len; + int cur_index = 0, binder_found = 0; + + if (p == NULL || psk_index < 0 || binder_out == NULL) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + if (p->obj_len == 0) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + /* Place the pointer at the start of the binders */ + if (advance_to_end_of_object(p) < 0) + return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); + + binders_len = _gnutls_read_uint16(p->data); + if (binders_len > 0) { + DECR_LEN(p->len, 2); + p->data += 2; + + p->obj_len = binders_len; + p->obj_read = 0; + } else { + return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + } + + /* Start traversing the binders */ + while (p->len > 0) { + binder_len = *p->data; + if (binder_len == 0) + return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); + + DECR_LEN(p->len, 1); + p->data++; + p->obj_read++; + + if (cur_index == psk_index) { + /* We found the binder with the supplied index */ + binder_out->data = gnutls_malloc(binder_len); + if (!binder_out->data) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + binder_out->size = binder_len; + memcpy(binder_out->data, p->data, binder_len); + + binder_found = 1; + } + + DECR_LEN(p->len, binder_len); + p->data += binder_len; + p->obj_read += binder_len; + + if (binder_found) + break; + + binder_len = 0; + cur_index++; + } + + return (binder_found ? + 0 : + gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)); +} diff --git a/lib/tls13/psk_parser.h b/lib/tls13/psk_parser.h index cae258b3a4..de908ead98 100644 --- a/lib/tls13/psk_parser.h +++ b/lib/tls13/psk_parser.h @@ -24,11 +24,11 @@ #define PSK_PARSER_H #include "gnutls_int.h" -struct psk_parser_st { +struct psk_ext_parser_st { unsigned char *data; ssize_t len; - uint16_t identities_len; - uint16_t identities_read; + uint16_t obj_len; + uint16_t obj_read; int next_index; }; @@ -38,12 +38,13 @@ struct psk_st { int selected_index; }; -void _gnutls13_psk_parser_init(struct psk_parser_st *p, - const unsigned char *data, size_t len, - uint16_t ttl_identities_len); -void _gnutls13_psk_parser_deinit(struct psk_parser_st *p, +int _gnutls13_psk_ext_parser_init(struct psk_ext_parser_st *p, + const unsigned char *data, size_t len); +int _gnutls13_psk_ext_parser_deinit(struct psk_ext_parser_st *p, const unsigned char **data, size_t *len); -int _gnutls13_psk_parser_next(struct psk_parser_st *p, struct psk_st *psk); +int _gnutls13_psk_ext_parser_next_psk(struct psk_ext_parser_st *p, struct psk_st *psk); +int _gnutls13_psk_ext_parser_find_binder(struct psk_ext_parser_st *p, int psk_index, + gnutls_datum_t *binder_out); #endif diff --git a/lib/tls13/session_ticket.c b/lib/tls13/session_ticket.c index 7aa75fa10c..da07828bd5 100644 --- a/lib/tls13/session_ticket.c +++ b/lib/tls13/session_ticket.c @@ -489,7 +489,8 @@ cleanup: */ int _gnutls13_unpack_session_ticket(gnutls_session_t session, gnutls_datum_t *data, - gnutls_datum_t *rms, gnutls_mac_algorithm_t *kdf_id) + gnutls_datum_t *rms, gnutls_datum_t *nonce, + gnutls_mac_algorithm_t *kdf_id) { int ret; const unsigned char *p = data->data; @@ -563,6 +564,8 @@ int _gnutls13_unpack_session_ticket(gnutls_session_t session, rms->data = ticket_data.rms; rms->size = ticket_data.rms_len; + nonce->data = ticket_data.ticket_nonce; + nonce->size = ticket_data.ticket_nonce_len; *kdf_id = ticket_data.kdf_id; return decrypted.size; diff --git a/lib/tls13/session_ticket.h b/lib/tls13/session_ticket.h index 79be097b9d..48d0a3c70a 100644 --- a/lib/tls13/session_ticket.h +++ b/lib/tls13/session_ticket.h @@ -35,7 +35,8 @@ int _gnutls13_recv_session_ticket(gnutls_session_t session, int _gnutls13_unpack_session_ticket(gnutls_session_t session, gnutls_datum_t *data, - gnutls_datum_t *rms, gnutls_mac_algorithm_t *kdf_id); + gnutls_datum_t *rms, gnutls_datum_t *nonce, + gnutls_mac_algorithm_t *kdf_id); int _gnutls13_session_ticket_set(gnutls_session_t session, struct tls13_nst_st *ticket, |