diff --git a/Userland/Libraries/LibTLS/HandshakeClient.cpp b/Userland/Libraries/LibTLS/HandshakeClient.cpp index 70f02f0344..eaca644a9c 100644 --- a/Userland/Libraries/LibTLS/HandshakeClient.cpp +++ b/Userland/Libraries/LibTLS/HandshakeClient.cpp @@ -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(); diff --git a/Userland/Libraries/LibTLS/HandshakeServer.cpp b/Userland/Libraries/LibTLS/HandshakeServer.cpp index 239f1882bb..9513741a48 100644 --- a/Userland/Libraries/LibTLS/HandshakeServer.cpp +++ b/Userland/Libraries/LibTLS/HandshakeServer.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -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 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; +} + } diff --git a/Userland/Libraries/LibTLS/TLSv12.h b/Userland/Libraries/LibTLS/TLSv12.h index 4165de4f8b..e3a1953f10 100644 --- a/Userland/Libraries/LibTLS/TLSv12.h +++ b/Userland/Libraries/LibTLS/TLSv12.h @@ -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, 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 {