2020-04-25 22:14:27 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2020, Ali Mohammad Pur <ali.mpfard@gmail.com>
|
|
|
|
*
|
2021-04-22 11:24:48 +03:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-04-25 22:14:27 +03:00
|
|
|
*/
|
|
|
|
|
2021-01-17 18:06:30 +03:00
|
|
|
#include <AK/Debug.h>
|
2020-08-25 16:11:15 +03:00
|
|
|
#include <AK/Endian.h>
|
2020-11-13 01:29:36 +03:00
|
|
|
#include <AK/MemoryStream.h>
|
2020-04-25 22:14:27 +03:00
|
|
|
#include <LibCore/Timer.h>
|
|
|
|
#include <LibCrypto/PK/Code/EMSA_PSS.h>
|
|
|
|
#include <LibTLS/TLSv12.h>
|
|
|
|
|
|
|
|
namespace TLS {
|
|
|
|
|
|
|
|
void TLSv12::write_packet(ByteBuffer& packet)
|
|
|
|
{
|
|
|
|
m_context.tls_buffer.append(packet.data(), packet.size());
|
2020-05-19 21:05:19 +03:00
|
|
|
if (m_context.connection_status > ConnectionStatus::Disconnected) {
|
|
|
|
if (!m_has_scheduled_write_flush) {
|
2021-02-07 15:03:24 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "Scheduling write of {}", m_context.tls_buffer.size());
|
2020-05-19 21:05:19 +03:00
|
|
|
deferred_invoke([this](auto&) { write_into_socket(); });
|
|
|
|
m_has_scheduled_write_flush = true;
|
|
|
|
} else {
|
|
|
|
// multiple packet are available, let's flush some out
|
2021-02-07 15:03:24 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "Flushing scheduled write of {}", m_context.tls_buffer.size());
|
2020-05-19 21:05:19 +03:00
|
|
|
write_into_socket();
|
|
|
|
// the deferred invoke is still in place
|
|
|
|
m_has_scheduled_write_flush = true;
|
|
|
|
}
|
2020-05-19 17:33:57 +03:00
|
|
|
}
|
2020-04-25 22:14:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void TLSv12::update_packet(ByteBuffer& packet)
|
|
|
|
{
|
|
|
|
u32 header_size = 5;
|
2020-08-25 16:11:15 +03:00
|
|
|
*(u16*)packet.offset_pointer(3) = AK::convert_between_host_and_network_endian((u16)(packet.size() - header_size));
|
2020-04-25 22:14:27 +03:00
|
|
|
|
|
|
|
if (packet[0] != (u8)MessageType::ChangeCipher) {
|
|
|
|
if (packet[0] == (u8)MessageType::Handshake && packet.size() > header_size) {
|
|
|
|
u8 handshake_type = packet[header_size];
|
|
|
|
if (handshake_type != HandshakeType::HelloRequest && handshake_type != HandshakeType::HelloVerifyRequest) {
|
2021-02-07 06:51:32 +03:00
|
|
|
update_hash(packet.bytes(), header_size);
|
2020-04-25 22:14:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m_context.cipher_spec_set && m_context.crypto.created) {
|
2020-11-13 01:29:36 +03:00
|
|
|
size_t length = packet.size() - header_size;
|
|
|
|
size_t block_size, padding, mac_size;
|
|
|
|
|
|
|
|
if (!is_aead()) {
|
|
|
|
block_size = m_aes_local.cbc->cipher().block_size();
|
|
|
|
// If the length is already a multiple a block_size,
|
|
|
|
// an entire block of padding is added.
|
|
|
|
// In short, we _never_ have no padding.
|
|
|
|
mac_size = mac_length();
|
|
|
|
length += mac_size;
|
2020-11-16 13:41:57 +03:00
|
|
|
padding = block_size - length % block_size;
|
|
|
|
length += padding;
|
2020-11-13 01:29:36 +03:00
|
|
|
} else {
|
|
|
|
block_size = m_aes_local.gcm->cipher().block_size();
|
|
|
|
padding = 0;
|
|
|
|
mac_size = 0; // AEAD provides its own authentication scheme.
|
|
|
|
}
|
2020-04-25 22:14:27 +03:00
|
|
|
|
|
|
|
if (m_context.crypto.created == 1) {
|
|
|
|
// `buffer' will continue to be encrypted
|
2020-08-11 22:00:06 +03:00
|
|
|
auto buffer = ByteBuffer::create_uninitialized(length);
|
2020-04-25 22:14:27 +03:00
|
|
|
size_t buffer_position = 0;
|
|
|
|
auto iv_size = iv_length();
|
|
|
|
|
|
|
|
// copy the packet, sans the header
|
|
|
|
buffer.overwrite(buffer_position, packet.offset_pointer(header_size), packet.size() - header_size);
|
|
|
|
buffer_position += packet.size() - header_size;
|
|
|
|
|
2020-11-13 01:29:36 +03:00
|
|
|
ByteBuffer ct;
|
|
|
|
|
|
|
|
if (is_aead()) {
|
|
|
|
// We need enough space for a header, the data, a tag, and the IV
|
|
|
|
ct = ByteBuffer::create_uninitialized(length + header_size + iv_size + 16);
|
|
|
|
|
|
|
|
// copy the header over
|
|
|
|
ct.overwrite(0, packet.data(), header_size - 2);
|
|
|
|
|
|
|
|
// AEAD AAD (13)
|
|
|
|
// Seq. no (8)
|
|
|
|
// content type (1)
|
|
|
|
// version (2)
|
|
|
|
// length (2)
|
|
|
|
u8 aad[13];
|
|
|
|
Bytes aad_bytes { aad, 13 };
|
|
|
|
OutputMemoryStream aad_stream { aad_bytes };
|
|
|
|
|
|
|
|
u64 seq_no = AK::convert_between_host_and_network_endian(m_context.local_sequence_number);
|
|
|
|
u16 len = AK::convert_between_host_and_network_endian((u16)(packet.size() - header_size));
|
|
|
|
|
|
|
|
aad_stream.write({ &seq_no, sizeof(seq_no) });
|
|
|
|
aad_stream.write(packet.bytes().slice(0, 3)); // content-type + version
|
|
|
|
aad_stream.write({ &len, sizeof(len) }); // length
|
2021-02-23 22:42:32 +03:00
|
|
|
VERIFY(aad_stream.is_end());
|
2020-11-13 01:29:36 +03:00
|
|
|
|
|
|
|
// AEAD IV (12)
|
|
|
|
// IV (4)
|
|
|
|
// (Nonce) (8)
|
|
|
|
// -- Our GCM impl takes 16 bytes
|
|
|
|
// zero (4)
|
|
|
|
u8 iv[16];
|
|
|
|
Bytes iv_bytes { iv, 16 };
|
|
|
|
Bytes { m_context.crypto.local_aead_iv, 4 }.copy_to(iv_bytes);
|
2021-02-25 23:10:47 +03:00
|
|
|
fill_with_random(iv_bytes.offset(4), 8);
|
2020-11-13 01:29:36 +03:00
|
|
|
memset(iv_bytes.offset(12), 0, 4);
|
|
|
|
|
|
|
|
// write the random part of the iv out
|
|
|
|
iv_bytes.slice(4, 8).copy_to(ct.bytes().slice(header_size));
|
|
|
|
|
|
|
|
// Write the encrypted data and the tag
|
|
|
|
m_aes_local.gcm->encrypt(
|
|
|
|
packet.bytes().slice(header_size, length),
|
|
|
|
ct.bytes().slice(header_size + 8, length),
|
|
|
|
iv_bytes,
|
|
|
|
aad_bytes,
|
|
|
|
ct.bytes().slice(header_size + 8 + length, 16));
|
|
|
|
|
2021-02-23 22:42:32 +03:00
|
|
|
VERIFY(header_size + 8 + length + 16 == ct.size());
|
2020-11-13 01:29:36 +03:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// We need enough space for a header, iv_length bytes of IV and whatever the packet contains
|
|
|
|
ct = ByteBuffer::create_uninitialized(length + header_size + iv_size);
|
|
|
|
|
|
|
|
// copy the header over
|
|
|
|
ct.overwrite(0, packet.data(), header_size - 2);
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2020-11-13 01:29:36 +03:00
|
|
|
// get the appropricate HMAC value for the entire packet
|
|
|
|
auto mac = hmac_message(packet, {}, mac_size, true);
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2020-11-13 01:29:36 +03:00
|
|
|
// write the MAC
|
|
|
|
buffer.overwrite(buffer_position, mac.data(), mac.size());
|
|
|
|
buffer_position += mac.size();
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2020-11-13 01:29:36 +03:00
|
|
|
// Apply the padding (a packet MUST always be padded)
|
|
|
|
memset(buffer.offset_pointer(buffer_position), padding - 1, padding);
|
|
|
|
buffer_position += padding;
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2021-02-23 22:42:32 +03:00
|
|
|
VERIFY(buffer_position == buffer.size());
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2020-11-13 01:29:36 +03:00
|
|
|
auto iv = ByteBuffer::create_uninitialized(iv_size);
|
2021-02-25 23:10:47 +03:00
|
|
|
fill_with_random(iv.data(), iv.size());
|
2020-06-04 15:22:56 +03:00
|
|
|
|
2020-11-13 01:29:36 +03:00
|
|
|
// write it into the ciphertext portion of the message
|
|
|
|
ct.overwrite(header_size, iv.data(), iv.size());
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2021-02-23 22:42:32 +03:00
|
|
|
VERIFY(header_size + iv_size + length == ct.size());
|
|
|
|
VERIFY(length % block_size == 0);
|
2020-11-13 01:29:36 +03:00
|
|
|
|
|
|
|
// get a block to encrypt into
|
|
|
|
auto view = ct.bytes().slice(header_size + iv_size, length);
|
|
|
|
m_aes_local.cbc->encrypt(buffer, view, iv);
|
|
|
|
}
|
2020-04-25 22:14:27 +03:00
|
|
|
|
|
|
|
// store the correct ciphertext length into the packet
|
|
|
|
u16 ct_length = (u16)ct.size() - header_size;
|
2020-06-04 15:22:56 +03:00
|
|
|
|
2020-08-25 16:11:15 +03:00
|
|
|
*(u16*)ct.offset_pointer(header_size - 2) = AK::convert_between_host_and_network_endian(ct_length);
|
2020-04-25 22:14:27 +03:00
|
|
|
|
|
|
|
// replace the packet with the ciphertext
|
|
|
|
packet = ct;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++m_context.local_sequence_number;
|
|
|
|
}
|
|
|
|
|
2021-02-07 06:51:32 +03:00
|
|
|
void TLSv12::update_hash(ReadonlyBytes message, size_t header_size)
|
2020-04-25 22:14:27 +03:00
|
|
|
{
|
2021-04-07 19:51:12 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "Update hash with message of size {}", message.size());
|
2021-02-07 06:51:32 +03:00
|
|
|
m_context.handshake_hash.update(message.slice(header_size));
|
2020-04-25 22:14:27 +03:00
|
|
|
}
|
|
|
|
|
2020-08-11 22:00:49 +03:00
|
|
|
ByteBuffer TLSv12::hmac_message(const ReadonlyBytes& buf, const Optional<ReadonlyBytes> buf2, size_t mac_length, bool local)
|
2020-04-25 22:14:27 +03:00
|
|
|
{
|
2020-08-25 16:11:15 +03:00
|
|
|
u64 sequence_number = AK::convert_between_host_and_network_endian(local ? m_context.local_sequence_number : m_context.remote_sequence_number);
|
2020-04-25 22:14:27 +03:00
|
|
|
ensure_hmac(mac_length, local);
|
|
|
|
auto& hmac = local ? *m_hmac_local : *m_hmac_remote;
|
2021-04-07 19:51:12 +03:00
|
|
|
if constexpr (TLS_DEBUG) {
|
|
|
|
dbgln("========================= PACKET DATA ==========================");
|
|
|
|
print_buffer((const u8*)&sequence_number, sizeof(u64));
|
|
|
|
print_buffer(buf.data(), buf.size());
|
|
|
|
if (buf2.has_value())
|
|
|
|
print_buffer(buf2.value().data(), buf2.value().size());
|
|
|
|
dbgln("========================= PACKET DATA ==========================");
|
|
|
|
}
|
2020-04-25 22:14:27 +03:00
|
|
|
hmac.update((const u8*)&sequence_number, sizeof(u64));
|
|
|
|
hmac.update(buf);
|
|
|
|
if (buf2.has_value() && buf2.value().size()) {
|
|
|
|
hmac.update(buf2.value());
|
|
|
|
}
|
|
|
|
auto digest = hmac.digest();
|
|
|
|
auto mac = ByteBuffer::copy(digest.immutable_data(), digest.data_length());
|
2021-01-17 18:06:30 +03:00
|
|
|
|
2021-01-24 01:59:27 +03:00
|
|
|
if constexpr (TLS_DEBUG) {
|
2021-01-17 18:06:30 +03:00
|
|
|
dbgln("HMAC of the block for sequence number {}", sequence_number);
|
|
|
|
print_buffer(mac);
|
|
|
|
}
|
|
|
|
|
2020-04-25 22:14:27 +03:00
|
|
|
return mac;
|
|
|
|
}
|
|
|
|
|
2020-12-19 17:07:09 +03:00
|
|
|
ssize_t TLSv12::handle_message(ReadonlyBytes buffer)
|
2020-04-25 22:14:27 +03:00
|
|
|
{
|
|
|
|
auto res { 5ll };
|
|
|
|
size_t header_size = res;
|
|
|
|
ssize_t payload_res = 0;
|
|
|
|
|
2021-02-07 15:03:24 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "buffer size: {}", buffer.size());
|
2021-01-17 18:06:30 +03:00
|
|
|
|
2020-04-25 22:14:27 +03:00
|
|
|
if (buffer.size() < 5) {
|
|
|
|
return (i8)Error::NeedMoreData;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto type = (MessageType)buffer[0];
|
|
|
|
size_t buffer_position { 1 };
|
|
|
|
|
|
|
|
// FIXME: Read the version and verify it
|
2021-01-17 18:06:30 +03:00
|
|
|
|
2021-01-24 01:59:27 +03:00
|
|
|
if constexpr (TLS_DEBUG) {
|
2021-01-17 18:06:30 +03:00
|
|
|
auto version = (Version) * (const u16*)buffer.offset_pointer(buffer_position);
|
|
|
|
dbgln("type={}, version={}", (u8)type, (u16)version);
|
|
|
|
}
|
|
|
|
|
2020-04-25 22:14:27 +03:00
|
|
|
buffer_position += 2;
|
|
|
|
|
2020-08-25 16:11:15 +03:00
|
|
|
auto length = AK::convert_between_host_and_network_endian(*(const u16*)buffer.offset_pointer(buffer_position));
|
2021-02-07 15:03:24 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "record length: {} at offset: {}", length, buffer_position);
|
2020-04-25 22:14:27 +03:00
|
|
|
buffer_position += 2;
|
|
|
|
|
|
|
|
if (buffer_position + length > buffer.size()) {
|
2021-02-07 15:03:24 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "record length more than what we have: {}", buffer.size());
|
2020-04-25 22:14:27 +03:00
|
|
|
return (i8)Error::NeedMoreData;
|
|
|
|
}
|
|
|
|
|
2021-02-07 15:03:24 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "message type: {}, length: {}", (u8)type, length);
|
2020-12-19 17:07:09 +03:00
|
|
|
auto plain = buffer.slice(buffer_position, buffer.size() - buffer_position);
|
|
|
|
|
|
|
|
ByteBuffer decrypted;
|
2020-04-25 22:14:27 +03:00
|
|
|
|
|
|
|
if (m_context.cipher_spec_set && type != MessageType::ChangeCipher) {
|
2021-01-24 01:59:27 +03:00
|
|
|
if constexpr (TLS_DEBUG) {
|
2021-01-17 18:06:30 +03:00
|
|
|
dbgln("Encrypted: ");
|
|
|
|
print_buffer(buffer.slice(header_size, length));
|
|
|
|
}
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2020-11-13 01:29:36 +03:00
|
|
|
if (is_aead()) {
|
2021-02-23 22:42:32 +03:00
|
|
|
VERIFY(m_aes_remote.gcm);
|
2020-11-13 01:29:36 +03:00
|
|
|
|
|
|
|
if (length < 24) {
|
2021-01-09 20:51:44 +03:00
|
|
|
dbgln("Invalid packet length");
|
2020-11-13 01:29:36 +03:00
|
|
|
auto packet = build_alert(true, (u8)AlertDescription::DecryptError);
|
|
|
|
write_packet(packet);
|
|
|
|
return (i8)Error::BrokenPacket;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto packet_length = length - iv_length() - 16;
|
2020-12-19 17:07:09 +03:00
|
|
|
auto payload = plain;
|
|
|
|
decrypted = ByteBuffer::create_uninitialized(packet_length);
|
2020-11-13 01:29:36 +03:00
|
|
|
|
|
|
|
// AEAD AAD (13)
|
|
|
|
// Seq. no (8)
|
|
|
|
// content type (1)
|
|
|
|
// version (2)
|
|
|
|
// length (2)
|
|
|
|
u8 aad[13];
|
|
|
|
Bytes aad_bytes { aad, 13 };
|
|
|
|
OutputMemoryStream aad_stream { aad_bytes };
|
|
|
|
|
|
|
|
u64 seq_no = AK::convert_between_host_and_network_endian(m_context.remote_sequence_number);
|
|
|
|
u16 len = AK::convert_between_host_and_network_endian((u16)packet_length);
|
|
|
|
|
2020-12-19 17:07:09 +03:00
|
|
|
aad_stream.write({ &seq_no, sizeof(seq_no) }); // Sequence number
|
|
|
|
aad_stream.write(buffer.slice(0, header_size - 2)); // content-type + version
|
2020-11-13 01:29:36 +03:00
|
|
|
aad_stream.write({ &len, sizeof(u16) });
|
2021-02-23 22:42:32 +03:00
|
|
|
VERIFY(aad_stream.is_end());
|
2020-11-13 01:29:36 +03:00
|
|
|
|
|
|
|
auto nonce = payload.slice(0, iv_length());
|
|
|
|
payload = payload.slice(iv_length());
|
|
|
|
|
|
|
|
// AEAD IV (12)
|
|
|
|
// IV (4)
|
|
|
|
// (Nonce) (8)
|
|
|
|
// -- Our GCM impl takes 16 bytes
|
|
|
|
// zero (4)
|
|
|
|
u8 iv[16];
|
|
|
|
Bytes iv_bytes { iv, 16 };
|
|
|
|
Bytes { m_context.crypto.remote_aead_iv, 4 }.copy_to(iv_bytes);
|
|
|
|
nonce.copy_to(iv_bytes.slice(4));
|
|
|
|
memset(iv_bytes.offset(12), 0, 4);
|
|
|
|
|
|
|
|
auto ciphertext = payload.slice(0, payload.size() - 16);
|
|
|
|
auto tag = payload.slice(ciphertext.size());
|
|
|
|
|
|
|
|
auto consistency = m_aes_remote.gcm->decrypt(
|
|
|
|
ciphertext,
|
|
|
|
decrypted,
|
|
|
|
iv_bytes,
|
|
|
|
aad_bytes,
|
|
|
|
tag);
|
|
|
|
|
|
|
|
if (consistency != Crypto::VerificationConsistency::Consistent) {
|
2021-01-11 23:13:30 +03:00
|
|
|
dbgln("integrity check failed (tag length {})", tag.size());
|
2020-11-13 01:29:36 +03:00
|
|
|
auto packet = build_alert(true, (u8)AlertDescription::BadRecordMAC);
|
|
|
|
write_packet(packet);
|
|
|
|
|
|
|
|
return (i8)Error::IntegrityCheckFailed;
|
|
|
|
}
|
|
|
|
|
|
|
|
plain = decrypted;
|
|
|
|
} else {
|
2021-02-23 22:42:32 +03:00
|
|
|
VERIFY(m_aes_remote.cbc);
|
2020-11-13 01:29:36 +03:00
|
|
|
auto iv_size = iv_length();
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2020-12-26 18:06:27 +03:00
|
|
|
decrypted = m_aes_remote.cbc->create_aligned_buffer(length - iv_size);
|
2020-12-19 17:07:09 +03:00
|
|
|
auto iv = buffer.slice(header_size, iv_size);
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2020-11-13 01:29:36 +03:00
|
|
|
Bytes decrypted_span = decrypted;
|
2020-12-19 17:07:09 +03:00
|
|
|
m_aes_remote.cbc->decrypt(buffer.slice(header_size + iv_size, length - iv_size), decrypted_span, iv);
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2020-11-13 01:29:36 +03:00
|
|
|
length = decrypted_span.size();
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2021-04-07 19:51:12 +03:00
|
|
|
if constexpr (TLS_DEBUG) {
|
|
|
|
dbgln("Decrypted: ");
|
|
|
|
print_buffer(decrypted);
|
|
|
|
}
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2020-11-13 01:29:36 +03:00
|
|
|
auto mac_size = mac_length();
|
|
|
|
if (length < mac_size) {
|
2021-01-09 20:51:44 +03:00
|
|
|
dbgln("broken packet");
|
2020-11-13 01:29:36 +03:00
|
|
|
auto packet = build_alert(true, (u8)AlertDescription::DecryptError);
|
|
|
|
write_packet(packet);
|
|
|
|
return (i8)Error::BrokenPacket;
|
|
|
|
}
|
2020-04-25 22:14:27 +03:00
|
|
|
|
2020-11-13 01:29:36 +03:00
|
|
|
length -= mac_size;
|
|
|
|
|
|
|
|
const u8* message_hmac = decrypted_span.offset(length);
|
|
|
|
u8 temp_buf[5];
|
|
|
|
memcpy(temp_buf, buffer.offset_pointer(0), 3);
|
|
|
|
*(u16*)(temp_buf + 3) = AK::convert_between_host_and_network_endian(length);
|
|
|
|
auto hmac = hmac_message({ temp_buf, 5 }, decrypted_span.slice(0, length), mac_size);
|
2020-12-19 18:23:52 +03:00
|
|
|
auto message_mac = ReadonlyBytes { message_hmac, mac_size };
|
2020-11-13 01:29:36 +03:00
|
|
|
if (hmac != message_mac) {
|
2021-01-11 23:13:30 +03:00
|
|
|
dbgln("integrity check failed (mac length {})", mac_size);
|
2021-01-09 20:51:44 +03:00
|
|
|
dbgln("mac received:");
|
2020-11-13 01:29:36 +03:00
|
|
|
print_buffer(message_mac);
|
2021-01-09 20:51:44 +03:00
|
|
|
dbgln("mac computed:");
|
2020-11-13 01:29:36 +03:00
|
|
|
print_buffer(hmac);
|
|
|
|
auto packet = build_alert(true, (u8)AlertDescription::BadRecordMAC);
|
|
|
|
write_packet(packet);
|
|
|
|
|
|
|
|
return (i8)Error::IntegrityCheckFailed;
|
|
|
|
}
|
2020-12-26 18:06:27 +03:00
|
|
|
plain = decrypted.bytes().slice(0, length);
|
2020-04-25 22:14:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
m_context.remote_sequence_number++;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case MessageType::ApplicationData:
|
|
|
|
if (m_context.connection_status != ConnectionStatus::Established) {
|
2021-01-09 20:51:44 +03:00
|
|
|
dbgln("unexpected application data");
|
2020-04-25 22:14:27 +03:00
|
|
|
payload_res = (i8)Error::UnexpectedMessage;
|
|
|
|
auto packet = build_alert(true, (u8)AlertDescription::UnexpectedMessage);
|
|
|
|
write_packet(packet);
|
|
|
|
} else {
|
2021-02-07 15:03:24 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "application data message of size {}", plain.size());
|
2020-04-25 22:14:27 +03:00
|
|
|
|
|
|
|
m_context.application_buffer.append(plain.data(), plain.size());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MessageType::Handshake:
|
2021-04-07 19:51:12 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "tls handshake message");
|
2020-04-25 22:14:27 +03:00
|
|
|
payload_res = handle_payload(plain);
|
|
|
|
break;
|
|
|
|
case MessageType::ChangeCipher:
|
|
|
|
if (m_context.connection_status != ConnectionStatus::KeyExchange) {
|
2021-01-09 20:51:44 +03:00
|
|
|
dbgln("unexpected change cipher message");
|
2020-04-25 22:14:27 +03:00
|
|
|
auto packet = build_alert(true, (u8)AlertDescription::UnexpectedMessage);
|
|
|
|
payload_res = (i8)Error::UnexpectedMessage;
|
|
|
|
} else {
|
2021-04-07 19:51:12 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "change cipher spec message");
|
2020-04-25 22:14:27 +03:00
|
|
|
m_context.cipher_spec_set = true;
|
|
|
|
m_context.remote_sequence_number = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MessageType::Alert:
|
2021-02-07 15:03:24 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "alert message of length {}", length);
|
2020-04-25 22:14:27 +03:00
|
|
|
if (length >= 2) {
|
2021-01-24 01:59:27 +03:00
|
|
|
if constexpr (TLS_DEBUG)
|
2021-01-17 18:06:30 +03:00
|
|
|
print_buffer(plain);
|
|
|
|
|
2020-04-25 22:14:27 +03:00
|
|
|
auto level = plain[0];
|
|
|
|
auto code = plain[1];
|
2021-04-10 17:21:09 +03:00
|
|
|
dbgln_if(TLS_DEBUG, "Alert received with level {}, code {}", level, code);
|
|
|
|
|
2020-04-25 22:14:27 +03:00
|
|
|
if (level == (u8)AlertLevel::Critical) {
|
2021-01-11 23:13:30 +03:00
|
|
|
dbgln("We were alerted of a critical error: {} ({})", code, alert_name((AlertDescription)code));
|
2020-04-25 22:14:27 +03:00
|
|
|
m_context.critical_error = code;
|
2020-05-05 11:54:00 +03:00
|
|
|
try_disambiguate_error();
|
2020-04-25 22:14:27 +03:00
|
|
|
res = (i8)Error::UnknownError;
|
|
|
|
}
|
2021-04-10 17:21:09 +03:00
|
|
|
|
|
|
|
if (code == (u8)AlertDescription::CloseNotify) {
|
2020-04-25 22:14:27 +03:00
|
|
|
res += 2;
|
2020-05-30 18:23:07 +03:00
|
|
|
alert(AlertLevel::Critical, AlertDescription::CloseNotify);
|
2020-04-25 22:14:27 +03:00
|
|
|
m_context.connection_finished = true;
|
2020-10-26 00:09:10 +03:00
|
|
|
if (!m_context.cipher_spec_set) {
|
|
|
|
// AWS CloudFront hits this.
|
2021-01-09 20:51:44 +03:00
|
|
|
dbgln("Server sent a close notify and we haven't agreed on a cipher suite. Treating it as a handshake failure.");
|
2020-10-26 00:09:10 +03:00
|
|
|
m_context.critical_error = (u8)AlertDescription::HandshakeFailure;
|
|
|
|
try_disambiguate_error();
|
|
|
|
}
|
2020-04-25 22:14:27 +03:00
|
|
|
}
|
|
|
|
m_context.error_code = (Error)code;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2021-01-09 20:51:44 +03:00
|
|
|
dbgln("message not understood");
|
2020-04-25 22:14:27 +03:00
|
|
|
return (i8)Error::NotUnderstood;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (payload_res < 0)
|
|
|
|
return payload_res;
|
|
|
|
|
|
|
|
if (res > 0)
|
|
|
|
return header_size + length;
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|