mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-21 18:37:58 +03:00
LibTLS: Add ECDSA support with the secp256r1 curve
This commit is contained in:
parent
caf533bddf
commit
c548dca174
Notes:
sideshowbarker
2024-07-17 02:35:27 +09:00
Author: https://github.com/msvisser Commit: https://github.com/SerenityOS/serenity/commit/c548dca174 Pull-request: https://github.com/SerenityOS/serenity/pull/21212 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/stelar7
@ -393,11 +393,11 @@ ByteBuffer TLSv12::build_client_key_exchange()
|
||||
TODO();
|
||||
break;
|
||||
case KeyExchangeAlgorithm::ECDHE_RSA:
|
||||
case KeyExchangeAlgorithm::ECDHE_ECDSA:
|
||||
build_ecdhe_rsa_pre_master_secret(builder);
|
||||
break;
|
||||
case KeyExchangeAlgorithm::ECDH_ECDSA:
|
||||
case KeyExchangeAlgorithm::ECDH_RSA:
|
||||
case KeyExchangeAlgorithm::ECDHE_ECDSA:
|
||||
case KeyExchangeAlgorithm::ECDH_anon:
|
||||
dbgln("Client key exchange for ECDHE algorithms is not implemented");
|
||||
TODO();
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <LibCore/Timer.h>
|
||||
#include <LibCrypto/ASN1/DER.h>
|
||||
#include <LibCrypto/Curves/Ed25519.h>
|
||||
#include <LibCrypto/Curves/EllipticCurve.h>
|
||||
#include <LibCrypto/Curves/SECP256r1.h>
|
||||
#include <LibCrypto/Curves/X25519.h>
|
||||
@ -237,9 +238,10 @@ ssize_t TLSv12::handle_server_key_exchange(ReadonlyBytes buffer)
|
||||
break;
|
||||
case KeyExchangeAlgorithm::ECDHE_RSA:
|
||||
return handle_ecdhe_rsa_server_key_exchange(buffer);
|
||||
case KeyExchangeAlgorithm::ECDHE_ECDSA:
|
||||
return handle_ecdhe_ecdsa_server_key_exchange(buffer);
|
||||
case KeyExchangeAlgorithm::ECDH_ECDSA:
|
||||
case KeyExchangeAlgorithm::ECDH_RSA:
|
||||
case KeyExchangeAlgorithm::ECDHE_ECDSA:
|
||||
case KeyExchangeAlgorithm::ECDH_anon:
|
||||
dbgln("Server key exchange for ECDHE algorithms is not implemented");
|
||||
TODO();
|
||||
@ -292,7 +294,7 @@ ssize_t TLSv12::handle_dhe_rsa_server_key_exchange(ReadonlyBytes buffer)
|
||||
return verify_rsa_server_key_exchange(server_key_info, signature);
|
||||
}
|
||||
|
||||
ssize_t TLSv12::handle_ecdhe_rsa_server_key_exchange(ReadonlyBytes buffer)
|
||||
ssize_t TLSv12::handle_ecdhe_server_key_exchange(ReadonlyBytes buffer, u8& server_public_key_length)
|
||||
{
|
||||
if (buffer.size() < 7)
|
||||
return (i8)Error::NeedMoreData;
|
||||
@ -319,7 +321,7 @@ ssize_t TLSv12::handle_ecdhe_rsa_server_key_exchange(ReadonlyBytes buffer)
|
||||
return (i8)Error::NotUnderstood;
|
||||
}
|
||||
|
||||
auto server_public_key_length = buffer[6];
|
||||
server_public_key_length = buffer[6];
|
||||
if (server_public_key_length != m_context.server_key_exchange_curve->key_size())
|
||||
return (i8)Error::NotUnderstood;
|
||||
|
||||
@ -338,6 +340,16 @@ ssize_t TLSv12::handle_ecdhe_rsa_server_key_exchange(ReadonlyBytes buffer)
|
||||
dbgln("ECDHE server public key: {:hex-dump}", server_public_key);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t TLSv12::handle_ecdhe_rsa_server_key_exchange(ReadonlyBytes buffer)
|
||||
{
|
||||
u8 server_public_key_length;
|
||||
if (auto result = handle_ecdhe_server_key_exchange(buffer, server_public_key_length)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto server_key_info = buffer.slice(3, 4 + server_public_key_length);
|
||||
auto signature = buffer.slice(7 + server_public_key_length);
|
||||
return verify_rsa_server_key_exchange(server_key_info, signature);
|
||||
@ -412,4 +424,98 @@ ssize_t TLSv12::verify_rsa_server_key_exchange(ReadonlyBytes server_key_info_buf
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t TLSv12::handle_ecdhe_ecdsa_server_key_exchange(ReadonlyBytes buffer)
|
||||
{
|
||||
u8 server_public_key_length;
|
||||
if (auto result = handle_ecdhe_server_key_exchange(buffer, server_public_key_length)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto server_key_info = buffer.slice(3, 4 + server_public_key_length);
|
||||
auto signature = buffer.slice(7 + server_public_key_length);
|
||||
return verify_ecdsa_server_key_exchange(server_key_info, signature);
|
||||
}
|
||||
|
||||
ssize_t TLSv12::verify_ecdsa_server_key_exchange(ReadonlyBytes server_key_info_buffer, ReadonlyBytes signature_buffer)
|
||||
{
|
||||
auto signature_hash = signature_buffer[0];
|
||||
auto signature_algorithm = signature_buffer[1];
|
||||
if (signature_algorithm != (u8)SignatureAlgorithm::ECDSA) {
|
||||
dbgln("verify_ecdsa_server_key_exchange failed: Signature algorithm is not ECDSA, instead {}", signature_algorithm);
|
||||
return (i8)Error::NotUnderstood;
|
||||
}
|
||||
|
||||
auto signature_length = AK::convert_between_host_and_network_endian(ByteReader::load16(signature_buffer.offset_pointer(2)));
|
||||
auto signature = signature_buffer.slice(4, signature_length);
|
||||
|
||||
if (m_context.certificates.is_empty()) {
|
||||
dbgln("verify_ecdsa_server_key_exchange failed: Attempting to verify signature without certificates");
|
||||
return (i8)Error::NotSafe;
|
||||
}
|
||||
ReadonlyBytes server_point = m_context.certificates.first().public_key.raw_key;
|
||||
|
||||
auto message_result = ByteBuffer::create_uninitialized(64 + server_key_info_buffer.size());
|
||||
if (message_result.is_error()) {
|
||||
dbgln("verify_ecdsa_server_key_exchange failed: Not enough memory");
|
||||
return (i8)Error::OutOfMemory;
|
||||
}
|
||||
auto message = message_result.release_value();
|
||||
message.overwrite(0, m_context.local_random, 32);
|
||||
message.overwrite(32, m_context.remote_random, 32);
|
||||
message.overwrite(64, server_key_info_buffer.data(), server_key_info_buffer.size());
|
||||
|
||||
Crypto::Hash::HashKind hash_kind;
|
||||
switch ((HashAlgorithm)signature_hash) {
|
||||
case HashAlgorithm::SHA256:
|
||||
hash_kind = Crypto::Hash::HashKind::SHA256;
|
||||
break;
|
||||
case HashAlgorithm::SHA384:
|
||||
hash_kind = Crypto::Hash::HashKind::SHA384;
|
||||
break;
|
||||
case HashAlgorithm::SHA512:
|
||||
hash_kind = Crypto::Hash::HashKind::SHA512;
|
||||
break;
|
||||
default:
|
||||
dbgln("verify_ecdsa_server_key_exchange failed: Hash algorithm is not SHA256/384/512, instead {}", signature_hash);
|
||||
return (i8)Error::NotUnderstood;
|
||||
}
|
||||
|
||||
ErrorOr<bool> res = AK::Error::from_errno(ENOTSUP);
|
||||
auto& public_key = m_context.certificates.first().public_key;
|
||||
switch (public_key.algorithm.ec_parameters) {
|
||||
case SupportedGroup::SECP256R1: {
|
||||
Crypto::Hash::Manager manager(hash_kind);
|
||||
manager.update(message);
|
||||
auto digest = manager.digest();
|
||||
|
||||
Crypto::Curves::SECP256r1 curve;
|
||||
res = curve.verify(digest.bytes(), server_point, signature);
|
||||
break;
|
||||
}
|
||||
case SupportedGroup::X25519: {
|
||||
Crypto::Curves::Ed25519 curve;
|
||||
res = curve.verify(public_key.raw_key, signature, message);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
dbgln("verify_ecdsa_server_key_exchange failed: Server certificate public key algorithm is not supported: {}", to_underlying(public_key.algorithm.ec_parameters));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res.is_error()) {
|
||||
dbgln("verify_ecdsa_server_key_exchange failed: {}", res.error());
|
||||
return (i8)Error::NotUnderstood;
|
||||
}
|
||||
|
||||
bool verification_ok = res.release_value();
|
||||
if (!verification_ok) {
|
||||
dbgln("verify_ecdsa_server_key_exchange failed: Verification of signature failed");
|
||||
return (i8)Error::NotSafe;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -98,7 +98,8 @@ enum ClientVerificationStaus {
|
||||
C(true, CipherSuite::TLS_RSA_WITH_AES_128_CBC_SHA256, KeyExchangeAlgorithm::RSA, CipherAlgorithm::AES_128_CBC, Crypto::Hash::SHA256, 16, false) \
|
||||
C(true, CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA256, KeyExchangeAlgorithm::RSA, CipherAlgorithm::AES_256_CBC, Crypto::Hash::SHA256, 16, false) \
|
||||
C(true, CipherSuite::TLS_RSA_WITH_AES_128_CBC_SHA, KeyExchangeAlgorithm::RSA, CipherAlgorithm::AES_128_CBC, Crypto::Hash::SHA1, 16, false) \
|
||||
C(true, CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA, KeyExchangeAlgorithm::RSA, CipherAlgorithm::AES_256_CBC, Crypto::Hash::SHA1, 16, false)
|
||||
C(true, CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA, KeyExchangeAlgorithm::RSA, CipherAlgorithm::AES_256_CBC, Crypto::Hash::SHA1, 16, false) \
|
||||
C(true, CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, KeyExchangeAlgorithm::ECDHE_ECDSA, CipherAlgorithm::AES_128_GCM, Crypto::Hash::SHA256, 8, true)
|
||||
|
||||
constexpr KeyExchangeAlgorithm get_key_exchange_algorithm(CipherSuite suite)
|
||||
{
|
||||
@ -161,7 +162,9 @@ struct Options {
|
||||
{ HashAlgorithm::SHA512, SignatureAlgorithm::RSA },
|
||||
{ HashAlgorithm::SHA384, SignatureAlgorithm::RSA },
|
||||
{ HashAlgorithm::SHA256, SignatureAlgorithm::RSA },
|
||||
{ HashAlgorithm::SHA1, SignatureAlgorithm::RSA });
|
||||
{ HashAlgorithm::SHA1, SignatureAlgorithm::RSA },
|
||||
{ HashAlgorithm::SHA256, SignatureAlgorithm::ECDSA },
|
||||
{ HashAlgorithm::INTRINSIC, SignatureAlgorithm::ECDSA });
|
||||
OPTION_WITH_DEFAULTS(Vector<SupportedGroup>, elliptic_curves,
|
||||
SupportedGroup::X25519,
|
||||
SupportedGroup::SECP256R1,
|
||||
@ -384,7 +387,9 @@ private:
|
||||
ssize_t handle_certificate(ReadonlyBytes);
|
||||
ssize_t handle_server_key_exchange(ReadonlyBytes);
|
||||
ssize_t handle_dhe_rsa_server_key_exchange(ReadonlyBytes);
|
||||
ssize_t handle_ecdhe_server_key_exchange(ReadonlyBytes, u8& server_public_key_length);
|
||||
ssize_t handle_ecdhe_rsa_server_key_exchange(ReadonlyBytes);
|
||||
ssize_t handle_ecdhe_ecdsa_server_key_exchange(ReadonlyBytes);
|
||||
ssize_t handle_server_hello_done(ReadonlyBytes);
|
||||
ssize_t handle_certificate_verify(ReadonlyBytes);
|
||||
ssize_t handle_handshake_payload(ReadonlyBytes);
|
||||
@ -393,6 +398,7 @@ private:
|
||||
void pseudorandom_function(Bytes output, ReadonlyBytes secret, u8 const* label, size_t label_length, ReadonlyBytes seed, ReadonlyBytes seed_b);
|
||||
|
||||
ssize_t verify_rsa_server_key_exchange(ReadonlyBytes server_key_info_buffer, ReadonlyBytes signature_buffer);
|
||||
ssize_t verify_ecdsa_server_key_exchange(ReadonlyBytes server_key_info_buffer, ReadonlyBytes signature_buffer);
|
||||
|
||||
size_t key_length() const
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user