diff --git a/Userland/Libraries/LibTLS/HandshakeClient.cpp b/Userland/Libraries/LibTLS/HandshakeClient.cpp index 4d75f62413..38c8e34efe 100644 --- a/Userland/Libraries/LibTLS/HandshakeClient.cpp +++ b/Userland/Libraries/LibTLS/HandshakeClient.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -294,19 +295,68 @@ void TLSv12::build_dhe_rsa_pre_master_secret(PacketBuilder& builder) builder.append(dh_Yc_bytes); } +ErrorOr TLSv12::named_curve_multiply(NamedCurve curve, ReadonlyBytes a, ReadonlyBytes b) +{ + switch (curve) { + case NamedCurve::x25519: + return Crypto::Curves::X25519::compute_coordinate(a, b); + case NamedCurve::x448: + return Crypto::Curves::X448::compute_coordinate(a, b); + default: + dbgln("No known handler for multiplying curve {}", static_cast(curve)); + TODO(); + } +} + +ErrorOr TLSv12::named_curve_generator_point(NamedCurve curve) +{ + auto key_size = named_curve_key_size(curve) / 8; + + auto generator_point_data_result = ByteBuffer::create_zeroed(key_size); + if (generator_point_data_result.is_error()) { + dbgln("Failed to generate curve multiplication point: not enough memory"); + return AK::Error::from_string_literal("Failed to generate curve multiplication point: not enough memory"); + } + auto generator_point_data = generator_point_data_result.release_value(); + + switch (curve) { + case NamedCurve::x25519: + ByteReader::store(generator_point_data.offset_pointer(0), 9); + break; + case NamedCurve::x448: + ByteReader::store(generator_point_data.offset_pointer(0), 5); + break; + default: + dbgln("No known handler for generator point of curve {}", static_cast(curve)); + TODO(); + } + + return generator_point_data; +} + void TLSv12::build_ecdhe_rsa_pre_master_secret(PacketBuilder& builder) { - size_t const key_size = named_curve_key_size(NamedCurve::x25519) / 8; - u8 generator_point[key_size] { 9 }; - ReadonlyBytes generator_point_bytes { generator_point, key_size }; + size_t const key_size = named_curve_key_size(m_context.server_curve_choice) / 8; + auto generator_point_result = named_curve_generator_point(m_context.server_curve_choice); + if (generator_point_result.is_error()) { + dbgln("Failed to build ECDHE_RSA premaster secret: not enough memory"); + return; + } + auto generator_point = generator_point_result.release_value(); + ReadonlyBytes generator_point_bytes = generator_point; // Create a random private key - u8 private_key[key_size]; - fill_with_random(private_key, key_size); - ReadonlyBytes private_key_bytes { private_key, key_size }; + auto private_key_result = ByteBuffer::create_uninitialized(key_size); + if (private_key_result.is_error()) { + dbgln("Failed to build ECDHE_RSA premaster secret: not enough memory"); + return; + } + auto private_key = private_key_result.release_value(); + fill_with_random(private_key.data(), key_size); + ReadonlyBytes private_key_bytes = private_key; - // Calculate the public key by multiplying the private key with 9 - auto public_key_result = Crypto::Curves::X25519::compute_coordinate(private_key_bytes, generator_point_bytes); + // Calculate the public key by multiplying the private key with the generator point + auto public_key_result = named_curve_multiply(m_context.server_curve_choice, private_key_bytes, generator_point_bytes); if (public_key_result.is_error()) { dbgln("Failed to build ECDHE_RSA premaster secret: not enough memory"); return; @@ -315,7 +365,7 @@ void TLSv12::build_ecdhe_rsa_pre_master_secret(PacketBuilder& builder) // Calculate the pre master secret by multiplying the client private key and the server public key ReadonlyBytes server_public_key_bytes = m_context.server_diffie_hellman_params.p; - auto pre_master_secret_result = Crypto::Curves::X25519::compute_coordinate(private_key_bytes, server_public_key_bytes); + auto pre_master_secret_result = named_curve_multiply(m_context.server_curve_choice, private_key_bytes, server_public_key_bytes); if (pre_master_secret_result.is_error()) { dbgln("Failed to build ECDHE_RSA premaster secret: not enough memory"); return; diff --git a/Userland/Libraries/LibTLS/HandshakeServer.cpp b/Userland/Libraries/LibTLS/HandshakeServer.cpp index ffad3216b7..1fc590fbe3 100644 --- a/Userland/Libraries/LibTLS/HandshakeServer.cpp +++ b/Userland/Libraries/LibTLS/HandshakeServer.cpp @@ -290,21 +290,26 @@ ssize_t TLSv12::handle_dhe_rsa_server_key_exchange(ReadonlyBytes buffer) ssize_t TLSv12::handle_ecdhe_rsa_server_key_exchange(ReadonlyBytes buffer) { - auto x25519_key_size_bytes = named_curve_key_size(NamedCurve::x25519) / 8; - if (buffer.size() < x25519_key_size_bytes + 7) + size_t size_required_for_curve_name = 6; + if (buffer.size() < size_required_for_curve_name) return (i8)Error::NeedMoreData; auto curve_type = buffer[3]; if (curve_type != (u8)ECCurveType::NamedCurve) return (i8)Error::NotUnderstood; - auto curve = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(4))); - if (curve != (u16)NamedCurve::x25519) + auto curve = static_cast(AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(4)))); + if (!m_context.options.elliptic_curves.contains_slow(curve)) return (i8)Error::NotUnderstood; + m_context.server_curve_choice = curve; + auto curve_key_size_bytes = named_curve_key_size(curve) / 8; + if (buffer.size() < curve_key_size_bytes + 1) + return (i8)Error::NeedMoreData; + auto server_public_key_length = buffer[6]; - if (server_public_key_length != x25519_key_size_bytes) - return (i8)Error::NotUnderstood; + if (server_public_key_length != curve_key_size_bytes) + return (i8)Error::FeatureNotSupported; auto server_public_key = buffer.slice(7, server_public_key_length); auto server_public_key_copy_result = ByteBuffer::copy(server_public_key); diff --git a/Userland/Libraries/LibTLS/TLSv12.h b/Userland/Libraries/LibTLS/TLSv12.h index 850bd5c4fb..b94fae81fc 100644 --- a/Userland/Libraries/LibTLS/TLSv12.h +++ b/Userland/Libraries/LibTLS/TLSv12.h @@ -242,7 +242,9 @@ struct Options { { HashAlgorithm::SHA384, SignatureAlgorithm::RSA }, { HashAlgorithm::SHA256, SignatureAlgorithm::RSA }, { HashAlgorithm::SHA1, SignatureAlgorithm::RSA }); - OPTION_WITH_DEFAULTS(Vector, elliptic_curves, NamedCurve::x25519) + OPTION_WITH_DEFAULTS(Vector, elliptic_curves, + NamedCurve::x25519, + NamedCurve::x448) OPTION_WITH_DEFAULTS(Vector, supported_ec_point_formats, ECPointFormat::Uncompressed) OPTION_WITH_DEFAULTS(bool, use_sni, true) @@ -331,6 +333,8 @@ struct Context { ByteBuffer g; ByteBuffer Ys; } server_diffie_hellman_params; + + NamedCurve server_curve_choice; }; class TLSv12 final : public Core::Stream::Socket { @@ -461,6 +465,9 @@ private: void build_dhe_rsa_pre_master_secret(PacketBuilder&); void build_ecdhe_rsa_pre_master_secret(PacketBuilder&); + static ErrorOr named_curve_multiply(NamedCurve curve, ReadonlyBytes a, ReadonlyBytes b); + static ErrorOr named_curve_generator_point(NamedCurve curve); + ErrorOr flush(); void write_into_socket(); ErrorOr read_from_socket();