LibTLS: Move AlertDescription to Extensions.h

Also add missing values from the IANA registry
This commit is contained in:
stelar7 2023-04-14 00:43:25 +02:00 committed by Sam Atkins
parent e8945f15f4
commit 5853d9642a
Notes: sideshowbarker 2024-07-17 07:38:17 +09:00
8 changed files with 100 additions and 93 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -91,7 +91,7 @@ ErrorOr<NonnullOwnPtr<TLSv12>> 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<AlertDescription>(256 - result)));
return AK::Error::from_string_view(enum_to_string(static_cast<AlertDescription>(256 - result)));
}
ErrorOr<NonnullOwnPtr<TLSv12>> TLSv12::connect(DeprecatedString const& host, Core::Socket& underlying_stream, Options options)
@ -112,7 +112,7 @@ ErrorOr<NonnullOwnPtr<TLSv12>> 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<AlertDescription>(256 - result)));
return AK::Error::from_string_view(enum_to_string(static_cast<AlertDescription>(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<bool> TLSv12::flush()
void TLSv12::close()
{
alert(AlertLevel::FATAL, AlertDescription::CloseNotify);
alert(AlertLevel::FATAL, AlertDescription::CLOSE_NOTIFY);
// bye bye.
m_context.connection_status = ConnectionStatus::Disconnected;
}

View File

@ -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:

View File

@ -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,

View File

@ -146,9 +146,9 @@ ErrorOr<void> 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;