summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnder Juaristi <a@juaristi.eus>2018-02-09 19:15:56 +0100
committerAnder Juaristi <a@juaristi.eus>2018-02-09 20:18:51 +0100
commitc62d35dea3ca5e690dc1b37853ef17ac8d7c5b16 (patch)
tree7d08481913f62b0507800aac020f467feff19a49
parentf297bd3321e6b101f9b197824df8a5deb894417c (diff)
downloadgnutls-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.am3
-rw-r--r--lib/ext/pre_shared_key.c138
-rw-r--r--lib/tls13/psk_ext_parser.c194
-rw-r--r--lib/tls13/psk_ext_parser.h44
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