summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDexesTTP <dexes.ttp@gmail.com>2021-05-29 08:26:10 +0200
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2021-05-29 13:29:46 +0430
commit4bbf954ad037e456da48e71fe85dfbbfca84275f (patch)
treee6b0412fb56e6a9bb5b2e9e039e4cd324e0b62c7
parentcb4a0dec8a3f723e8c1eaa261e490052fa1f84f5 (diff)
downloadserenity-4bbf954ad037e456da48e71fe85dfbbfca84275f.zip
LibTLS: Allow using other hash algorithms for HMAC
The standard allows for ciphers to define which hash to use. Fixes #7348
-rw-r--r--Userland/Libraries/LibTLS/Handshake.cpp13
-rw-r--r--Userland/Libraries/LibTLS/HandshakeServer.cpp4
-rw-r--r--Userland/Libraries/LibTLS/TLSv12.cpp39
-rw-r--r--Userland/Libraries/LibTLS/TLSv12.h14
4 files changed, 56 insertions, 14 deletions
diff --git a/Userland/Libraries/LibTLS/Handshake.cpp b/Userland/Libraries/LibTLS/Handshake.cpp
index fc1402f922..7f6361f595 100644
--- a/Userland/Libraries/LibTLS/Handshake.cpp
+++ b/Userland/Libraries/LibTLS/Handshake.cpp
@@ -140,12 +140,17 @@ ByteBuffer TLSv12::build_handshake_finished()
PacketBuilder builder { MessageType::Handshake, m_context.options.version, 12 + 64 };
builder.append((u8)HandshakeType::Finished);
- constexpr u32 out_size = 12;
+ // RFC 5246 section 7.4.9: "In previous versions of TLS, the verify_data was always 12 octets
+ // long. In the current version of TLS, it depends on the cipher
+ // suite. Any cipher suite which does not explicitly specify
+ // verify_data_length has a verify_data_length equal to 12."
+ // Simplification: Assume that verify_data_length is always 12.
+ constexpr u32 verify_data_length = 12;
- builder.append_u24(out_size);
+ builder.append_u24(verify_data_length);
- u8 out[out_size];
- auto outbuffer = Bytes { out, out_size };
+ u8 out[verify_data_length];
+ auto outbuffer = Bytes { out, verify_data_length };
auto dummy = ByteBuffer::create_zeroed(0);
auto digest = m_context.handshake_hash.digest();
diff --git a/Userland/Libraries/LibTLS/HandshakeServer.cpp b/Userland/Libraries/LibTLS/HandshakeServer.cpp
index 66b615fdee..7af7949f03 100644
--- a/Userland/Libraries/LibTLS/HandshakeServer.cpp
+++ b/Userland/Libraries/LibTLS/HandshakeServer.cpp
@@ -81,8 +81,8 @@ ssize_t TLSv12::handle_server_hello(ReadonlyBytes buffer, WritePacketStage& writ
m_context.cipher = cipher;
dbgln_if(TLS_DEBUG, "Cipher: {}", (u16)cipher);
- // The handshake hash function is _always_ SHA256
- m_context.handshake_hash.initialize(Crypto::Hash::HashKind::SHA256);
+ // Simplification: We only support handshake hash functions via HMAC
+ m_context.handshake_hash.initialize(hmac_hash());
// Compression method
if (buffer.size() - res < 1)
diff --git a/Userland/Libraries/LibTLS/TLSv12.cpp b/Userland/Libraries/LibTLS/TLSv12.cpp
index f39b201743..3993ce26ad 100644
--- a/Userland/Libraries/LibTLS/TLSv12.cpp
+++ b/Userland/Libraries/LibTLS/TLSv12.cpp
@@ -232,19 +232,14 @@ bool Context::verify_chain() const
return true;
}
-void TLSv12::pseudorandom_function(Bytes output, ReadonlyBytes secret, const u8* label, size_t label_length, ReadonlyBytes seed, ReadonlyBytes seed_b)
+template<typename HMACType>
+static void hmac_pseudorandom_function(Bytes output, ReadonlyBytes secret, const u8* label, size_t label_length, ReadonlyBytes seed, ReadonlyBytes seed_b)
{
if (!secret.size()) {
dbgln("null secret");
return;
}
- // RFC 5246: "In this section, we define one PRF, based on HMAC. This PRF with the
- // SHA-256 hash function is used for all cipher suites defined in this
- // document and in TLS documents published prior to this document when
- // TLS 1.2 is negotiated."
- // Apparently this PRF _always_ uses SHA256
-
auto append_label_seed = [&](auto& hmac) {
hmac.update(label, label_length);
hmac.update(seed);
@@ -252,7 +247,7 @@ void TLSv12::pseudorandom_function(Bytes output, ReadonlyBytes secret, const u8*
hmac.update(seed_b);
};
- Crypto::Authentication::HMAC<Crypto::Hash::SHA256> hmac(secret);
+ HMACType hmac(secret);
append_label_seed(hmac);
constexpr auto digest_size = hmac.digest_size();
@@ -276,6 +271,34 @@ void TLSv12::pseudorandom_function(Bytes output, ReadonlyBytes secret, const u8*
}
}
+void TLSv12::pseudorandom_function(Bytes output, ReadonlyBytes secret, const u8* label, size_t label_length, ReadonlyBytes seed, ReadonlyBytes seed_b)
+{
+ // Simplification: We only support the HMAC PRF with the hash function SHA-256 or stronger.
+
+ // RFC 5246: "In this section, we define one PRF, based on HMAC. This PRF with the
+ // SHA-256 hash function is used for all cipher suites defined in this
+ // document and in TLS documents published prior to this document when
+ // TLS 1.2 is negotiated. New cipher suites MUST explicitly specify a
+ // PRF and, in general, SHOULD use the TLS PRF with SHA-256 or a
+ // stronger standard hash function."
+
+ switch (hmac_hash()) {
+ case Crypto::Hash::HashKind::SHA512:
+ hmac_pseudorandom_function<Crypto::Authentication::HMAC<Crypto::Hash::SHA512>>(output, secret, label, label_length, seed, seed_b);
+ break;
+ case Crypto::Hash::HashKind::SHA384:
+ hmac_pseudorandom_function<Crypto::Authentication::HMAC<Crypto::Hash::SHA384>>(output, secret, label, label_length, seed, seed_b);
+ break;
+ case Crypto::Hash::HashKind::SHA256:
+ hmac_pseudorandom_function<Crypto::Authentication::HMAC<Crypto::Hash::SHA256>>(output, secret, label, label_length, seed, seed_b);
+ break;
+ default:
+ dbgln("Failed to find a suitable HMAC hash");
+ VERIFY_NOT_REACHED();
+ break;
+ }
+}
+
TLSv12::TLSv12(Core::Object* parent, Options options)
: Core::Socket(Core::Socket::Type::TCP, parent)
{
diff --git a/Userland/Libraries/LibTLS/TLSv12.h b/Userland/Libraries/LibTLS/TLSv12.h
index 23f899ca54..628453d3ef 100644
--- a/Userland/Libraries/LibTLS/TLSv12.h
+++ b/Userland/Libraries/LibTLS/TLSv12.h
@@ -447,6 +447,20 @@ private:
}
}
+ Crypto::Hash::HashKind hmac_hash() const
+ {
+ switch (mac_length()) {
+ case Crypto::Hash::SHA512::DigestSize:
+ return Crypto::Hash::HashKind::SHA512;
+ case Crypto::Hash::SHA384::DigestSize:
+ return Crypto::Hash::HashKind::SHA384;
+ case Crypto::Hash::SHA256::DigestSize:
+ case Crypto::Hash::SHA1::DigestSize:
+ default:
+ return Crypto::Hash::HashKind::SHA256;
+ }
+ }
+
size_t iv_length() const
{
switch (m_context.cipher) {