diff options
author | Ander Juaristi <a@juaristi.eus> | 2018-02-09 19:15:56 +0100 |
---|---|---|
committer | Ander Juaristi <a@juaristi.eus> | 2018-02-09 20:18:51 +0100 |
commit | c62d35dea3ca5e690dc1b37853ef17ac8d7c5b16 (patch) | |
tree | 7d08481913f62b0507800aac020f467feff19a49 | |
parent | f297bd3321e6b101f9b197824df8a5deb894417c (diff) | |
download | gnutls-c62d35dea3ca5e690dc1b37853ef17ac8d7c5b16.tar.gz |
Introduce new "pre_shared_key" extension parser
* lib/ext/pre_shared_key.c (server_read_identities): remove function.
(server_read_binders): remove function.
(server_recv_params): use the new functions to parse the PskIdentity
and PskBinderEntry structures.
* lib/tls13/psk_ext_parser.c, lib/tls13/psk_ext_parser.c
(_gnutls13_psk_ext_parser_init): new function
(_gnutls13_psk_ext_parser_deinit): new function
(_gnutls13_psk_ext_parser_next_psk): new function
(_gnutls13_psk_ext_parser_find_binder): new function
Signed-off-by: Ander Juaristi <a@juaristi.eus>
-rw-r--r-- | lib/Makefile.am | 3 | ||||
-rw-r--r-- | lib/ext/pre_shared_key.c | 138 | ||||
-rw-r--r-- | lib/tls13/psk_ext_parser.c | 194 | ||||
-rw-r--r-- | lib/tls13/psk_ext_parser.h | 44 |
4 files changed, 272 insertions, 107 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 7e8b85b066..00e43dda27 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -97,7 +97,8 @@ COBJECTS += tls13/encrypted_extensions.c tls13/encrypted_extensions.h \ tls13/hello_retry.c tls13/hello_retry.h \ tls13/session_ticket.c tls13/session_ticket.h \ tls13/certificate.c tls13/certificate.h \ - tls13/post_handshake.c + tls13/post_handshake.c \ + tls13/psk_ext_parser.c tls13/psk_ext_parser.h if ENABLE_PKCS11 COBJECTS += pkcs11.c pkcs11x.c pkcs11_privkey.c pkcs11_write.c pkcs11_secret.c \ diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c index ace44e9777..0d1e2cd5bf 100644 --- a/lib/ext/pre_shared_key.c +++ b/lib/ext/pre_shared_key.c @@ -23,6 +23,7 @@ #include "gnutls_int.h" #include "auth/psk.h" #include "secrets.h" +#include "tls13/psk_ext_parser.h" #include "tls13/finished.h" #include "auth/psk_passwd.h" #include <ext/pre_shared_key.h> @@ -288,97 +289,6 @@ server_send_params(gnutls_session_t session, gnutls_buffer_t extdata) return 2; } -static int -server_read_identities(gnutls_session_t session, - const unsigned char **data_p, long *len_p, - uint16_t ttl_identities_len, gnutls_datum_t *key) -{ - int ret, psk_index = 0, psk_found = 0; - char *identity; - uint16_t identity_len; - uint16_t identities_read = 0; - const unsigned char *data = *data_p; - long len = *len_p; - - /* Read a PskIdentity structure */ - identity_len = _gnutls_read_uint16(data); - if (identity_len == 0) - return -1; - - DECR_LEN(len, 2); - data += 2; - identities_read += 2; - - identity = gnutls_calloc(1, identity_len + 1); - if (!identity) - return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); - memcpy(identity, data, identity_len); - - DECR_LEN(len, identity_len); - data += identity_len; - identities_read += identity_len; - - /* Skip the obfuscated ticket age (we ignore it) */ - DECR_LEN(len, 4); - data += 4; - identities_read += 4; - - ret = _gnutls_psk_pwd_find_entry(session, identity, key); - gnutls_free(identity); - - if (ret == 0) - psk_found = 1; - - *len_p = len; - *data_p = data; - return (psk_found ? psk_index : ret); -} - -static int -server_read_binders(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) { - DECR_LEN(len, 1); - - binder_len = *data; - if (binder_len == 0) - return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); - - 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; - DECR_LEN(len, binder_len); - memcpy(binder_recvd->data, data, binder_recvd->size); - 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_ILLEGAL_PARAMETER)); -} - static int server_recv_params(gnutls_session_t session, const unsigned char *data, long len, const gnutls_psk_server_credentials_t pskcred) @@ -387,37 +297,53 @@ static int server_recv_params(gnutls_session_t session, const mac_entry_st *prf; 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 = 0; + int psk_index = -1; gnutls_datum_t binder_recvd = { NULL, 0 }; gnutls_datum_t key; unsigned hash_size; + psk_ext_parser_t psk_parser; + struct psk_st psk; - 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) { + /* No PSKs advertised by client */ return 0; + } else if (ret < 0) { + return gnutls_assert_val(ret); + } + + if (_gnutls13_psk_ext_parser_next_psk(psk_parser, &psk) >= 0) { + /* _gnutls_psk_pwd_find_entry() expects 0-terminated identities */ + if (psk.identity.size > 0) { + char identity_str[psk.identity.size + 1]; - DECR_LEN(len, 2); - data += 2; + memcpy(identity_str, psk.identity.data, psk.identity.size); + identity_str[psk.identity.size] = 0; + + ret = _gnutls_psk_pwd_find_entry(session, identity_str, &key); + if (ret == 0) + psk_index = psk.selected_index; + } + } - psk_index = server_read_identities(session, - &data, &len, - ttl_identities_len, &key); if (psk_index < 0) return 0; - DECR_LEN(len, 2); - data += 2; - - ret = server_read_binders(&data, &len, - psk_index, &binder_recvd); + 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); + ret = _gnutls13_psk_ext_parser_deinit(&psk_parser, + &data, (size_t *) &len); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + priv = gnutls_malloc(sizeof(psk_ext_st)); if (!priv) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); diff --git a/lib/tls13/psk_ext_parser.c b/lib/tls13/psk_ext_parser.c new file mode 100644 index 0000000000..702c060586 --- /dev/null +++ b/lib/tls13/psk_ext_parser.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * Author: Ander Juaristi + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ +#include "tls13/psk_ext_parser.h" + +struct psk_ext_parser_st { + unsigned char *data; + ssize_t len; + uint16_t obj_len; + uint16_t obj_read; + int next_index; +}; + +static int advance_to_end_of_object(psk_ext_parser_t p) +{ + 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; +} + +int _gnutls13_psk_ext_parser_init(psk_ext_parser_t *p, + const unsigned char *data, size_t len) +{ + uint16_t identities_len; + + if (!p || !data || !len) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + *p = gnutls_calloc(1, sizeof(struct psk_ext_parser_st)); + if (!*p) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + 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(psk_ext_parser_t *pp, + const unsigned char **data, size_t *len) +{ + psk_ext_parser_t p; + + if (!pp || !*pp) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + p = *pp; + + 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; + +end: + gnutls_free(p); + *pp = NULL; + return 0; +} + +int _gnutls13_psk_ext_parser_next_psk(psk_ext_parser_t p, struct psk_st *psk) +{ + 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 GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + + DECR_LEN(p->len, 2); + p->data += 2; + p->obj_read += 2; + + psk->identity.data = p->data; + + DECR_LEN(p->len, psk->identity.size); + p->data += 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->obj_read += 4; + + psk->selected_index = p->next_index++; + return psk->selected_index; +} + +int _gnutls13_psk_ext_parser_find_binder(psk_ext_parser_t 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); + + DECR_LEN(p->len, 2); + binders_len = _gnutls_read_uint16(p->data); + if (binders_len > 0) { + 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 (!binder_found && p->len > 0) { + DECR_LEN(p->len, 1); + binder_len = *(p->data); + + if (binder_len == 0) + return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); + + 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; + DECR_LEN(p->len, binder_len); + memcpy(binder_out->data, p->data, binder_len); + p->data += binder_len; + p->obj_read += binder_len; + + binder_found = 1; + } else { + /* Not our binder - continue to the next one */ + DECR_LEN(p->len, binder_len); + p->data += binder_len; + p->obj_read += binder_len; + + binder_len = 0; + cur_index++; + } + } + + return (binder_found ? + 0 : + gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)); +} diff --git a/lib/tls13/psk_ext_parser.h b/lib/tls13/psk_ext_parser.h new file mode 100644 index 0000000000..d8eab03d8d --- /dev/null +++ b/lib/tls13/psk_ext_parser.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * Author: Ander Juaristi + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef PSK_PARSER_H +#define PSK_PARSER_H +#include "gnutls_int.h" + +struct psk_ext_parser_st; +typedef struct psk_ext_parser_st *psk_ext_parser_t; + +struct psk_st { + gnutls_datum_t identity; + uint32_t ob_ticket_age; + int selected_index; +}; + +int _gnutls13_psk_ext_parser_init(psk_ext_parser_t *p, + const unsigned char *data, size_t len); +int _gnutls13_psk_ext_parser_deinit(psk_ext_parser_t *p, + const unsigned char **data, size_t *len); +int _gnutls13_psk_ext_parser_next_psk(psk_ext_parser_t p, struct psk_st *psk); +int _gnutls13_psk_ext_parser_find_binder(psk_ext_parser_t p, int psk_index, + gnutls_datum_t *binder_out); + +#endif |