|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* Copyright (C) 2017 Red Hat, Inc.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Author: Nikos Mavrogiannopoulos
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This file is part of GnuTLS.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit Service |
4684c1 |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
4684c1 |
* the License, or (at your option) any later version.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This library is distributed in the hope that it will be useful, but
|
|
Packit Service |
4684c1 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
4684c1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
4684c1 |
* Lesser General Public License for more details.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include "gnutls_int.h"
|
|
Packit Service |
4684c1 |
#include "errors.h"
|
|
Packit Service |
4684c1 |
#include "handshake.h"
|
|
Packit Service |
4684c1 |
#include "tls13/finished.h"
|
|
Packit Service |
4684c1 |
#include "mem.h"
|
|
Packit Service |
4684c1 |
#include "mbuffers.h"
|
|
Packit Service |
4684c1 |
#include "secrets.h"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int _gnutls13_compute_finished(const mac_entry_st *prf,
|
|
Packit Service |
4684c1 |
const uint8_t *base_key,
|
|
Packit Service |
4684c1 |
gnutls_buffer_st *handshake_hash_buffer,
|
|
Packit Service |
4684c1 |
void *out)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
uint8_t fkey[MAX_HASH_SIZE];
|
|
Packit Service |
4684c1 |
uint8_t ts_hash[MAX_HASH_SIZE];
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = _tls13_expand_secret2(prf,
|
|
Packit Service |
4684c1 |
"finished", 8,
|
|
Packit Service |
4684c1 |
NULL, 0,
|
|
Packit Service |
4684c1 |
base_key,
|
|
Packit Service |
4684c1 |
prf->output_size, fkey);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_hash_fast(prf->id,
|
|
Packit Service |
4684c1 |
handshake_hash_buffer->data,
|
|
Packit Service |
4684c1 |
handshake_hash_buffer->length,
|
|
Packit Service |
4684c1 |
ts_hash);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_hmac_fast(prf->id,
|
|
Packit Service |
4684c1 |
fkey, prf->output_size,
|
|
Packit Service |
4684c1 |
ts_hash, prf->output_size,
|
|
Packit Service |
4684c1 |
out);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int _gnutls13_recv_finished(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
gnutls_buffer_st buf;
|
|
Packit Service |
4684c1 |
uint8_t verifier[MAX_HASH_SIZE];
|
|
Packit Service |
4684c1 |
const uint8_t *base_key;
|
|
Packit Service |
4684c1 |
unsigned hash_size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (unlikely(session->security_parameters.prf == NULL))
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hash_size = session->security_parameters.prf->output_size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!session->internals.initial_negotiation_completed) {
|
|
Packit Service |
4684c1 |
if (session->security_parameters.entity == GNUTLS_CLIENT)
|
|
Packit Service |
4684c1 |
base_key = session->key.proto.tls13.hs_skey;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
base_key = session->key.proto.tls13.hs_ckey;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
if (session->security_parameters.entity == GNUTLS_CLIENT)
|
|
Packit Service |
4684c1 |
base_key = session->key.proto.tls13.ap_skey;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
base_key = session->key.proto.tls13.ap_ckey;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = _gnutls13_compute_finished(session->security_parameters.prf,
|
|
Packit Service |
4684c1 |
base_key,
|
|
Packit Service |
4684c1 |
&session->internals.handshake_hash_buffer,
|
|
Packit Service |
4684c1 |
verifier);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_FINISHED, 0, &buf;;
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_handshake_log("HSK[%p]: parsing finished\n", session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (buf.length != hash_size) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
|
|
Packit Service |
4684c1 |
# warning This is unsafe for production builds
|
|
Packit Service |
4684c1 |
#else
|
|
Packit Service |
4684c1 |
if (safe_memcmp(verifier, buf.data, buf.length) != 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
ret = GNUTLS_E_ERROR_IN_FINISHED_PACKET;
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = 0;
|
|
Packit Service |
4684c1 |
cleanup:
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_buffer_clear(&buf;;
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int _gnutls13_send_finished(gnutls_session_t session, unsigned again)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
uint8_t verifier[MAX_HASH_SIZE];
|
|
Packit Service |
4684c1 |
mbuffer_st *bufel = NULL;
|
|
Packit Service |
4684c1 |
const uint8_t *base_key;
|
|
Packit Service |
4684c1 |
unsigned hash_size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (again == 0) {
|
|
Packit Service |
4684c1 |
if (unlikely(session->security_parameters.prf == NULL))
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hash_size = session->security_parameters.prf->output_size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!session->internals.initial_negotiation_completed) {
|
|
Packit Service |
4684c1 |
if (session->security_parameters.entity == GNUTLS_CLIENT)
|
|
Packit Service |
4684c1 |
base_key = session->key.proto.tls13.hs_ckey;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
base_key = session->key.proto.tls13.hs_skey;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
if (session->security_parameters.entity == GNUTLS_CLIENT)
|
|
Packit Service |
4684c1 |
base_key = session->key.proto.tls13.ap_ckey;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
base_key = session->key.proto.tls13.ap_skey;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = _gnutls13_compute_finished(session->security_parameters.prf,
|
|
Packit Service |
4684c1 |
base_key,
|
|
Packit Service |
4684c1 |
&session->internals.handshake_hash_buffer,
|
|
Packit Service |
4684c1 |
verifier);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_handshake_log("HSK[%p]: sending finished\n", session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
bufel = _gnutls_handshake_alloc(session, hash_size);
|
|
Packit Service |
4684c1 |
if (bufel == NULL)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_mbuffer_set_udata_size(bufel, 0);
|
|
Packit Service |
4684c1 |
ret = _mbuffer_append_data(bufel, verifier, hash_size);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_FINISHED);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cleanup:
|
|
Packit Service |
4684c1 |
_mbuffer_xfree(&bufel);
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|