mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:47:34 +00:00
LibTLS: Implement the DHE_RSA key exchange algorithm
This adds two methods, handle_dhe_rsa_server_key_exchange and build_dhe_rsa_pre_master_secret, to TLSv12 and a struct, server_diffie_hellman_params, to Context, which are used to implement the DHE_RSA key exchange algorithm. This grants us the benefits of forward secrecy and access to sites which support DHE_RSA. It is worth noting that the signature of the server provided Diffie-Hellman parameters is not currently validated. This will need to be addressed to prevent man-in-the-middle attacks.
This commit is contained in:
parent
020bfc9d93
commit
b288016bbc
3 changed files with 75 additions and 5 deletions
|
@ -7,6 +7,8 @@
|
|||
#include <AK/Debug.h>
|
||||
#include <AK/Random.h>
|
||||
#include <LibCrypto/ASN1/DER.h>
|
||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||
#include <LibCrypto/NumberTheory/ModularFunctions.h>
|
||||
#include <LibCrypto/PK/Code/EMSA_PSS.h>
|
||||
#include <LibTLS/TLSv12.h>
|
||||
|
||||
|
@ -224,6 +226,43 @@ void TLSv12::build_rsa_pre_master_secret(PacketBuilder& builder)
|
|||
builder.append(outbuf);
|
||||
}
|
||||
|
||||
void TLSv12::build_dhe_rsa_pre_master_secret(PacketBuilder& builder)
|
||||
{
|
||||
auto& dh = m_context.server_diffie_hellman_params;
|
||||
auto dh_p = Crypto::UnsignedBigInteger::import_data(dh.p.data(), dh.p.size());
|
||||
auto dh_g = Crypto::UnsignedBigInteger::import_data(dh.g.data(), dh.g.size());
|
||||
auto dh_Ys = Crypto::UnsignedBigInteger::import_data(dh.Ys.data(), dh.Ys.size());
|
||||
auto dh_key_size = dh.p.size();
|
||||
|
||||
auto dh_random = Crypto::NumberTheory::random_number(0, dh_p);
|
||||
auto dh_Yc = Crypto::NumberTheory::ModularPower(dh_g, dh_random, dh_p);
|
||||
auto dh_Yc_bytes = ByteBuffer::create_uninitialized(dh_key_size);
|
||||
dh_Yc.export_data(dh_Yc_bytes);
|
||||
|
||||
auto premaster_key = Crypto::NumberTheory::ModularPower(dh_Ys, dh_random, dh_p);
|
||||
m_context.premaster_key = ByteBuffer::create_uninitialized(dh_key_size);
|
||||
premaster_key.export_data(m_context.premaster_key, true);
|
||||
|
||||
dh.p.clear();
|
||||
dh.g.clear();
|
||||
dh.Ys.clear();
|
||||
|
||||
if constexpr (TLS_DEBUG) {
|
||||
dbgln("dh_random: {}", dh_random.to_base(16));
|
||||
dbgln("dh_Yc: {:hex-dump}", (ReadonlyBytes)dh_Yc_bytes);
|
||||
dbgln("premaster key: {:hex-dump}", (ReadonlyBytes)m_context.premaster_key);
|
||||
}
|
||||
|
||||
if (!compute_master_secret_from_pre_master_secret(48)) {
|
||||
dbgln("oh noes we could not derive a master key :(");
|
||||
return;
|
||||
}
|
||||
|
||||
builder.append_u24(dh_key_size + 2);
|
||||
builder.append((u16)dh_key_size);
|
||||
builder.append(dh_Yc_bytes);
|
||||
}
|
||||
|
||||
ByteBuffer TLSv12::build_certificate()
|
||||
{
|
||||
PacketBuilder builder { MessageType::Handshake, m_context.options.version };
|
||||
|
@ -296,8 +335,7 @@ ByteBuffer TLSv12::build_client_key_exchange()
|
|||
TODO();
|
||||
break;
|
||||
case KeyExchangeAlgorithm::DHE_RSA:
|
||||
dbgln("Client key exchange for DHE_RSA is not implemented");
|
||||
TODO();
|
||||
build_dhe_rsa_pre_master_secret(builder);
|
||||
break;
|
||||
case KeyExchangeAlgorithm::DH_anon:
|
||||
dbgln("Client key exchange for DH_anon is not implemented");
|
||||
|
|
|
@ -199,7 +199,7 @@ ByteBuffer TLSv12::build_server_key_exchange()
|
|||
return {};
|
||||
}
|
||||
|
||||
ssize_t TLSv12::handle_server_key_exchange(ReadonlyBytes)
|
||||
ssize_t TLSv12::handle_server_key_exchange(ReadonlyBytes buffer)
|
||||
{
|
||||
switch (get_key_exchange_algorithm(m_context.cipher)) {
|
||||
case KeyExchangeAlgorithm::RSA:
|
||||
|
@ -214,8 +214,7 @@ ssize_t TLSv12::handle_server_key_exchange(ReadonlyBytes)
|
|||
TODO();
|
||||
break;
|
||||
case KeyExchangeAlgorithm::DHE_RSA:
|
||||
dbgln("Server key exchange for DHE_RSA is not implemented");
|
||||
TODO();
|
||||
handle_dhe_rsa_server_key_exchange(buffer);
|
||||
break;
|
||||
case KeyExchangeAlgorithm::DH_anon:
|
||||
dbgln("Server key exchange for DH_anon is not implemented");
|
||||
|
@ -237,4 +236,29 @@ ssize_t TLSv12::handle_server_key_exchange(ReadonlyBytes)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ssize_t TLSv12::handle_dhe_rsa_server_key_exchange(ReadonlyBytes buffer)
|
||||
{
|
||||
auto dh_p_length = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(3)));
|
||||
auto dh_p = buffer.slice(5, dh_p_length);
|
||||
m_context.server_diffie_hellman_params.p = ByteBuffer::copy(dh_p.data(), dh_p.size());
|
||||
|
||||
auto dh_g_length = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(5 + dh_p_length)));
|
||||
auto dh_g = buffer.slice(7 + dh_p_length, dh_g_length);
|
||||
m_context.server_diffie_hellman_params.g = ByteBuffer::copy(dh_g.data(), dh_g.size());
|
||||
|
||||
auto dh_Ys_length = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(7 + dh_p_length + dh_g_length)));
|
||||
auto dh_Ys = buffer.slice(9 + dh_p_length + dh_g_length, dh_Ys_length);
|
||||
m_context.server_diffie_hellman_params.Ys = ByteBuffer::copy(dh_Ys.data(), dh_Ys.size());
|
||||
|
||||
if constexpr (TLS_DEBUG) {
|
||||
dbgln("dh_p: {:hex-dump}", dh_p);
|
||||
dbgln("dh_g: {:hex-dump}", dh_g);
|
||||
dbgln("dh_Ys: {:hex-dump}", dh_Ys);
|
||||
}
|
||||
|
||||
// FIXME: Validate signature of Diffie-Hellman parameters as defined in RFC 5246 section 7.4.3.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -300,6 +300,12 @@ struct Context {
|
|||
size_t send_retries { 0 };
|
||||
|
||||
time_t handshake_initiation_timestamp { 0 };
|
||||
|
||||
struct {
|
||||
ByteBuffer p;
|
||||
ByteBuffer g;
|
||||
ByteBuffer Ys;
|
||||
} server_diffie_hellman_params;
|
||||
};
|
||||
|
||||
class TLSv12 : public Core::Socket {
|
||||
|
@ -397,6 +403,7 @@ private:
|
|||
ByteBuffer build_change_cipher_spec();
|
||||
ByteBuffer build_verify_request();
|
||||
void build_rsa_pre_master_secret(PacketBuilder&);
|
||||
void build_dhe_rsa_pre_master_secret(PacketBuilder&);
|
||||
|
||||
bool flush();
|
||||
void write_into_socket();
|
||||
|
@ -408,6 +415,7 @@ private:
|
|||
ssize_t handle_handshake_finished(ReadonlyBytes, WritePacketStage&);
|
||||
ssize_t handle_certificate(ReadonlyBytes);
|
||||
ssize_t handle_server_key_exchange(ReadonlyBytes);
|
||||
ssize_t handle_dhe_rsa_server_key_exchange(ReadonlyBytes);
|
||||
ssize_t handle_server_hello_done(ReadonlyBytes);
|
||||
ssize_t handle_certificate_verify(ReadonlyBytes);
|
||||
ssize_t handle_handshake_payload(ReadonlyBytes);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue