|
Packit |
aea12f |
/*
|
|
Packit |
aea12f |
* Copyright (C) 2017-2018 Free Software Foundation, Inc.
|
|
Packit |
aea12f |
* Copyright (C) 2018 Red Hat, Inc.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Author: Ander Juaristi, Nikos Mavrogiannopoulos
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This file is part of GnuTLS.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit |
aea12f |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit |
aea12f |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
aea12f |
* the License, or (at your option) any later version.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This library is distributed in the hope that it will be useful, but
|
|
Packit |
aea12f |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
aea12f |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
aea12f |
* Lesser General Public License for more details.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
aea12f |
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
#include "gnutls_int.h"
|
|
Packit |
aea12f |
#include "auth/psk.h"
|
|
Packit |
aea12f |
#include "handshake.h"
|
|
Packit |
aea12f |
#include "kx.h"
|
|
Packit |
aea12f |
#include "secrets.h"
|
|
Packit |
aea12f |
#include "tls13/anti_replay.h"
|
|
Packit |
aea12f |
#include "tls13/psk_ext_parser.h"
|
|
Packit |
aea12f |
#include "tls13/finished.h"
|
|
Packit |
aea12f |
#include "tls13/session_ticket.h"
|
|
Packit |
aea12f |
#include "auth/psk_passwd.h"
|
|
Packit |
aea12f |
#include <ext/session_ticket.h>
|
|
Packit |
aea12f |
#include <ext/pre_shared_key.h>
|
|
Packit |
aea12f |
#include <assert.h>
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
compute_psk_from_ticket(const tls13_ticket_st *ticket, gnutls_datum_t *key)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (unlikely(ticket->prf == NULL || ticket->prf->output_size == 0))
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
key->data = gnutls_malloc(ticket->prf->output_size);
|
|
Packit |
aea12f |
if (!key->data) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_MEMORY_ERROR;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
key->size = ticket->prf->output_size;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _tls13_expand_secret2(ticket->prf,
|
|
Packit |
aea12f |
RESUMPTION_LABEL, sizeof(RESUMPTION_LABEL)-1,
|
|
Packit |
aea12f |
ticket->nonce, ticket->nonce_size,
|
|
Packit |
aea12f |
ticket->resumption_master_secret,
|
|
Packit |
aea12f |
key->size,
|
|
Packit |
aea12f |
key->data);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
compute_binder_key(const mac_entry_st *prf,
|
|
Packit |
aea12f |
const uint8_t *key, size_t keylen,
|
|
Packit |
aea12f |
bool resuming,
|
|
Packit |
aea12f |
void *out)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
const char ext_label[] = EXT_BINDER_LABEL;
|
|
Packit |
aea12f |
const size_t ext_label_len = sizeof(ext_label) - 1;
|
|
Packit |
aea12f |
const char res_label[] = RES_BINDER_LABEL;
|
|
Packit |
aea12f |
const size_t res_label_len = sizeof(res_label) - 1;
|
|
Packit |
aea12f |
const char *label = resuming ? res_label : ext_label;
|
|
Packit |
aea12f |
size_t label_len = resuming ? res_label_len : ext_label_len;
|
|
Packit |
aea12f |
uint8_t tmp_key[MAX_HASH_SIZE];
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Compute HKDF-Extract(0, psk) */
|
|
Packit |
aea12f |
ret = _tls13_init_secret2(prf, key, keylen, tmp_key);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Compute Derive-Secret(secret, label, transcript_hash) */
|
|
Packit |
aea12f |
ret = _tls13_derive_secret2(prf, label, label_len,
|
|
Packit |
aea12f |
NULL, 0, tmp_key, out);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
compute_psk_binder(gnutls_session_t session,
|
|
Packit |
aea12f |
const mac_entry_st *prf, unsigned binders_length,
|
|
Packit |
aea12f |
int exts_length, int ext_offset,
|
|
Packit |
aea12f |
const gnutls_datum_t *psk, const gnutls_datum_t *client_hello,
|
|
Packit |
aea12f |
bool resuming, void *out)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
unsigned client_hello_pos, extensions_len_pos;
|
|
Packit |
aea12f |
gnutls_buffer_st handshake_buf;
|
|
Packit |
aea12f |
uint8_t binder_key[MAX_HASH_SIZE];
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_buffer_init(&handshake_buf);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->security_parameters.entity == GNUTLS_CLIENT) {
|
|
Packit |
aea12f |
if (session->internals.hsk_flags & HSK_HRR_RECEIVED) {
|
|
Packit |
aea12f |
ret = gnutls_buffer_append_data(&handshake_buf,
|
|
Packit |
aea12f |
(const void *) session->internals.handshake_hash_buffer.data,
|
|
Packit |
aea12f |
session->internals.handshake_hash_buffer.length);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
client_hello_pos = handshake_buf.length;
|
|
Packit |
aea12f |
ret = gnutls_buffer_append_data(&handshake_buf, client_hello->data,
|
|
Packit |
aea12f |
client_hello->size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* This is a ClientHello message */
|
|
Packit |
aea12f |
handshake_buf.data[client_hello_pos] = GNUTLS_HANDSHAKE_CLIENT_HELLO;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* At this point we have not yet added the binders to the ClientHello,
|
|
Packit |
aea12f |
* but we have to overwrite the size field, pretending as if binders
|
|
Packit |
aea12f |
* of the correct length were present.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
_gnutls_write_uint24(handshake_buf.length - client_hello_pos + binders_length - 2, &handshake_buf.data[client_hello_pos + 1]);
|
|
Packit |
aea12f |
_gnutls_write_uint16(handshake_buf.length - client_hello_pos + binders_length - ext_offset,
|
|
Packit |
aea12f |
&handshake_buf.data[client_hello_pos + ext_offset]);
|
|
Packit |
aea12f |
extensions_len_pos = handshake_buf.length - client_hello_pos - exts_length - 2;
|
|
Packit |
aea12f |
_gnutls_write_uint16(exts_length + binders_length + 2,
|
|
Packit |
aea12f |
&handshake_buf.data[client_hello_pos + extensions_len_pos]);
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
if (session->internals.hsk_flags & HSK_HRR_SENT) {
|
|
Packit |
aea12f |
if (unlikely(session->internals.handshake_hash_buffer.length <= client_hello->size)) {
|
|
Packit |
aea12f |
ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = gnutls_buffer_append_data(&handshake_buf,
|
|
Packit |
aea12f |
session->internals.handshake_hash_buffer.data,
|
|
Packit |
aea12f |
session->internals.handshake_hash_buffer.length - client_hello->size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (unlikely(client_hello->size <= binders_length)) {
|
|
Packit |
aea12f |
ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = gnutls_buffer_append_data(&handshake_buf,
|
|
Packit |
aea12f |
(const void *) client_hello->data,
|
|
Packit |
aea12f |
client_hello->size - binders_length);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = compute_binder_key(prf,
|
|
Packit |
aea12f |
psk->data, psk->size, resuming,
|
|
Packit |
aea12f |
binder_key);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls13_compute_finished(prf, binder_key,
|
|
Packit |
aea12f |
&handshake_buf,
|
|
Packit |
aea12f |
out);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
_gnutls_buffer_clear(&handshake_buf);
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
generate_early_secrets(gnutls_session_t session,
|
|
Packit |
aea12f |
const mac_entry_st *prf)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _tls13_derive_secret2(prf, EARLY_TRAFFIC_LABEL, sizeof(EARLY_TRAFFIC_LABEL)-1,
|
|
Packit |
aea12f |
session->internals.handshake_hash_buffer.data,
|
|
Packit |
aea12f |
session->internals.handshake_hash_buffer_client_hello_len,
|
|
Packit |
aea12f |
session->key.proto.tls13.temp_secret,
|
|
Packit |
aea12f |
session->key.proto.tls13.e_ckey);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit Service |
991b93 |
ret = _gnutls_call_keylog_func(session, "CLIENT_EARLY_TRAFFIC_SECRET",
|
|
Packit Service |
991b93 |
session->key.proto.tls13.e_ckey,
|
|
Packit Service |
991b93 |
prf->output_size);
|
|
Packit Service |
991b93 |
if (ret < 0)
|
|
Packit Service |
991b93 |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _tls13_derive_secret2(prf, EARLY_EXPORTER_MASTER_LABEL, sizeof(EARLY_EXPORTER_MASTER_LABEL)-1,
|
|
Packit |
aea12f |
session->internals.handshake_hash_buffer.data,
|
|
Packit |
aea12f |
session->internals.handshake_hash_buffer_client_hello_len,
|
|
Packit |
aea12f |
session->key.proto.tls13.temp_secret,
|
|
Packit |
aea12f |
session->key.proto.tls13.ap_expkey);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit Service |
991b93 |
ret = _gnutls_call_keylog_func(session, "EARLY_EXPORTER_SECRET",
|
|
Packit Service |
991b93 |
session->key.proto.tls13.ap_expkey,
|
|
Packit Service |
991b93 |
prf->output_size);
|
|
Packit Service |
991b93 |
if (ret < 0)
|
|
Packit Service |
991b93 |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Calculate TLS 1.3 Early Secret and the derived secrets from the
|
|
Packit |
aea12f |
* selected PSK. */
|
|
Packit |
aea12f |
int
|
|
Packit |
aea12f |
_gnutls_generate_early_secrets_for_psk(gnutls_session_t session)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
const uint8_t *psk;
|
|
Packit |
aea12f |
size_t psk_size;
|
|
Packit |
aea12f |
const mac_entry_st *prf;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
psk = session->key.binders[0].psk.data;
|
|
Packit |
aea12f |
psk_size = session->key.binders[0].psk.size;
|
|
Packit |
aea12f |
prf = session->key.binders[0].prf;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (unlikely(psk_size == 0))
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _tls13_init_secret2(prf, psk, psk_size,
|
|
Packit |
aea12f |
session->key.proto.tls13.temp_secret);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->key.proto.tls13.temp_secret_size = prf->output_size;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = generate_early_secrets(session, session->key.binders[0].prf);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
client_send_params(gnutls_session_t session,
|
|
Packit |
aea12f |
gnutls_buffer_t extdata,
|
|
Packit |
aea12f |
const gnutls_psk_client_credentials_t cred)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret, ext_offset = 0;
|
|
Packit |
aea12f |
uint8_t binder_value[MAX_HASH_SIZE];
|
|
Packit |
aea12f |
size_t spos;
|
|
Packit |
aea12f |
gnutls_datum_t username = {NULL, 0};
|
|
Packit |
aea12f |
gnutls_datum_t user_key = {NULL, 0}, rkey = {NULL, 0};
|
|
Packit |
aea12f |
gnutls_datum_t client_hello;
|
|
Packit |
aea12f |
unsigned next_idx;
|
|
Packit |
aea12f |
const mac_entry_st *prf_res = NULL;
|
|
Packit |
aea12f |
const mac_entry_st *prf_psk = NULL;
|
|
Packit |
aea12f |
struct timespec cur_time;
|
|
Packit |
aea12f |
uint32_t ticket_age, ob_ticket_age;
|
|
Packit |
aea12f |
int free_username = 0;
|
|
Packit |
aea12f |
psk_auth_info_t info = NULL;
|
|
Packit |
aea12f |
unsigned psk_id_len = 0;
|
|
Packit |
aea12f |
unsigned binders_len, binders_pos;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (((session->internals.flags & GNUTLS_NO_TICKETS) ||
|
|
Packit |
aea12f |
session->internals.tls13_ticket.ticket.data == NULL) &&
|
|
Packit |
aea12f |
(!cred || !_gnutls_have_psk_credentials(cred, session))) {
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
binders_len = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* placeholder to be filled later */
|
|
Packit |
aea12f |
spos = extdata->length;
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* First, let's see if we have a session ticket to send */
|
|
Packit |
aea12f |
if (!(session->internals.flags & GNUTLS_NO_TICKETS) &&
|
|
Packit |
aea12f |
session->internals.tls13_ticket.ticket.data != NULL) {
|
|
Packit |
aea12f |
/* We found a session ticket */
|
|
Packit |
aea12f |
if (unlikely(session->internals.tls13_ticket.prf == NULL)) {
|
|
Packit |
aea12f |
_gnutls13_session_ticket_unset(session);
|
|
Packit |
aea12f |
ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
prf_res = session->internals.tls13_ticket.prf;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
gnutls_gettime(&cur_time);
|
|
Packit |
aea12f |
if (unlikely(_gnutls_timespec_cmp(&cur_time,
|
|
Packit |
aea12f |
&session->internals.
|
|
Packit |
aea12f |
tls13_ticket.
|
|
Packit |
aea12f |
arrival_time) < 0)) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
_gnutls13_session_ticket_unset(session);
|
|
Packit |
aea12f |
goto ignore_ticket;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Check whether the ticket is stale */
|
|
Packit |
aea12f |
ticket_age = timespec_sub_ms(&cur_time,
|
|
Packit |
aea12f |
&session->internals.tls13_ticket.
|
|
Packit |
aea12f |
arrival_time);
|
|
Packit |
aea12f |
if (ticket_age / 1000 > session->internals.tls13_ticket.lifetime) {
|
|
Packit |
aea12f |
_gnutls13_session_ticket_unset(session);
|
|
Packit |
aea12f |
goto ignore_ticket;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = compute_psk_from_ticket(&session->internals.tls13_ticket, &rkey);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
_gnutls13_session_ticket_unset(session);
|
|
Packit |
aea12f |
goto ignore_ticket;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Calculate obfuscated ticket age, in milliseconds, mod 2^32 */
|
|
Packit |
aea12f |
ob_ticket_age = ticket_age + session->internals.tls13_ticket.age_add;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16,
|
|
Packit |
aea12f |
session->internals.tls13_ticket.ticket.data,
|
|
Packit |
aea12f |
session->internals.tls13_ticket.ticket.size)) < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Now append the obfuscated ticket age */
|
|
Packit |
aea12f |
if ((ret = _gnutls_buffer_append_prefix(extdata, 32, ob_ticket_age)) < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
psk_id_len += 6 + session->internals.tls13_ticket.ticket.size;
|
|
Packit |
aea12f |
binders_len += 1 + _gnutls_mac_get_algo_len(prf_res);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ignore_ticket:
|
|
Packit |
aea12f |
if (cred && _gnutls_have_psk_credentials(cred, session)) {
|
|
Packit |
aea12f |
gnutls_datum_t tkey;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (cred->binder_algo == NULL) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
prf_psk = cred->binder_algo;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_find_psk_key(session, cred, &username, &tkey, &free_username);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (username.size == 0 || username.size > UINT16_MAX) {
|
|
Packit |
aea12f |
ret = gnutls_assert_val(GNUTLS_E_INVALID_PASSWORD);
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (!free_username) {
|
|
Packit |
aea12f |
/* we need to copy the key */
|
|
Packit |
aea12f |
ret = _gnutls_set_datum(&user_key, tkey.data, tkey.size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
user_key.data = tkey.data;
|
|
Packit |
aea12f |
user_key.size = tkey.size;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
|
|
Packit |
aea12f |
assert(info != NULL);
|
|
Packit |
aea12f |
|
|
Packit Service |
991b93 |
_gnutls_copy_psk_username(info, &username);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16,
|
|
Packit |
aea12f |
username.data,
|
|
Packit |
aea12f |
username.size)) < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Now append the obfuscated ticket age */
|
|
Packit |
aea12f |
if ((ret = _gnutls_buffer_append_prefix(extdata, 32, 0)) < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
psk_id_len += 6 + username.size;
|
|
Packit |
aea12f |
binders_len += 1 + _gnutls_mac_get_algo_len(prf_psk);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* if no tickets or identities to be sent */
|
|
Packit |
aea12f |
if (psk_id_len == 0) {
|
|
Packit |
aea12f |
/* reset extensions buffer */
|
|
Packit |
aea12f |
extdata->length = spos;
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_write_uint16(psk_id_len, &extdata->data[spos]);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
binders_pos = extdata->length-spos;
|
|
Packit |
aea12f |
ext_offset = _gnutls_ext_get_extensions_offset(session);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Compute the binders. extdata->data points to the start
|
|
Packit |
aea12f |
* of this client hello. */
|
|
Packit |
aea12f |
assert(extdata->length >= sizeof(mbuffer_st));
|
|
Packit |
aea12f |
assert(ext_offset >= (ssize_t)sizeof(mbuffer_st));
|
|
Packit |
aea12f |
ext_offset -= sizeof(mbuffer_st);
|
|
Packit |
aea12f |
client_hello.data = extdata->data+sizeof(mbuffer_st);
|
|
Packit |
aea12f |
client_hello.size = extdata->length-sizeof(mbuffer_st);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
next_idx = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_prefix(extdata, 16, binders_len);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert_val(ret);
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (prf_res && rkey.size > 0) {
|
|
Packit |
aea12f |
ret = compute_psk_binder(session, prf_res,
|
|
Packit |
aea12f |
binders_len, binders_pos,
|
|
Packit |
aea12f |
ext_offset, &rkey, &client_hello, 1,
|
|
Packit |
aea12f |
binder_value);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Associate the selected pre-shared key with the session */
|
|
Packit |
aea12f |
gnutls_free(session->key.binders[next_idx].psk.data);
|
|
Packit |
aea12f |
session->key.binders[next_idx].psk.data = rkey.data;
|
|
Packit |
aea12f |
session->key.binders[next_idx].psk.size = rkey.size;
|
|
Packit |
aea12f |
rkey.data = NULL;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->key.binders[next_idx].prf = prf_res;
|
|
Packit |
aea12f |
session->key.binders[next_idx].resumption = 1;
|
|
Packit |
aea12f |
session->key.binders[next_idx].idx = next_idx;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_handshake_log("EXT[%p]: sent PSK resumption identity (%d)\n", session, next_idx);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
next_idx++;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Add the binder */
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_res->output_size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->internals.hsk_flags |= HSK_TLS13_TICKET_SENT;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (prf_psk && user_key.size > 0 && info) {
|
|
Packit |
aea12f |
ret = compute_psk_binder(session, prf_psk,
|
|
Packit |
aea12f |
binders_len, binders_pos,
|
|
Packit |
aea12f |
ext_offset, &user_key, &client_hello, 0,
|
|
Packit |
aea12f |
binder_value);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Associate the selected pre-shared key with the session */
|
|
Packit |
aea12f |
gnutls_free(session->key.binders[next_idx].psk.data);
|
|
Packit |
aea12f |
session->key.binders[next_idx].psk.data = user_key.data;
|
|
Packit |
aea12f |
session->key.binders[next_idx].psk.size = user_key.size;
|
|
Packit |
aea12f |
user_key.data = NULL;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->key.binders[next_idx].prf = prf_psk;
|
|
Packit |
aea12f |
session->key.binders[next_idx].resumption = 0;
|
|
Packit |
aea12f |
session->key.binders[next_idx].idx = next_idx;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_handshake_log("EXT[%p]: sent PSK identity '%s' (%d)\n", session, info->username, next_idx);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
next_idx++;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Add the binder */
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_psk->output_size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
cleanup:
|
|
Packit |
aea12f |
if (free_username)
|
|
Packit |
aea12f |
_gnutls_free_datum(&username);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_free_temp_key_datum(&user_key);
|
|
Packit |
aea12f |
_gnutls_free_temp_key_datum(&rkey);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
server_send_params(gnutls_session_t session, gnutls_buffer_t extdata)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (!(session->internals.hsk_flags & HSK_PSK_SELECTED))
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_buffer_append_prefix(extdata, 16,
|
|
Packit |
aea12f |
session->key.binders[0].idx);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 2;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int server_recv_params(gnutls_session_t session,
|
|
Packit |
aea12f |
const unsigned char *data, size_t len,
|
|
Packit |
aea12f |
const gnutls_psk_server_credentials_t pskcred)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
const mac_entry_st *prf;
|
|
Packit |
aea12f |
gnutls_datum_t full_client_hello;
|
|
Packit |
aea12f |
uint8_t binder_value[MAX_HASH_SIZE];
|
|
Packit |
aea12f |
uint16_t psk_index, i;
|
|
Packit |
aea12f |
gnutls_datum_t binder_recvd = { NULL, 0 };
|
|
Packit |
aea12f |
gnutls_datum_t key = {NULL, 0};
|
|
Packit |
aea12f |
psk_ext_parser_st psk_parser;
|
|
Packit |
aea12f |
psk_ext_iter_st psk_iter;
|
|
Packit |
aea12f |
struct psk_st psk;
|
|
Packit |
aea12f |
psk_auth_info_t info;
|
|
Packit |
aea12f |
tls13_ticket_st ticket_data;
|
|
Packit |
aea12f |
/* These values should be set properly when session ticket is accepted. */
|
|
Packit |
aea12f |
uint32_t ticket_age = UINT32_MAX;
|
|
Packit |
aea12f |
struct timespec ticket_creation_time = { 0, 0 };
|
|
Packit |
aea12f |
bool resuming;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls13_psk_ext_parser_init(&psk_parser, data, len);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
/* No PSKs advertised by client */
|
|
Packit |
aea12f |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls13_psk_ext_iter_init(&psk_iter, &psk_parser);
|
|
Packit |
aea12f |
for (psk_index = 0; ; psk_index++) {
|
|
Packit |
aea12f |
ret = _gnutls13_psk_ext_iter_next_identity(&psk_iter, &psk;;
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
/* We couldn't find any usable PSK */
|
|
Packit |
aea12f |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* This will unpack the session ticket if it is well
|
|
Packit |
aea12f |
* formed and has the expected name */
|
|
Packit |
aea12f |
if (!(session->internals.flags & GNUTLS_NO_TICKETS) &&
|
|
Packit |
aea12f |
(ret = _gnutls13_unpack_session_ticket(session, &psk.identity, &ticket_data)) == 0) {
|
|
Packit |
aea12f |
prf = ticket_data.prf;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->internals.resumption_requested = 1;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Check whether ticket is stale or not */
|
|
Packit |
aea12f |
ticket_age = psk.ob_ticket_age - ticket_data.age_add;
|
|
Packit |
aea12f |
if (ticket_age / 1000 > ticket_data.lifetime) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
tls13_ticket_deinit(&ticket_data);
|
|
Packit |
aea12f |
continue;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = compute_psk_from_ticket(&ticket_data, &key);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
tls13_ticket_deinit(&ticket_data);
|
|
Packit |
aea12f |
continue;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
memcpy(&ticket_creation_time,
|
|
Packit |
aea12f |
&ticket_data.creation_time,
|
|
Packit |
aea12f |
sizeof(struct timespec));
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
tls13_ticket_deinit(&ticket_data);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
resuming = 1;
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
} else if (pskcred &&
|
|
Packit |
aea12f |
psk.ob_ticket_age == 0 &&
|
|
Packit |
aea12f |
psk.identity.size > 0 && psk.identity.size <= MAX_USERNAME_SIZE) {
|
|
Packit |
aea12f |
prf = pskcred->binder_algo;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* this fails only on configuration errors; as such we always
|
|
Packit |
aea12f |
* return its error code in that case */
|
|
Packit Service |
991b93 |
ret = _gnutls_psk_pwd_find_entry(session, (char *) psk.identity.data, psk.identity.size, &key);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
resuming = 0;
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls13_psk_ext_iter_init(&psk_iter, &psk_parser);
|
|
Packit |
aea12f |
for (i = 0; i <= psk_index; i++) {
|
|
Packit |
aea12f |
ret = _gnutls13_psk_ext_iter_next_binder(&psk_iter, &binder_recvd);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
/* We couldn't extract binder */
|
|
Packit |
aea12f |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
|
|
Packit |
aea12f |
ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
|
|
Packit |
aea12f |
goto fail;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Get full ClientHello */
|
|
Packit |
aea12f |
if (!_gnutls_ext_get_full_client_hello(session, &full_client_hello)) {
|
|
Packit |
aea12f |
ret = GNUTLS_E_INTERNAL_ERROR;
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto fail;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Compute the binder value for this PSK */
|
|
Packit |
aea12f |
ret = compute_psk_binder(session, prf, psk_parser.binders_len+2, 0, 0,
|
|
Packit |
aea12f |
&key, &full_client_hello, resuming,
|
|
Packit |
aea12f |
binder_value);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto fail;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (_gnutls_mac_get_algo_len(prf) != binder_recvd.size ||
|
|
Packit Service |
6bac9f |
gnutls_memcmp(binder_value, binder_recvd.data, binder_recvd.size)) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
|
|
Packit |
aea12f |
goto fail;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->internals.hsk_flags & HSK_PSK_KE_MODE_DHE_PSK)
|
|
Packit |
aea12f |
_gnutls_handshake_log("EXT[%p]: selected DHE-PSK mode\n", session);
|
|
Packit |
aea12f |
else {
|
|
Packit |
aea12f |
reset_cand_groups(session);
|
|
Packit |
aea12f |
_gnutls_handshake_log("EXT[%p]: selected PSK mode\n", session);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* save the username in psk_auth_info to make it available
|
|
Packit |
aea12f |
* using gnutls_psk_server_get_username() */
|
|
Packit |
aea12f |
if (!resuming) {
|
|
Packit |
aea12f |
assert(psk.identity.size < sizeof(info->username));
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto fail;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
|
|
Packit |
aea12f |
assert(info != NULL);
|
|
Packit |
aea12f |
|
|
Packit Service |
991b93 |
_gnutls_copy_psk_username(info, &psk.identity);
|
|
Packit |
aea12f |
_gnutls_handshake_log("EXT[%p]: selected PSK identity: %s (%d)\n", session, info->username, psk_index);
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
if (session->internals.hsk_flags & HSK_EARLY_DATA_ACCEPTED) {
|
|
Packit |
aea12f |
if (session->internals.anti_replay) {
|
|
Packit |
aea12f |
ret = _gnutls_anti_replay_check(session->internals.anti_replay,
|
|
Packit |
aea12f |
ticket_age,
|
|
Packit |
aea12f |
&ticket_creation_time,
|
|
Packit |
aea12f |
&binder_recvd);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
session->internals.hsk_flags &= ~HSK_EARLY_DATA_ACCEPTED;
|
|
Packit |
aea12f |
_gnutls_handshake_log("EXT[%p]: replay detected; rejecting early data\n",
|
|
Packit |
aea12f |
session);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
_gnutls_handshake_log("EXT[%p]: anti-replay is not enabled; rejecting early data\n",
|
|
Packit |
aea12f |
session);
|
|
Packit |
aea12f |
session->internals.hsk_flags &= ~HSK_EARLY_DATA_ACCEPTED;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->internals.resumed = RESUME_TRUE;
|
|
Packit |
aea12f |
_gnutls_handshake_log("EXT[%p]: selected resumption PSK identity (%d)\n", session, psk_index);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->internals.hsk_flags |= HSK_PSK_SELECTED;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Reference the selected pre-shared key */
|
|
Packit |
aea12f |
session->key.binders[0].psk.data = key.data;
|
|
Packit |
aea12f |
session->key.binders[0].psk.size = key.size;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->key.binders[0].idx = psk_index;
|
|
Packit |
aea12f |
session->key.binders[0].prf = prf;
|
|
Packit |
aea12f |
session->key.binders[0].resumption = resuming;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_generate_early_secrets_for_psk(session);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto fail;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
fail:
|
|
Packit |
aea12f |
gnutls_free(key.data);
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/*
|
|
Packit |
aea12f |
* Return values for this function:
|
|
Packit |
aea12f |
* - 0 : Not applicable.
|
|
Packit |
aea12f |
* - >0 : Ok. Return size of extension data.
|
|
Packit |
aea12f |
* - GNUTLS_E_INT_RET_0 : Size of extension data is zero.
|
|
Packit |
aea12f |
* - <0 : There's been an error.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* In the client, generates the PskIdentity and PskBinderEntry messages.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* PskIdentity identities<7..2^16-1>;
|
|
Packit |
aea12f |
* PskBinderEntry binders<33..2^16-1>;
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* struct {
|
|
Packit |
aea12f |
* opaque identity<1..2^16-1>;
|
|
Packit |
aea12f |
* uint32 obfuscated_ticket_age;
|
|
Packit |
aea12f |
* } PskIdentity;
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* opaque PskBinderEntry<32..255>;
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* The server sends the selected identity, which is a zero-based index
|
|
Packit |
aea12f |
* of the PSKs offered by the client:
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* struct {
|
|
Packit |
aea12f |
* uint16 selected_identity;
|
|
Packit |
aea12f |
* } PreSharedKeyExtension;
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int _gnutls_psk_send_params(gnutls_session_t session,
|
|
Packit |
aea12f |
gnutls_buffer_t extdata)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
gnutls_psk_client_credentials_t cred = NULL;
|
|
Packit |
aea12f |
const version_entry_st *vers;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->security_parameters.entity == GNUTLS_CLIENT) {
|
|
Packit |
aea12f |
vers = _gnutls_version_max(session);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (!vers || !vers->tls13_sem)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->internals.hsk_flags & HSK_PSK_KE_MODES_SENT) {
|
|
Packit |
aea12f |
cred = (gnutls_psk_client_credentials_t)
|
|
Packit |
aea12f |
_gnutls_get_cred(session, GNUTLS_CRD_PSK);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((session->internals.flags & GNUTLS_NO_TICKETS) && !session->internals.priorities->have_psk)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return client_send_params(session, extdata, cred);
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
vers = get_version(session);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (!vers || !vers->tls13_sem)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if ((session->internals.flags & GNUTLS_NO_TICKETS) && !session->internals.priorities->have_psk)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->internals.hsk_flags & HSK_PSK_KE_MODES_RECEIVED)
|
|
Packit |
aea12f |
return server_send_params(session, extdata);
|
|
Packit |
aea12f |
else
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static void swap_binders(gnutls_session_t session)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
struct binder_data_st tmp;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
memcpy(&tmp, &session->key.binders[0], sizeof(struct binder_data_st));
|
|
Packit |
aea12f |
memcpy(&session->key.binders[0], &session->key.binders[1], sizeof(struct binder_data_st));
|
|
Packit |
aea12f |
memcpy(&session->key.binders[1], &tmp, sizeof(struct binder_data_st));
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/*
|
|
Packit |
aea12f |
* Return values for this function:
|
|
Packit |
aea12f |
* - 0 : Not applicable.
|
|
Packit |
aea12f |
* - >0 : Ok. Return size of extension data.
|
|
Packit |
aea12f |
* - <0 : There's been an error.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int _gnutls_psk_recv_params(gnutls_session_t session,
|
|
Packit |
aea12f |
const unsigned char *data, size_t len)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
unsigned i;
|
|
Packit |
aea12f |
gnutls_psk_server_credentials_t pskcred;
|
|
Packit |
aea12f |
const version_entry_st *vers = get_version(session);
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (!vers || !vers->tls13_sem)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->security_parameters.entity == GNUTLS_CLIENT) {
|
|
Packit |
aea12f |
if (session->internals.hsk_flags & HSK_PSK_KE_MODES_SENT) {
|
|
Packit |
aea12f |
uint16_t selected_identity = _gnutls_read_uint16(data);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
for (i=0;i<sizeof(session->key.binders)/sizeof(session->key.binders[0]);i++) {
|
|
Packit |
aea12f |
if (session->key.binders[i].prf != NULL && session->key.binders[i].idx == selected_identity) {
|
|
Packit |
aea12f |
if (session->key.binders[i].resumption) {
|
|
Packit |
aea12f |
session->internals.resumed = RESUME_TRUE;
|
|
Packit |
aea12f |
_gnutls_handshake_log("EXT[%p]: selected PSK-resumption mode\n", session);
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
_gnutls_handshake_log("EXT[%p]: selected PSK mode\n", session);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* different PSK is selected, than the one we calculated early secrets */
|
|
Packit |
aea12f |
if (i != 0) {
|
|
Packit |
aea12f |
/* ensure that selected binder is set on (our) index zero */
|
|
Packit |
aea12f |
swap_binders(session);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_generate_early_secrets_for_psk(session);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
session->internals.hsk_flags |= HSK_PSK_SELECTED;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
if (session->internals.hsk_flags & HSK_PSK_KE_MODES_RECEIVED) {
|
|
Packit |
aea12f |
if (session->internals.hsk_flags & HSK_PSK_KE_MODE_INVALID) {
|
|
Packit |
aea12f |
/* We received a "psk_ke_modes" extension, but with a value we don't support */
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
pskcred = (gnutls_psk_server_credentials_t)
|
|
Packit |
aea12f |
_gnutls_get_cred(session, GNUTLS_CRD_PSK);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* If there are no PSK credentials, this extension is not applicable,
|
|
Packit |
aea12f |
* so we return zero. */
|
|
Packit |
aea12f |
if (pskcred == NULL && (session->internals.flags & GNUTLS_NO_TICKETS))
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return server_recv_params(session, data, len, pskcred);
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
const hello_ext_entry_st ext_mod_pre_shared_key = {
|
|
Packit |
aea12f |
.name = "Pre Shared Key",
|
|
Packit |
aea12f |
.tls_id = PRE_SHARED_KEY_TLS_ID,
|
|
Packit |
aea12f |
.gid = GNUTLS_EXTENSION_PRE_SHARED_KEY,
|
|
Packit Service |
991b93 |
.client_parse_point = GNUTLS_EXT_TLS,
|
|
Packit Service |
991b93 |
.server_parse_point = GNUTLS_EXT_TLS,
|
|
Packit |
aea12f |
.validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO,
|
|
Packit |
aea12f |
.send_func = _gnutls_psk_send_params,
|
|
Packit |
aea12f |
.recv_func = _gnutls_psk_recv_params
|
|
Packit |
aea12f |
};
|