ladybird/Userland/Libraries/LibTLS/Handshake.cpp
Ali Mohammad Pur afa98fcb55 LibTLS: Always send the signature_algorithms extension
At some point since Sep 2018, OpenSSL added a ~~bug~~ feature that makes
the default set of signature algorithms defined in TLSv1.2 unusable
without reducing what they call the "security level", which caused
communication with servers using more recent versions of openssl to
fail with "internal error".
This commit makes LibTLS always send its supported sigalgs, making the
server not default to the insecure defaults, and thus enabling us to
talk to such servers.
2021-05-12 08:35:02 +01:00

170 lines
5.1 KiB
C++

/*
* Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Random.h>
#include <LibCrypto/ASN1/DER.h>
#include <LibCrypto/PK/Code/EMSA_PSS.h>
#include <LibTLS/TLSv12.h>
namespace TLS {
ByteBuffer TLSv12::build_hello()
{
fill_with_random(&m_context.local_random, 32);
auto packet_version = (u16)m_context.options.version;
auto version = (u16)m_context.options.version;
PacketBuilder builder { MessageType::Handshake, packet_version };
builder.append((u8)ClientHello);
// hello length (for later)
u8 dummy[3] = {};
builder.append(dummy, 3);
auto start_length = builder.length();
builder.append(version);
builder.append(m_context.local_random, sizeof(m_context.local_random));
builder.append(m_context.session_id_size);
if (m_context.session_id_size)
builder.append(m_context.session_id, m_context.session_id_size);
size_t extension_length = 0;
size_t alpn_length = 0;
size_t alpn_negotiated_length = 0;
// ALPN
if (!m_context.negotiated_alpn.is_null()) {
alpn_negotiated_length = m_context.negotiated_alpn.length();
alpn_length = alpn_negotiated_length + 1;
extension_length += alpn_length + 6;
} else if (m_context.alpn.size()) {
for (auto& alpn : m_context.alpn) {
size_t length = alpn.length();
alpn_length += length + 1;
}
if (alpn_length)
extension_length += alpn_length + 6;
}
// Ciphers
builder.append((u16)(m_context.options.usable_cipher_suites.size() * sizeof(u16)));
for (auto suite : m_context.options.usable_cipher_suites)
builder.append((u16)suite);
// we don't like compression
VERIFY(!m_context.options.use_compression);
builder.append((u8)1);
builder.append((u8)m_context.options.use_compression);
// set SNI if we have one, and the user hasn't explicitly asked us to omit it.
auto sni_length = 0;
if (!m_context.extensions.SNI.is_null() && m_context.options.use_sni)
sni_length = m_context.extensions.SNI.length();
// signature_algorithms: 2b extension ID, 2b extension length, 2b vector length, 2xN signatures and hashes
extension_length += 2 + 2 + 2 + 2 * m_context.options.supported_signature_algorithms.size();
if (sni_length)
extension_length += sni_length + 9;
builder.append((u16)extension_length);
if (sni_length) {
// SNI extension
builder.append((u16)HandshakeExtension::ServerName);
// extension length
builder.append((u16)(sni_length + 5));
// SNI length
builder.append((u16)(sni_length + 3));
// SNI type
builder.append((u8)0);
// SNI host length + value
builder.append((u16)sni_length);
builder.append((const u8*)m_context.extensions.SNI.characters(), sni_length);
}
// signature_algorithms extension
builder.append((u16)HandshakeExtension::SignatureAlgorithms);
// Extension length
builder.append((u16)(2 + 2 * m_context.options.supported_signature_algorithms.size()));
// Vector count
builder.append((u16)(m_context.options.supported_signature_algorithms.size() * 2));
// Entries
for (auto& entry : m_context.options.supported_signature_algorithms) {
builder.append((u8)entry.hash);
builder.append((u8)entry.signature);
}
if (alpn_length) {
// TODO
VERIFY_NOT_REACHED();
}
// set the "length" field of the packet
size_t remaining = builder.length() - start_length;
size_t payload_position = 6;
builder.set(payload_position, remaining / 0x10000);
remaining %= 0x10000;
builder.set(payload_position + 1, remaining / 0x100);
remaining %= 0x100;
builder.set(payload_position + 2, remaining);
auto packet = builder.build();
update_packet(packet);
return packet;
}
ByteBuffer TLSv12::build_alert(bool critical, u8 code)
{
PacketBuilder builder(MessageType::Alert, (u16)m_context.options.version);
builder.append((u8)(critical ? AlertLevel::Critical : AlertLevel::Warning));
builder.append(code);
if (critical)
m_context.critical_error = code;
auto packet = builder.build();
update_packet(packet);
return packet;
}
ByteBuffer TLSv12::build_finished()
{
PacketBuilder builder { MessageType::Handshake, m_context.options.version, 12 + 64 };
builder.append((u8)HandshakeType::Finished);
u32 out_size = 12;
builder.append_u24(out_size);
u8 out[out_size];
auto outbuffer = Bytes { out, out_size };
auto dummy = ByteBuffer::create_zeroed(0);
auto digest = m_context.handshake_hash.digest();
auto hashbuf = ReadonlyBytes { digest.immutable_data(), m_context.handshake_hash.digest_size() };
pseudorandom_function(outbuffer, m_context.master_key, (const u8*)"client finished", 15, hashbuf, dummy);
builder.append(outbuffer);
auto packet = builder.build();
update_packet(packet);
return packet;
}
void TLSv12::alert(AlertLevel level, AlertDescription code)
{
auto the_alert = build_alert(level == AlertLevel::Critical, (u8)code);
write_packet(the_alert);
flush();
}
}