From 5853d9642a48733f4bfc51239d2ee36a30a5a14d Mon Sep 17 00:00:00 2001 From: stelar7 Date: Fri, 14 Apr 2023 00:43:25 +0200 Subject: [PATCH] LibTLS: Move AlertDescription to Extensions.h Also add missing values from the IANA registry --- Userland/Libraries/LibTLS/Extensions.h | 56 +++++++++++++++++++ Userland/Libraries/LibTLS/Handshake.cpp | 22 ++++---- Userland/Libraries/LibTLS/HandshakeClient.cpp | 2 +- Userland/Libraries/LibTLS/Record.cpp | 22 ++++---- Userland/Libraries/LibTLS/Socket.cpp | 8 +-- Userland/Libraries/LibTLS/TLSv12.cpp | 30 +++++----- Userland/Libraries/LibTLS/TLSv12.h | 49 ---------------- .../Services/RequestServer/ConnectionCache.h | 4 +- 8 files changed, 100 insertions(+), 93 deletions(-) diff --git a/Userland/Libraries/LibTLS/Extensions.h b/Userland/Libraries/LibTLS/Extensions.h index f1fbe9db24..6a418bf712 100644 --- a/Userland/Libraries/LibTLS/Extensions.h +++ b/Userland/Libraries/LibTLS/Extensions.h @@ -659,7 +659,63 @@ enum class CipherSuite : u16 { __ENUM_CIPHER_SUITES }; +// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-6 +#define __ENUM_ALERT_DESCRIPTIONS \ + _ENUM_KEY_VALUE(CLOSE_NOTIFY, 0) \ + _ENUM_KEY_VALUE(UNEXPECTED_MESSAGE, 10) \ + _ENUM_KEY_VALUE(BAD_RECORD_MAC, 20) \ + _ENUM_KEY_VALUE(DECRYPTION_FAILED_RESERVED, 21) \ + _ENUM_KEY_VALUE(RECORD_OVERFLOW, 22) \ + _ENUM_KEY_VALUE(DECOMPRESSION_FAILURE_RESERVED, 30) \ + _ENUM_KEY_VALUE(HANDSHAKE_FAILURE, 40) \ + _ENUM_KEY_VALUE(NO_CERTIFICATE_RESERVED, 41) \ + _ENUM_KEY_VALUE(BAD_CERTIFICATE, 42) \ + _ENUM_KEY_VALUE(UNSUPPORTED_CERTIFICATE, 43) \ + _ENUM_KEY_VALUE(CERTIFICATE_REVOKED, 44) \ + _ENUM_KEY_VALUE(CERTIFICATE_EXPIRED, 45) \ + _ENUM_KEY_VALUE(CERTIFICATE_UNKNOWN, 46) \ + _ENUM_KEY_VALUE(ILLEGAL_PARAMETER, 47) \ + _ENUM_KEY_VALUE(UNKNOWN_CA, 48) \ + _ENUM_KEY_VALUE(ACCESS_DENIED, 49) \ + _ENUM_KEY_VALUE(DECODE_ERROR, 50) \ + _ENUM_KEY_VALUE(DECRYPT_ERROR, 51) \ + _ENUM_KEY_VALUE(TOO_MANY_CIDS_REQUESTED, 52) \ + _ENUM_KEY_VALUE(EXPORT_RESTRICTION_RESERVED, 60) \ + _ENUM_KEY_VALUE(PROTOCOL_VERSION, 70) \ + _ENUM_KEY_VALUE(INSUFFICIENT_SECURITY, 71) \ + _ENUM_KEY_VALUE(INTERNAL_ERROR, 80) \ + _ENUM_KEY_VALUE(INAPPROPRIATE_FALLBACK, 86) \ + _ENUM_KEY_VALUE(USER_CANCELED, 90) \ + _ENUM_KEY_VALUE(NO_RENEGOTIATION_RESERVED, 100) \ + _ENUM_KEY_VALUE(MISSING_EXTENSION, 109) \ + _ENUM_KEY_VALUE(UNSUPPORTED_EXTENSION, 110) \ + _ENUM_KEY_VALUE(CERTIFICATE_UNOBTAINABLE_RESERVED, 111) \ + _ENUM_KEY_VALUE(UNRECOGNIZED_NAME, 112) \ + _ENUM_KEY_VALUE(BAD_CERTIFICATE_STATUS_RESPONSE, 113) \ + _ENUM_KEY_VALUE(BAD_CERTIFICATE_HASH_VALUE_RESERVED, 114) \ + _ENUM_KEY_VALUE(UNKNOWN_PSK_IDENTITY, 115) \ + _ENUM_KEY_VALUE(CERTIFICATE_REQUIRED, 116) \ + _ENUM_KEY_VALUE(NO_APPLICATION_PROTOCOL, 120) + +enum class AlertDescription : u8 { + __ENUM_ALERT_DESCRIPTIONS +}; + #undef _ENUM_KEY #undef _ENUM_KEY_VALUE +constexpr static StringView enum_to_string(AlertDescription descriptor) +{ +#define _ENUM_KEY_VALUE(name, value) \ + case AlertDescription::name: \ + return #name##sv; + + switch (descriptor) { + __ENUM_ALERT_DESCRIPTIONS + } + + return "Unknown"sv; +#undef _ENUM_KEY_VALUE +} + } diff --git a/Userland/Libraries/LibTLS/Handshake.cpp b/Userland/Libraries/LibTLS/Handshake.cpp index 002b1bee4c..c654eeb9fd 100644 --- a/Userland/Libraries/LibTLS/Handshake.cpp +++ b/Userland/Libraries/LibTLS/Handshake.cpp @@ -424,58 +424,58 @@ ssize_t TLSv12::handle_handshake_payload(ReadonlyBytes vbuffer) if (payload_res < 0) { switch ((Error)payload_res) { case Error::UnexpectedMessage: { - auto packet = build_alert(true, (u8)AlertDescription::UnexpectedMessage); + auto packet = build_alert(true, (u8)AlertDescription::UNEXPECTED_MESSAGE); write_packet(packet); break; } case Error::CompressionNotSupported: { - auto packet = build_alert(true, (u8)AlertDescription::DecompressionFailure); + auto packet = build_alert(true, (u8)AlertDescription::DECOMPRESSION_FAILURE_RESERVED); write_packet(packet); break; } case Error::BrokenPacket: { - auto packet = build_alert(true, (u8)AlertDescription::DecodeError); + auto packet = build_alert(true, (u8)AlertDescription::DECODE_ERROR); write_packet(packet); break; } case Error::NotVerified: { - auto packet = build_alert(true, (u8)AlertDescription::BadRecordMAC); + auto packet = build_alert(true, (u8)AlertDescription::BAD_RECORD_MAC); write_packet(packet); break; } case Error::BadCertificate: { - auto packet = build_alert(true, (u8)AlertDescription::BadCertificate); + auto packet = build_alert(true, (u8)AlertDescription::BAD_CERTIFICATE); write_packet(packet); break; } case Error::UnsupportedCertificate: { - auto packet = build_alert(true, (u8)AlertDescription::UnsupportedCertificate); + auto packet = build_alert(true, (u8)AlertDescription::UNSUPPORTED_CERTIFICATE); write_packet(packet); break; } case Error::NoCommonCipher: { - auto packet = build_alert(true, (u8)AlertDescription::InsufficientSecurity); + auto packet = build_alert(true, (u8)AlertDescription::INSUFFICIENT_SECURITY); write_packet(packet); break; } case Error::NotUnderstood: case Error::OutOfMemory: { - auto packet = build_alert(true, (u8)AlertDescription::InternalError); + auto packet = build_alert(true, (u8)AlertDescription::INTERNAL_ERROR); write_packet(packet); break; } case Error::NoRenegotiation: { - auto packet = build_alert(true, (u8)AlertDescription::NoRenegotiation); + auto packet = build_alert(true, (u8)AlertDescription::NO_RENEGOTIATION_RESERVED); write_packet(packet); break; } case Error::DecryptionFailed: { - auto packet = build_alert(true, (u8)AlertDescription::DecryptionFailed); + auto packet = build_alert(true, (u8)AlertDescription::DECRYPTION_FAILED_RESERVED); write_packet(packet); break; } case Error::NotSafe: { - auto packet = build_alert(true, (u8)AlertDescription::DecryptError); + auto packet = build_alert(true, (u8)AlertDescription::DECRYPT_ERROR); write_packet(packet); break; } diff --git a/Userland/Libraries/LibTLS/HandshakeClient.cpp b/Userland/Libraries/LibTLS/HandshakeClient.cpp index 892c4ba1a2..70f02f0344 100644 --- a/Userland/Libraries/LibTLS/HandshakeClient.cpp +++ b/Userland/Libraries/LibTLS/HandshakeClient.cpp @@ -365,7 +365,7 @@ ByteBuffer TLSv12::build_client_key_exchange() bool chain_verified = m_context.verify_chain(m_context.extensions.SNI); if (!chain_verified) { dbgln("certificate verification failed :("); - alert(AlertLevel::FATAL, AlertDescription::BadCertificate); + alert(AlertLevel::FATAL, AlertDescription::BAD_CERTIFICATE); return {}; } diff --git a/Userland/Libraries/LibTLS/Record.cpp b/Userland/Libraries/LibTLS/Record.cpp index 8dbe3ae028..729d936f4b 100644 --- a/Userland/Libraries/LibTLS/Record.cpp +++ b/Userland/Libraries/LibTLS/Record.cpp @@ -359,7 +359,7 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer) VERIFY(is_aead()); if (length < 24) { dbgln("Invalid packet length"); - auto packet = build_alert(true, (u8)AlertDescription::DecryptError); + auto packet = build_alert(true, (u8)AlertDescription::DECRYPT_ERROR); write_packet(packet); return_value = Error::BrokenPacket; return; @@ -418,7 +418,7 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer) if (consistency != Crypto::VerificationConsistency::Consistent) { dbgln("integrity check failed (tag length {})", tag.size()); - auto packet = build_alert(true, (u8)AlertDescription::BadRecordMAC); + auto packet = build_alert(true, (u8)AlertDescription::BAD_RECORD_MAC); write_packet(packet); return_value = Error::IntegrityCheckFailed; @@ -453,7 +453,7 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer) auto mac_size = mac_length(); if (length < mac_size) { dbgln("broken packet"); - auto packet = build_alert(true, (u8)AlertDescription::DecryptError); + auto packet = build_alert(true, (u8)AlertDescription::DECRYPT_ERROR); write_packet(packet); return_value = Error::BrokenPacket; return; @@ -473,7 +473,7 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer) print_buffer(message_mac); dbgln("mac computed:"); print_buffer(hmac); - auto packet = build_alert(true, (u8)AlertDescription::BadRecordMAC); + auto packet = build_alert(true, (u8)AlertDescription::BAD_RECORD_MAC); write_packet(packet); return_value = Error::IntegrityCheckFailed; @@ -493,14 +493,14 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer) if (m_context.connection_status != ConnectionStatus::Established) { dbgln("unexpected application data"); payload_res = (i8)Error::UnexpectedMessage; - auto packet = build_alert(true, (u8)AlertDescription::UnexpectedMessage); + auto packet = build_alert(true, (u8)AlertDescription::UNEXPECTED_MESSAGE); write_packet(packet); } else { dbgln_if(TLS_DEBUG, "application data message of size {}", plain.size()); if (m_context.application_buffer.try_append(plain.data(), plain.size()).is_error()) { payload_res = (i8)Error::DecryptionFailed; - auto packet = build_alert(true, (u8)AlertDescription::DecryptionFailed); + auto packet = build_alert(true, (u8)AlertDescription::DECRYPTION_FAILED_RESERVED); write_packet(packet); } } @@ -512,7 +512,7 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer) case ContentType::CHANGE_CIPHER_SPEC: if (m_context.connection_status != ConnectionStatus::KeyExchange) { dbgln("unexpected change cipher message"); - auto packet = build_alert(true, (u8)AlertDescription::UnexpectedMessage); + auto packet = build_alert(true, (u8)AlertDescription::UNEXPECTED_MESSAGE); write_packet(packet); payload_res = (i8)Error::UnexpectedMessage; } else { @@ -532,19 +532,19 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer) dbgln_if(TLS_DEBUG, "Alert received with level {}, code {}", level, code); if (level == (u8)AlertLevel::FATAL) { - dbgln("We were alerted of a critical error: {} ({})", code, alert_name((AlertDescription)code)); + dbgln("We were alerted of a critical error: {} ({})", code, enum_to_string((AlertDescription)code)); m_context.critical_error = code; try_disambiguate_error(); res = (i8)Error::UnknownError; } - if (code == (u8)AlertDescription::CloseNotify) { + if (code == (u8)AlertDescription::CLOSE_NOTIFY) { res += 2; - alert(AlertLevel::FATAL, AlertDescription::CloseNotify); + alert(AlertLevel::FATAL, AlertDescription::CLOSE_NOTIFY); if (!m_context.cipher_spec_set) { // AWS CloudFront hits this. dbgln("Server sent a close notify and we haven't agreed on a cipher suite. Treating it as a handshake failure."); - m_context.critical_error = (u8)AlertDescription::HandshakeFailure; + m_context.critical_error = (u8)AlertDescription::HANDSHAKE_FAILURE; try_disambiguate_error(); } m_context.close_notify = true; diff --git a/Userland/Libraries/LibTLS/Socket.cpp b/Userland/Libraries/LibTLS/Socket.cpp index 43f231efd0..be0681b28c 100644 --- a/Userland/Libraries/LibTLS/Socket.cpp +++ b/Userland/Libraries/LibTLS/Socket.cpp @@ -91,7 +91,7 @@ ErrorOr> TLSv12::connect(DeprecatedString const& host, u16 tls_socket->try_disambiguate_error(); // FIXME: Should return richer information here. - return AK::Error::from_string_view(alert_name(static_cast(256 - result))); + return AK::Error::from_string_view(enum_to_string(static_cast(256 - result))); } ErrorOr> TLSv12::connect(DeprecatedString const& host, Core::Socket& underlying_stream, Options options) @@ -112,7 +112,7 @@ ErrorOr> TLSv12::connect(DeprecatedString const& host, Cor tls_socket->try_disambiguate_error(); // FIXME: Should return richer information here. - return AK::Error::from_string_view(alert_name(static_cast(256 - result))); + return AK::Error::from_string_view(enum_to_string(static_cast(256 - result))); } void TLSv12::setup_connection() @@ -135,7 +135,7 @@ void TLSv12::setup_connection() if (timeout_diff < m_max_wait_time_for_handshake_in_seconds + 1) { // The server did not respond fast enough, // time the connection out. - alert(AlertLevel::FATAL, AlertDescription::UserCanceled); + alert(AlertLevel::FATAL, AlertDescription::USER_CANCELED); m_context.tls_buffer.clear(); m_context.error_code = Error::TimedOut; m_context.critical_error = (u8)Error::TimedOut; @@ -317,7 +317,7 @@ ErrorOr TLSv12::flush() void TLSv12::close() { - alert(AlertLevel::FATAL, AlertDescription::CloseNotify); + alert(AlertLevel::FATAL, AlertDescription::CLOSE_NOTIFY); // bye bye. m_context.connection_status = ConnectionStatus::Disconnected; } diff --git a/Userland/Libraries/LibTLS/TLSv12.cpp b/Userland/Libraries/LibTLS/TLSv12.cpp index ff01c9acfd..b598a24b62 100644 --- a/Userland/Libraries/LibTLS/TLSv12.cpp +++ b/Userland/Libraries/LibTLS/TLSv12.cpp @@ -138,55 +138,55 @@ void TLSv12::try_disambiguate_error() const { dbgln("Possible failure cause(s): "); switch ((AlertDescription)m_context.critical_error) { - case AlertDescription::HandshakeFailure: + case AlertDescription::HANDSHAKE_FAILURE: if (!m_context.cipher_spec_set) { dbgln("- No cipher suite in common with {}", m_context.extensions.SNI); } else { dbgln("- Unknown internal issue"); } break; - case AlertDescription::InsufficientSecurity: + case AlertDescription::INSUFFICIENT_SECURITY: dbgln("- No cipher suite in common with {} (the server is oh so secure)", m_context.extensions.SNI); break; - case AlertDescription::ProtocolVersion: + case AlertDescription::PROTOCOL_VERSION: dbgln("- The server refused to negotiate with TLS 1.2 :("); break; - case AlertDescription::UnexpectedMessage: + case AlertDescription::UNEXPECTED_MESSAGE: dbgln("- We sent an invalid message for the state we're in."); break; - case AlertDescription::BadRecordMAC: + case AlertDescription::BAD_RECORD_MAC: dbgln("- Bad MAC record from our side."); dbgln("- Ciphertext wasn't an even multiple of the block length."); dbgln("- Bad block cipher padding."); dbgln("- If both sides are compliant, the only cause is messages being corrupted in the network."); break; - case AlertDescription::RecordOverflow: + case AlertDescription::RECORD_OVERFLOW: dbgln("- Sent a ciphertext record which has a length bigger than 18432 bytes."); dbgln("- Sent record decrypted to a compressed record that has a length bigger than 18432 bytes."); dbgln("- If both sides are compliant, the only cause is messages being corrupted in the network."); break; - case AlertDescription::DecompressionFailure: + case AlertDescription::DECOMPRESSION_FAILURE_RESERVED: dbgln("- We sent invalid input for decompression (e.g. data that would expand to excessive length)"); break; - case AlertDescription::IllegalParameter: + case AlertDescription::ILLEGAL_PARAMETER: dbgln("- We sent a parameter in the handshake that is out of range or inconsistent with the other parameters."); break; - case AlertDescription::DecodeError: + case AlertDescription::DECODE_ERROR: dbgln("- The message we sent cannot be decoded because a field was out of range or the length was incorrect."); dbgln("- If both sides are compliant, the only cause is messages being corrupted in the network."); break; - case AlertDescription::DecryptError: + case AlertDescription::DECRYPT_ERROR: dbgln("- A handshake crypto operation failed. This includes signature verification and validating Finished."); break; - case AlertDescription::AccessDenied: + case AlertDescription::ACCESS_DENIED: dbgln("- The certificate is valid, but once access control was applied, the sender decided to stop negotiation."); break; - case AlertDescription::InternalError: + case AlertDescription::INTERNAL_ERROR: dbgln("- No one knows, but it isn't a protocol failure."); break; - case AlertDescription::DecryptionFailed: - case AlertDescription::NoCertificate: - case AlertDescription::ExportRestriction: + case AlertDescription::DECRYPTION_FAILED_RESERVED: + case AlertDescription::NO_CERTIFICATE_RESERVED: + case AlertDescription::EXPORT_RESTRICTION_RESERVED: dbgln("- No one knows, the server sent a non-compliant alert."); break; default: diff --git a/Userland/Libraries/LibTLS/TLSv12.h b/Userland/Libraries/LibTLS/TLSv12.h index 42ec5d0d87..f84923869c 100644 --- a/Userland/Libraries/LibTLS/TLSv12.h +++ b/Userland/Libraries/LibTLS/TLSv12.h @@ -40,55 +40,6 @@ inline void print_buffer(u8 const* buffer, size_t size) class Socket; -#define ENUMERATE_ALERT_DESCRIPTIONS \ - ENUMERATE_ALERT_DESCRIPTION(CloseNotify, 0) \ - ENUMERATE_ALERT_DESCRIPTION(UnexpectedMessage, 10) \ - ENUMERATE_ALERT_DESCRIPTION(BadRecordMAC, 20) \ - ENUMERATE_ALERT_DESCRIPTION(DecryptionFailed, 21) \ - ENUMERATE_ALERT_DESCRIPTION(RecordOverflow, 22) \ - ENUMERATE_ALERT_DESCRIPTION(DecompressionFailure, 30) \ - ENUMERATE_ALERT_DESCRIPTION(HandshakeFailure, 40) \ - ENUMERATE_ALERT_DESCRIPTION(NoCertificate, 41) \ - ENUMERATE_ALERT_DESCRIPTION(BadCertificate, 42) \ - ENUMERATE_ALERT_DESCRIPTION(UnsupportedCertificate, 43) \ - ENUMERATE_ALERT_DESCRIPTION(CertificateRevoked, 44) \ - ENUMERATE_ALERT_DESCRIPTION(CertificateExpired, 45) \ - ENUMERATE_ALERT_DESCRIPTION(CertificateUnknown, 46) \ - ENUMERATE_ALERT_DESCRIPTION(IllegalParameter, 47) \ - ENUMERATE_ALERT_DESCRIPTION(UnknownCA, 48) \ - ENUMERATE_ALERT_DESCRIPTION(AccessDenied, 49) \ - ENUMERATE_ALERT_DESCRIPTION(DecodeError, 50) \ - ENUMERATE_ALERT_DESCRIPTION(DecryptError, 51) \ - ENUMERATE_ALERT_DESCRIPTION(ExportRestriction, 60) \ - ENUMERATE_ALERT_DESCRIPTION(ProtocolVersion, 70) \ - ENUMERATE_ALERT_DESCRIPTION(InsufficientSecurity, 71) \ - ENUMERATE_ALERT_DESCRIPTION(InternalError, 80) \ - ENUMERATE_ALERT_DESCRIPTION(InappropriateFallback, 86) \ - ENUMERATE_ALERT_DESCRIPTION(UserCanceled, 90) \ - ENUMERATE_ALERT_DESCRIPTION(NoRenegotiation, 100) \ - ENUMERATE_ALERT_DESCRIPTION(UnsupportedExtension, 110) \ - ENUMERATE_ALERT_DESCRIPTION(NoError, 255) - -enum class AlertDescription : u8 { -#define ENUMERATE_ALERT_DESCRIPTION(name, value) name = value, - ENUMERATE_ALERT_DESCRIPTIONS -#undef ENUMERATE_ALERT_DESCRIPTION -}; - -constexpr static StringView alert_name(AlertDescription descriptor) -{ -#define ENUMERATE_ALERT_DESCRIPTION(name, value) \ - case AlertDescription::name: \ - return #name##sv; - - switch (descriptor) { - ENUMERATE_ALERT_DESCRIPTIONS - } - - return "Unknown"sv; -#undef ENUMERATE_ALERT_DESCRIPTION -} - enum class Error : i8 { NoError = 0, UnknownError = -1, diff --git a/Userland/Services/RequestServer/ConnectionCache.h b/Userland/Services/RequestServer/ConnectionCache.h index 01298a4a3a..24bd516bb7 100644 --- a/Userland/Services/RequestServer/ConnectionCache.h +++ b/Userland/Services/RequestServer/ConnectionCache.h @@ -146,9 +146,9 @@ ErrorOr recreate_socket_if_needed(T& connection, URL const& url) TLS::Options options; options.set_alert_handler([&connection](TLS::AlertDescription alert) { Core::NetworkJob::Error reason; - if (alert == TLS::AlertDescription::HandshakeFailure) + if (alert == TLS::AlertDescription::HANDSHAKE_FAILURE) reason = Core::NetworkJob::Error::ProtocolFailed; - else if (alert == TLS::AlertDescription::DecryptError) + else if (alert == TLS::AlertDescription::DECRYPT_ERROR) reason = Core::NetworkJob::Error::ConnectionFailed; else reason = Core::NetworkJob::Error::TransmissionFailed;