Просмотр исходного кода

LibTLS: Add ECDSA support with the secp256r1 curve

Michiel Visser 3 лет назад
Родитель
Сommit
c548dca174

+ 1 - 1
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();

+ 109 - 3
Userland/Libraries/LibTLS/HandshakeServer.cpp

@@ -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;
+}
+
 }

+ 8 - 2
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<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
     {