1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:17:45 +00:00

LibTLS: Replace cipher selection with a variant

This commit is contained in:
DexesTTP 2021-05-18 22:58:13 +02:00 committed by Andreas Kling
parent 851e254e8f
commit 2e9a4bb95c
3 changed files with 200 additions and 176 deletions

View file

@ -75,14 +75,14 @@ bool TLSv12::expand_key()
memcpy(m_context.crypto.local_aead_iv, client_iv, iv_size);
memcpy(m_context.crypto.remote_aead_iv, server_iv, iv_size);
m_aes_local.gcm = make<Crypto::Cipher::AESCipher::GCMMode>(ReadonlyBytes { client_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Encryption, Crypto::Cipher::PaddingMode::RFC5246);
m_aes_remote.gcm = make<Crypto::Cipher::AESCipher::GCMMode>(ReadonlyBytes { server_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Decryption, Crypto::Cipher::PaddingMode::RFC5246);
m_cipher_local = Crypto::Cipher::AESCipher::GCMMode(ReadonlyBytes { client_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Encryption, Crypto::Cipher::PaddingMode::RFC5246);
m_cipher_remote = Crypto::Cipher::AESCipher::GCMMode(ReadonlyBytes { server_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Decryption, Crypto::Cipher::PaddingMode::RFC5246);
} else {
memcpy(m_context.crypto.local_iv, client_iv, iv_size);
memcpy(m_context.crypto.remote_iv, server_iv, iv_size);
m_aes_local.cbc = make<Crypto::Cipher::AESCipher::CBCMode>(ReadonlyBytes { client_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Encryption, Crypto::Cipher::PaddingMode::RFC5246);
m_aes_remote.cbc = make<Crypto::Cipher::AESCipher::CBCMode>(ReadonlyBytes { server_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Decryption, Crypto::Cipher::PaddingMode::RFC5246);
m_cipher_local = Crypto::Cipher::AESCipher::CBCMode(ReadonlyBytes { client_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Encryption, Crypto::Cipher::PaddingMode::RFC5246);
m_cipher_remote = Crypto::Cipher::AESCipher::CBCMode(ReadonlyBytes { server_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Decryption, Crypto::Cipher::PaddingMode::RFC5246);
}
m_context.crypto.created = 1;

View file

@ -67,10 +67,21 @@ void TLSv12::update_packet(ByteBuffer& packet)
}
if (m_context.cipher_spec_set && m_context.crypto.created) {
size_t length = packet.size() - header_size;
size_t block_size, padding, mac_size;
size_t block_size = 0;
size_t padding = 0;
size_t mac_size = 0;
if (!is_aead()) {
block_size = m_aes_local.cbc->cipher().block_size();
m_cipher_local.visit(
[&](Empty&) { VERIFY_NOT_REACHED(); },
[&](Crypto::Cipher::AESCipher::GCMMode& gcm) {
VERIFY(is_aead());
block_size = gcm.cipher().block_size();
padding = 0;
mac_size = 0; // AEAD provides its own authentication scheme.
},
[&](Crypto::Cipher::AESCipher::CBCMode& cbc) {
VERIFY(!is_aead());
block_size = 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.
@ -78,11 +89,7 @@ void TLSv12::update_packet(ByteBuffer& packet)
length += mac_size;
padding = block_size - length % block_size;
length += padding;
} else {
block_size = m_aes_local.gcm->cipher().block_size();
padding = 0;
mac_size = 0; // AEAD provides its own authentication scheme.
}
});
if (m_context.crypto.created == 1) {
// `buffer' will continue to be encrypted
@ -96,7 +103,10 @@ void TLSv12::update_packet(ByteBuffer& packet)
ByteBuffer ct;
if (is_aead()) {
m_cipher_local.visit(
[&](Empty&) { VERIFY_NOT_REACHED(); },
[&](Crypto::Cipher::AESCipher::GCMMode& gcm) {
VERIFY(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);
@ -135,7 +145,7 @@ void TLSv12::update_packet(ByteBuffer& packet)
iv_bytes.slice(4, 8).copy_to(ct.bytes().slice(header_size));
// Write the encrypted data and the tag
m_aes_local.gcm->encrypt(
gcm.encrypt(
packet.bytes().slice(header_size, length),
ct.bytes().slice(header_size + 8, length),
iv_bytes,
@ -143,8 +153,9 @@ void TLSv12::update_packet(ByteBuffer& packet)
ct.bytes().slice(header_size + 8 + length, 16));
VERIFY(header_size + 8 + length + 16 == ct.size());
} else {
},
[&](Crypto::Cipher::AESCipher::CBCMode& cbc) {
VERIFY(!is_aead());
// 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);
@ -175,8 +186,8 @@ void TLSv12::update_packet(ByteBuffer& packet)
// get a block to encrypt into
auto view = ct.bytes().slice(header_size + iv_size, length);
m_aes_local.cbc->encrypt(buffer, view, iv);
}
cbc.encrypt(buffer, view, iv);
});
// store the correct ciphertext length into the packet
u16 ct_length = (u16)ct.size() - header_size;
@ -303,14 +314,17 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer)
print_buffer(buffer.slice(header_size, length));
}
if (is_aead()) {
VERIFY(m_aes_remote.gcm);
Error return_value = Error::NoError;
m_cipher_remote.visit(
[&](Empty&) { VERIFY_NOT_REACHED(); },
[&](Crypto::Cipher::AESCipher::GCMMode& gcm) {
VERIFY(is_aead());
if (length < 24) {
dbgln("Invalid packet length");
auto packet = build_alert(true, (u8)AlertDescription::DecryptError);
write_packet(packet);
return (i8)Error::BrokenPacket;
return_value = Error::BrokenPacket;
return;
}
auto packet_length = length - iv_length() - 16;
@ -351,7 +365,7 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer)
auto ciphertext = payload.slice(0, payload.size() - 16);
auto tag = payload.slice(ciphertext.size());
auto consistency = m_aes_remote.gcm->decrypt(
auto consistency = gcm.decrypt(
ciphertext,
decrypted,
iv_bytes,
@ -363,19 +377,21 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer)
auto packet = build_alert(true, (u8)AlertDescription::BadRecordMAC);
write_packet(packet);
return (i8)Error::IntegrityCheckFailed;
return_value = Error::IntegrityCheckFailed;
return;
}
plain = decrypted;
} else {
VERIFY(m_aes_remote.cbc);
},
[&](Crypto::Cipher::AESCipher::CBCMode& cbc) {
VERIFY(!is_aead());
auto iv_size = iv_length();
decrypted = m_aes_remote.cbc->create_aligned_buffer(length - iv_size);
decrypted = cbc.create_aligned_buffer(length - iv_size);
auto iv = buffer.slice(header_size, iv_size);
Bytes decrypted_span = decrypted;
m_aes_remote.cbc->decrypt(buffer.slice(header_size + iv_size, length - iv_size), decrypted_span, iv);
cbc.decrypt(buffer.slice(header_size + iv_size, length - iv_size), decrypted_span, iv);
length = decrypted_span.size();
@ -389,7 +405,8 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer)
dbgln("broken packet");
auto packet = build_alert(true, (u8)AlertDescription::DecryptError);
write_packet(packet);
return (i8)Error::BrokenPacket;
return_value = Error::BrokenPacket;
return;
}
length -= mac_size;
@ -409,9 +426,14 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer)
auto packet = build_alert(true, (u8)AlertDescription::BadRecordMAC);
write_packet(packet);
return (i8)Error::IntegrityCheckFailed;
return_value = Error::IntegrityCheckFailed;
return;
}
plain = decrypted.bytes().slice(0, length);
});
if (return_value != Error::NoError) {
return (i8)return_value;
}
}
m_context.remote_sequence_number++;

View file

@ -463,10 +463,12 @@ private:
OwnPtr<Crypto::Authentication::HMAC<Crypto::Hash::Manager>> m_hmac_local;
OwnPtr<Crypto::Authentication::HMAC<Crypto::Hash::Manager>> m_hmac_remote;
struct {
OwnPtr<Crypto::Cipher::AESCipher::CBCMode> cbc;
OwnPtr<Crypto::Cipher::AESCipher::GCMMode> gcm;
} m_aes_local, m_aes_remote;
using CipherVariant = Variant<
Empty,
Crypto::Cipher::AESCipher::CBCMode,
Crypto::Cipher::AESCipher::GCMMode>;
CipherVariant m_cipher_local { Empty {} };
CipherVariant m_cipher_remote { Empty {} };
bool m_has_scheduled_write_flush { false };
i32 m_max_wait_time_for_handshake_in_seconds { 10 };