summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAnder Juaristi <a@juaristi.eus>2018-04-18 20:56:07 +0200
committerDaiki Ueno <dueno@redhat.com>2018-04-20 16:10:20 +0200
commitb65254724993d4fd5a290d439321f5d8ff54e4c5 (patch)
treed2f31251bb8e64288477034a3a88d5bbd2461c35 /lib
parent277b2e9b054884b6e5317a313e1a6433402c4bca (diff)
downloadgnutls-b65254724993d4fd5a290d439321f5d8ff54e4c5.tar.gz
ext/psk_ke_modes: Take into account of server priority stringtmp-session-resumption-tls13
Signed-off-by: Ander Juaristi <a@juaristi.eus>
Diffstat (limited to 'lib')
-rw-r--r--lib/auth/dhe_psk.c4
-rw-r--r--lib/auth/psk.c2
-rw-r--r--lib/auth/psk_passwd.c7
-rw-r--r--lib/auth/psk_passwd.h4
-rw-r--r--lib/auth/rsa_psk.c2
-rw-r--r--lib/ext/pre_shared_key.c26
-rw-r--r--lib/ext/psk_ke_modes.c226
-rw-r--r--lib/gnutls_int.h9
8 files changed, 155 insertions, 125 deletions
diff --git a/lib/auth/dhe_psk.c b/lib/auth/dhe_psk.c
index cb0c203a91..0d4d86ad03 100644
--- a/lib/auth/dhe_psk.c
+++ b/lib/auth/dhe_psk.c
@@ -323,7 +323,7 @@ proc_dhe_psk_client_kx(gnutls_session_t session, uint8_t * data,
data += username.size + 2;
ret =
- _gnutls_psk_pwd_find_entry(session, info->username, &psk_key);
+ _gnutls_psk_pwd_find_entry(session, cred, info->username, &psk_key);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -392,7 +392,7 @@ proc_ecdhe_psk_client_kx(gnutls_session_t session, uint8_t * data,
/* should never fail. It will always return a key even if it is
* a random one */
ret =
- _gnutls_psk_pwd_find_entry(session, info->username, &psk_key);
+ _gnutls_psk_pwd_find_entry(session, cred, info->username, &psk_key);
if (ret < 0)
return gnutls_assert_val(ret);
diff --git a/lib/auth/psk.c b/lib/auth/psk.c
index 6968bb8057..113fd53468 100644
--- a/lib/auth/psk.c
+++ b/lib/auth/psk.c
@@ -235,7 +235,7 @@ _gnutls_proc_psk_client_kx(gnutls_session_t session, uint8_t * data,
info->username[username.size] = 0;
ret =
- _gnutls_psk_pwd_find_entry(session, info->username, &psk_key);
+ _gnutls_psk_pwd_find_entry(session, cred, info->username, &psk_key);
if (ret < 0)
return gnutls_assert_val(ret);
diff --git a/lib/auth/psk_passwd.c b/lib/auth/psk_passwd.c
index dfaac2bea2..893c1fb0cd 100644
--- a/lib/auth/psk_passwd.c
+++ b/lib/auth/psk_passwd.c
@@ -105,18 +105,15 @@ static int _randomize_psk(gnutls_datum_t * psk)
* If the user doesn't exist a random password is returned instead.
*/
int
-_gnutls_psk_pwd_find_entry(gnutls_session_t session, char *username,
- gnutls_datum_t * psk)
+_gnutls_psk_pwd_find_entry(gnutls_session_t session, gnutls_psk_server_credentials_t cred,
+ char *username, gnutls_datum_t * psk)
{
- gnutls_psk_server_credentials_t cred;
FILE *fd;
char *line = NULL;
size_t line_size = 0;
unsigned i, len;
int ret;
- cred = (gnutls_psk_server_credentials_t)
- _gnutls_get_cred(session, GNUTLS_CRD_PSK);
if (cred == NULL) {
gnutls_assert();
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
diff --git a/lib/auth/psk_passwd.h b/lib/auth/psk_passwd.h
index 8fe7ae4b02..0bfdf53f4a 100644
--- a/lib/auth/psk_passwd.h
+++ b/lib/auth/psk_passwd.h
@@ -21,8 +21,8 @@
*/
/* this is locally allocated. It should be freed using the provided function */
-int _gnutls_psk_pwd_find_entry(gnutls_session_t, char *username,
- gnutls_datum_t * key);
+int _gnutls_psk_pwd_find_entry(gnutls_session_t, gnutls_psk_server_credentials_t cred,
+ char *username, gnutls_datum_t * key);
int _gnutls_find_psk_key(gnutls_session_t session,
gnutls_psk_client_credentials_t cred,
diff --git a/lib/auth/rsa_psk.c b/lib/auth/rsa_psk.c
index 5a29f91837..337f36ef83 100644
--- a/lib/auth/rsa_psk.c
+++ b/lib/auth/rsa_psk.c
@@ -398,7 +398,7 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
/* find the key of this username
*/
ret =
- _gnutls_psk_pwd_find_entry(session, info->username, &pwd_psk);
+ _gnutls_psk_pwd_find_entry(session, cred, info->username, &pwd_psk);
if (ret < 0) {
gnutls_assert();
goto cleanup;
diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c
index 10e5d0a2e3..8338550389 100644
--- a/lib/ext/pre_shared_key.c
+++ b/lib/ext/pre_shared_key.c
@@ -398,7 +398,7 @@ static int server_recv_params(gnutls_session_t session,
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);
+ ret = _gnutls_psk_pwd_find_entry(session, pskcred, identity_str, &key);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -487,13 +487,6 @@ static int server_recv_params(gnutls_session_t session,
goto fail;
}
- if (session->internals.hsk_flags & HSK_PSK_KE_MODE_DHE_PSK)
- _gnutls_handshake_log("EXT[%p]: Selected DHE-PSK mode\n", session);
- else {
- reset_cand_groups(session);
- _gnutls_handshake_log("EXT[%p]: Selected PSK mode\n", session);
- }
-
/* save the username in psk_auth_info to make it available
* using gnutls_psk_server_get_username() */
if (psk_kind == PSK) {
@@ -589,10 +582,11 @@ static int _gnutls_psk_send_params(gnutls_session_t session,
if (!session->internals.session_ticket_enable && !session->internals.priorities->have_psk)
return 0;
- if (session->internals.hsk_flags & HSK_PSK_KE_MODES_RECEIVED)
- return server_send_params(session, extdata);
- else
+ /* No overlapping key exchange modes */
+ if (session->internals.psk_ke_modes_size == 0)
return 0;
+
+ return server_send_params(session, extdata);
}
}
@@ -625,12 +619,12 @@ static int _gnutls_psk_recv_params(gnutls_session_t session,
return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
}
} else {
- if (session->internals.hsk_flags & HSK_PSK_KE_MODES_RECEIVED) {
- if (session->internals.hsk_flags & HSK_PSK_KE_MODE_INVALID) {
- /* We received a "psk_ke_modes" extension, but with a value we don't support */
- return 0;
- }
+ if (session->internals.hsk_flags & HSK_PSK_KE_MODE_INVALID) {
+ /* We received a "psk_ke_modes" extension, but with a value we don't support */
+ return 0;
+ }
+ if (session->internals.psk_ke_modes_size > 0) {
pskcred = (gnutls_psk_server_credentials_t)
_gnutls_get_cred(session, GNUTLS_CRD_PSK);
diff --git a/lib/ext/psk_ke_modes.c b/lib/ext/psk_ke_modes.c
index 56b382e1f5..1c22c74c07 100644
--- a/lib/ext/psk_ke_modes.c
+++ b/lib/ext/psk_ke_modes.c
@@ -25,50 +25,71 @@
#include "ext/pre_shared_key.h"
#include <assert.h>
-#define PSK_KE 0
-#define PSK_DHE_KE 1
+static void get_server_kx_algo_order(gnutls_session_t session, int *psk_pos, int *dhpsk_pos)
+{
+ unsigned i;
-/*
- * We only support ECDHE-authenticated PSKs.
- * The client just sends a "psk_key_exchange_modes" extension
- * with the value one.
- */
-static int
-psk_ke_modes_send_params(gnutls_session_t session,
- gnutls_buffer_t extdata)
+ *psk_pos = INT_MAX;
+ *dhpsk_pos = INT_MAX;
+
+ for (i = 0; i < session->internals.priorities->_kx.algorithms; i++) {
+ if (session->internals.priorities->_kx.priority[i] == GNUTLS_KX_PSK &&
+ *psk_pos == INT_MAX)
+ *psk_pos = i;
+ else if ((session->internals.priorities->_kx.priority[i] == GNUTLS_KX_DHE_PSK ||
+ session->internals.priorities->_kx.priority[i] == GNUTLS_KX_ECDHE_PSK) &&
+ *dhpsk_pos == INT_MAX)
+ *dhpsk_pos = i;
+
+ if (*psk_pos != INT_MAX && *dhpsk_pos != INT_MAX)
+ break;
+ }
+}
+
+static void get_client_kx_algo_order(gnutls_session_t session, int *psk_pos, int *dhpsk_pos)
{
- int ret;
- gnutls_psk_client_credentials_t cred;
- const version_entry_st *vers;
- uint8_t data[2];
- unsigned pos, i;
- unsigned have_dhpsk = 0;
- unsigned have_psk = 0;
+ *dhpsk_pos = INT_MAX;
+ *psk_pos = INT_MAX;
+
+ for (unsigned i = 0; i < session->internals.psk_ke_modes_size; i++) {
+ if (session->internals.psk_ke_modes[i] == PSK_DHE_KE)
+ *dhpsk_pos = i;
+ else if (session->internals.psk_ke_modes[i] == PSK_KE)
+ *psk_pos = i;
+ }
+}
- /* Server doesn't send psk_key_exchange_modes */
- if (session->security_parameters.entity == GNUTLS_SERVER)
- return 0;
+static int check_ke_modes(gnutls_session_t session)
+{
+ int mode = -1;
+ int psk_pos, dhpsk_pos;
+ int cli_psk_pos, cli_dhpsk_pos;
- cred = (gnutls_psk_client_credentials_t)
- _gnutls_get_cred(session, GNUTLS_CRD_PSK);
- if (cred == NULL || _gnutls_have_psk_credentials(cred) == 0) {
- /*
- * No out-of-band PSKs - do we have a session ticket?
- * We're not interested in the ticket itself.
- */
- if (session->internals.tls13_ticket.ticket.data == NULL)
- return 0;
+ get_server_kx_algo_order(session, &psk_pos, &dhpsk_pos);
+ get_client_kx_algo_order(session, &cli_psk_pos, &cli_dhpsk_pos);
+
+ if (session->internals.priorities->server_precedence) {
+ if (dhpsk_pos != INT_MAX && cli_dhpsk_pos != INT_MAX && dhpsk_pos < psk_pos)
+ mode = PSK_DHE_KE;
+ else if (psk_pos != INT_MAX && cli_psk_pos != INT_MAX && psk_pos < dhpsk_pos)
+ mode = PSK_KE;
} else {
- if (!session->internals.priorities->have_psk)
- return 0;
+ if (dhpsk_pos != INT_MAX && cli_dhpsk_pos != INT_MAX && cli_dhpsk_pos < cli_psk_pos)
+ mode = PSK_DHE_KE;
+ else if (psk_pos != INT_MAX && cli_psk_pos != INT_MAX && cli_psk_pos < cli_dhpsk_pos)
+ mode = PSK_KE;
}
- vers = _gnutls_version_max(session);
- if (!vers || !vers->tls13_sem)
- return 0;
+ return mode;
+}
- pos = 0;
- for (i=0;i<session->internals.priorities->_kx.algorithms;i++) {
+static int make_data(gnutls_session_t session, uint8_t data[2])
+{
+ int pos = 0;
+ unsigned have_dhpsk = 0;
+ unsigned have_psk = 0;
+
+ for (unsigned i = 0; i < session->internals.priorities->_kx.algorithms; i++) {
if (session->internals.priorities->_kx.priority[i] == GNUTLS_KX_PSK && !have_psk) {
assert(pos <= 1);
data[pos++] = PSK_KE;
@@ -86,22 +107,50 @@ psk_ke_modes_send_params(gnutls_session_t session,
break;
}
- ret = _gnutls_buffer_append_data_prefix(extdata, 8, data, pos);
- if (ret < 0)
- return gnutls_assert_val(ret);
+ return pos;
+}
+
+static int
+psk_ke_modes_send_params(gnutls_session_t session,
+ gnutls_buffer_t extdata)
+{
+ int ret;
+ gnutls_psk_client_credentials_t cred;
+ const version_entry_st *vers;
+ uint8_t data[2];
+ unsigned pos;
+
+ /* Server doesn't send psk_key_exchange_modes */
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ return 0;
- session->internals.hsk_flags |= HSK_PSK_KE_MODES_SENT;
+ vers = _gnutls_version_max(session);
+ if (!vers || !vers->tls13_sem)
+ return 0;
+
+ cred = (gnutls_psk_client_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_PSK);
+ if (cred == NULL || _gnutls_have_psk_credentials(cred) == 0) {
+ /* No out-of-band PSKs - do we have a session ticket? */
+ if (!session->internals.session_ticket_enable ||
+ session->internals.tls13_ticket.ticket.data == NULL)
+ return 0;
+ } else {
+ if (!session->internals.priorities->have_psk)
+ return 0;
+ }
+
+ pos = make_data(session, data);
+ if (pos > 0) {
+ ret = _gnutls_buffer_append_data_prefix(extdata, 8, data, pos);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ session->internals.hsk_flags |= HSK_PSK_KE_MODES_SENT;
+ }
return 0;
}
-#define MAX_POS INT_MAX
-
-/*
- * Since we only support ECDHE-authenticated PSKs, the server
- * just verifies that a "psk_key_exchange_modes" extension was received,
- * and that it contains the value one.
- */
static int
psk_ke_modes_recv_params(gnutls_session_t session,
const unsigned char *data, size_t _len)
@@ -109,12 +158,10 @@ psk_ke_modes_recv_params(gnutls_session_t session,
uint8_t ke_modes_len;
ssize_t len = _len;
const version_entry_st *vers = get_version(session);
- gnutls_psk_server_credentials_t cred;
- int dhpsk_pos = MAX_POS;
- int psk_pos = MAX_POS;
- int cli_psk_pos = MAX_POS;
- int cli_dhpsk_pos = MAX_POS;
- unsigned i;
+ int selected_ke_modes[2];
+ unsigned have_dhpsk = 0;
+ unsigned have_psk = 0;
+ unsigned i, pos = 0;
/* Server doesn't send psk_key_exchange_modes */
if (session->security_parameters.entity == GNUTLS_CLIENT)
@@ -123,59 +170,48 @@ psk_ke_modes_recv_params(gnutls_session_t session,
if (!vers || !vers->tls13_sem)
return 0;
- cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(session, GNUTLS_CRD_PSK);
- if (cred == NULL && !session->internals.session_ticket_enable)
- return 0;
-
DECR_LEN(len, 1);
ke_modes_len = *(data++);
- for (i=0;i<session->internals.priorities->_kx.algorithms;i++) {
- if (session->internals.priorities->_kx.priority[i] == GNUTLS_KX_PSK && psk_pos == MAX_POS) {
- psk_pos = i;
- } else if ((session->internals.priorities->_kx.priority[i] == GNUTLS_KX_DHE_PSK ||
- session->internals.priorities->_kx.priority[i] == GNUTLS_KX_ECDHE_PSK) &&
- dhpsk_pos == MAX_POS) {
- dhpsk_pos = i;
- }
+ for (i = 0; i < ke_modes_len; i++) {
+ DECR_LEN(len, 1);
- if (dhpsk_pos != MAX_POS && psk_pos != MAX_POS)
+ switch (data[i]) {
+ case PSK_DHE_KE:
+ selected_ke_modes[pos++] = PSK_DHE_KE;
+ have_dhpsk = 1;
break;
- }
-
- if (session->internals.priorities->groups.size == 0 && psk_pos == MAX_POS)
- return gnutls_assert_val(0);
-
- for (i=0;i<ke_modes_len;i++) {
- DECR_LEN(len, 1);
- if (data[i] == PSK_DHE_KE)
- cli_dhpsk_pos = i;
- else if (data[i] == PSK_KE)
- cli_psk_pos = i;
+ case PSK_KE:
+ selected_ke_modes[pos++] = PSK_KE;
+ have_psk = 1;
+ break;
+ default:
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
+ return 0;
+ }
- if (cli_psk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS)
+ if (have_dhpsk && have_psk)
break;
}
- if (session->internals.priorities->server_precedence) {
- if (dhpsk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS && dhpsk_pos < psk_pos)
- session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
- else if (psk_pos != MAX_POS && cli_psk_pos != MAX_POS && psk_pos < dhpsk_pos)
- session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
- } else {
- if (dhpsk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS && cli_dhpsk_pos < cli_psk_pos)
- session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
- else if (psk_pos != MAX_POS && cli_psk_pos != MAX_POS && cli_psk_pos < cli_dhpsk_pos)
- session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
+ for (i = 0; i < pos; i++)
+ session->internals.psk_ke_modes[i] = selected_ke_modes[i];
+ session->internals.psk_ke_modes_size = pos;
+
+ switch (check_ke_modes(session)) {
+ case PSK_DHE_KE:
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
+ _gnutls_handshake_log("EXT[%p]: Selected DHE-PSK mode\n", session);
+ break;
+ case PSK_KE:
+ session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
+ _gnutls_handshake_log("EXT[%p]: Selected PSK mode\n", session);
+ break;
+ default:
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
}
- if ((session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK) ||
- (session->internals.hsk_flags & HSK_PSK_KE_MODE_DHE_PSK)) {
- return 0;
- } else {
- session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
- return 0;
- }
+ return 0;
}
const hello_ext_entry_st ext_psk_ke_modes = {
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 08c76f5caf..2871607b53 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -1225,9 +1225,6 @@ typedef struct {
/* it is a copy of the handshake hash buffer if post handshake is used */
gnutls_buffer_st post_handshake_hash_buffer;
-/* When either of PSK or DHE-PSK is received */
-#define HSK_PSK_KE_MODES_RECEIVED (HSK_PSK_KE_MODE_PSK|HSK_PSK_KE_MODE_DHE_PSK|HSK_PSK_KE_MODE_INVALID)
-
#define HSK_CRT_VRFY_EXPECTED 1
#define HSK_CRT_SENT (1<<1)
#define HSK_CRT_ASKED (1<<2)
@@ -1345,6 +1342,12 @@ typedef struct {
/* the ciphersuite received in HRR */
uint8_t hrr_cs[2];
+#define PSK_KE 0
+#define PSK_DHE_KE 1
+
+ int psk_ke_modes[2];
+ unsigned psk_ke_modes_size;
+
int session_ticket_enable;
int session_ticket_renew;