diff --git a/Libraries/LibTLS/CMakeLists.txt b/Libraries/LibTLS/CMakeLists.txt index 6af75ed4a07..68c833205c7 100644 --- a/Libraries/LibTLS/CMakeLists.txt +++ b/Libraries/LibTLS/CMakeLists.txt @@ -2,12 +2,6 @@ add_cxx_compile_options(-Wvla) set(SOURCES DefaultRootCACertificates.cpp - Handshake.cpp - HandshakeCertificate.cpp - HandshakeClient.cpp - HandshakeServer.cpp - Record.cpp - Socket.cpp TLSv12.cpp ) @@ -15,3 +9,6 @@ serenity_lib(LibTLS tls) target_link_libraries(LibTLS PRIVATE LibCore LibCrypto LibFileSystem) include(ca_certificates_data) + +find_package(OpenSSL REQUIRED) +target_link_libraries(LibTLS PUBLIC OpenSSL::SSL) diff --git a/Libraries/LibTLS/CipherSuite.h b/Libraries/LibTLS/CipherSuite.h deleted file mode 100644 index 8f446b58116..00000000000 --- a/Libraries/LibTLS/CipherSuite.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace TLS { - -// Defined in RFC 5246 section 7.4.1.4.1 -struct SignatureAndHashAlgorithm { - HashAlgorithm hash; - SignatureAlgorithm signature; -}; - -enum class KeyExchangeAlgorithm { - Invalid, - // Defined in RFC 5246 section 7.4.2 / RFC 4279 section 4 - RSA_PSK, - // Defined in RFC 5246 section 7.4.3 - DHE_DSS, - DHE_RSA, - DH_anon, - RSA, - DH_DSS, - DH_RSA, - // Defined in RFC 4492 section 2 - ECDHE_RSA, - ECDH_ECDSA, - ECDH_RSA, - ECDHE_ECDSA, - ECDH_anon, -}; - -// Defined in RFC 5246 section 7.4.1.4.1 -constexpr SignatureAlgorithm signature_for_key_exchange_algorithm(KeyExchangeAlgorithm algorithm) -{ - switch (algorithm) { - case KeyExchangeAlgorithm::RSA: - case KeyExchangeAlgorithm::DHE_RSA: - case KeyExchangeAlgorithm::DH_RSA: - case KeyExchangeAlgorithm::RSA_PSK: - case KeyExchangeAlgorithm::ECDH_RSA: - case KeyExchangeAlgorithm::ECDHE_RSA: - return SignatureAlgorithm::RSA; - case KeyExchangeAlgorithm::DHE_DSS: - case KeyExchangeAlgorithm::DH_DSS: - return SignatureAlgorithm::DSA; - case KeyExchangeAlgorithm::ECDH_ECDSA: - case KeyExchangeAlgorithm::ECDHE_ECDSA: - return SignatureAlgorithm::ECDSA; - case KeyExchangeAlgorithm::DH_anon: - case KeyExchangeAlgorithm::ECDH_anon: - default: - return SignatureAlgorithm::ANONYMOUS; - } -} - -enum class CipherAlgorithm { - Invalid, - AES_128_CBC, - AES_128_GCM, - AES_128_CCM, - AES_128_CCM_8, - AES_256_CBC, - AES_256_GCM, -}; - -constexpr size_t cipher_key_size(CipherAlgorithm algorithm) -{ - switch (algorithm) { - case CipherAlgorithm::AES_128_CBC: - case CipherAlgorithm::AES_128_GCM: - case CipherAlgorithm::AES_128_CCM: - case CipherAlgorithm::AES_128_CCM_8: - return 128; - case CipherAlgorithm::AES_256_CBC: - case CipherAlgorithm::AES_256_GCM: - return 256; - case CipherAlgorithm::Invalid: - default: - return 0; - } -} - -} diff --git a/Libraries/LibTLS/Extensions.h b/Libraries/LibTLS/Extensions.h deleted file mode 100644 index 9911eae379c..00000000000 --- a/Libraries/LibTLS/Extensions.h +++ /dev/null @@ -1,981 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * Copyright (c) 2023, stelar7 - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace TLS { - -#define _ENUM_KEY(name) name, -#define _ENUM_KEY_VALUE(name, value) name = value, - -// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-5 -#define __ENUM_CONTENT_TYPES \ - _ENUM_KEY_VALUE(CHANGE_CIPHER_SPEC, 20) \ - _ENUM_KEY_VALUE(ALERT, 21) \ - _ENUM_KEY_VALUE(HANDSHAKE, 22) \ - _ENUM_KEY_VALUE(APPLICATION_DATA, 23) \ - _ENUM_KEY_VALUE(HEARTBEAT, 24) \ - _ENUM_KEY_VALUE(TLS12_CID, 25) \ - _ENUM_KEY_VALUE(ACK, 26) - -enum class ContentType : u8 { - __ENUM_CONTENT_TYPES -}; - -#define __ENUM_PROTOCOL_VERSIONS \ - _ENUM_KEY_VALUE(VERSION_1_3, 0x0304) \ - _ENUM_KEY_VALUE(VERSION_1_2, 0x0303) \ - _ENUM_KEY_VALUE(VERSION_1_1, 0x0302) \ - _ENUM_KEY_VALUE(VERSION_1_0, 0x0301) \ - _ENUM_KEY_VALUE(GREASE_0, 0x0A0A) \ - _ENUM_KEY_VALUE(GREASE_1, 0x1A1A) \ - _ENUM_KEY_VALUE(GREASE_2, 0x2A2A) \ - _ENUM_KEY_VALUE(GREASE_3, 0x3A3A) \ - _ENUM_KEY_VALUE(GREASE_4, 0x4A4A) \ - _ENUM_KEY_VALUE(GREASE_5, 0x5A5A) \ - _ENUM_KEY_VALUE(GREASE_6, 0x6A6A) \ - _ENUM_KEY_VALUE(GREASE_7, 0x7A7A) \ - _ENUM_KEY_VALUE(GREASE_8, 0x8A8A) \ - _ENUM_KEY_VALUE(GREASE_9, 0x9A9A) \ - _ENUM_KEY_VALUE(GREASE_A, 0xAAAA) \ - _ENUM_KEY_VALUE(GREASE_B, 0xBABA) \ - _ENUM_KEY_VALUE(GREASE_C, 0xCACA) \ - _ENUM_KEY_VALUE(GREASE_D, 0xDADA) \ - _ENUM_KEY_VALUE(GREASE_E, 0xEAEA) \ - _ENUM_KEY_VALUE(GREASE_F, 0xFAFA) - -enum class ProtocolVersion : u16 { - __ENUM_PROTOCOL_VERSIONS -}; - -#define __ENUM_ALERT_LEVELS \ - _ENUM_KEY_VALUE(WARNING, 1) \ - _ENUM_KEY_VALUE(FATAL, 2) - -enum class AlertLevel : u8 { - __ENUM_ALERT_LEVELS -}; - -// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-7 -#define __ENUM_HANDSHAKE_TYPES \ - _ENUM_KEY_VALUE(HELLO_REQUEST_RESERVED, 0) \ - _ENUM_KEY_VALUE(CLIENT_HELLO, 1) \ - _ENUM_KEY_VALUE(SERVER_HELLO, 2) \ - _ENUM_KEY_VALUE(HELLO_VERIFY_REQUEST_RESERVED, 3) \ - _ENUM_KEY_VALUE(NEW_SESSION_TICKET, 4) \ - _ENUM_KEY_VALUE(END_OF_EARLY_DATA, 5) \ - _ENUM_KEY_VALUE(HELLO_RETRY_REQUEST_RESERVED, 6) \ - _ENUM_KEY_VALUE(ENCRYPTED_EXTENSIONS, 8) \ - _ENUM_KEY_VALUE(REQUEST_CONNECTION_ID, 9) \ - _ENUM_KEY_VALUE(NEW_CONNECTION_ID, 10) \ - _ENUM_KEY_VALUE(CERTIFICATE, 11) \ - _ENUM_KEY_VALUE(SERVER_KEY_EXCHANGE_RESERVED, 12) \ - _ENUM_KEY_VALUE(CERTIFICATE_REQUEST, 13) \ - _ENUM_KEY_VALUE(SERVER_HELLO_DONE_RESERVED, 14) \ - _ENUM_KEY_VALUE(CERTIFICATE_VERIFY, 15) \ - _ENUM_KEY_VALUE(CLIENT_KEY_EXCHANGE_RESERVED, 16) \ - _ENUM_KEY_VALUE(FINISHED, 20) \ - _ENUM_KEY_VALUE(CERTIFICATE_URL_RESERVED, 21) \ - _ENUM_KEY_VALUE(CERTIFICATE_STATUS_RESERVED, 22) \ - _ENUM_KEY_VALUE(SUPPLEMENTAL_DATA_RESERVED, 23) \ - _ENUM_KEY_VALUE(KEY_UPDATE, 24) \ - _ENUM_KEY_VALUE(COMPRESSED_CERTIFICATE, 25) \ - _ENUM_KEY_VALUE(EKT_KEY, 26) \ - _ENUM_KEY_VALUE(MESSAGE_HASH, 254) - -enum class HandshakeType : u8 { - __ENUM_HANDSHAKE_TYPES -}; - -// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-1 -#define __ENUM_EXTENSION_TYPES \ - _ENUM_KEY_VALUE(SERVER_NAME, 0) \ - _ENUM_KEY_VALUE(MAX_FRAGMENT_LENGTH, 1) \ - _ENUM_KEY_VALUE(CLIENT_CERTIFICATE_URL, 2) \ - _ENUM_KEY_VALUE(TRUSTED_CA_KEYS, 3) \ - _ENUM_KEY_VALUE(TRUNCATED_HMAC, 4) \ - _ENUM_KEY_VALUE(STATUS_REQUEST, 5) \ - _ENUM_KEY_VALUE(USER_MAPPING, 6) \ - _ENUM_KEY_VALUE(CLIENT_AUTHZ, 7) \ - _ENUM_KEY_VALUE(SERVER_AUTHZ, 8) \ - _ENUM_KEY_VALUE(CERT_TYPE, 9) \ - _ENUM_KEY_VALUE(SUPPORTED_GROUPS, 10) \ - _ENUM_KEY_VALUE(EC_POINT_FORMATS, 11) \ - _ENUM_KEY_VALUE(SRP, 12) \ - _ENUM_KEY_VALUE(SIGNATURE_ALGORITHMS, 13) \ - _ENUM_KEY_VALUE(USE_SRTP, 14) \ - _ENUM_KEY_VALUE(HEARTBEAT, 15) \ - _ENUM_KEY_VALUE(APPLICATION_LAYER_PROTOCOL_NEGOTIATION, 16) \ - _ENUM_KEY_VALUE(STATUS_REQUEST_V2, 17) \ - _ENUM_KEY_VALUE(SIGNED_CERTIFICATE_TIMESTAMP, 18) \ - _ENUM_KEY_VALUE(CLIENT_CERTIFICATE_TYPE, 19) \ - _ENUM_KEY_VALUE(SERVER_CERTIFICATE_TYPE, 20) \ - _ENUM_KEY_VALUE(PADDING, 21) \ - _ENUM_KEY_VALUE(ENCRYPT_THEN_MAC, 22) \ - _ENUM_KEY_VALUE(EXTENDED_MASTER_SECRET, 23) \ - _ENUM_KEY_VALUE(TOKEN_BINDING, 24) \ - _ENUM_KEY_VALUE(CACHED_INFO, 25) \ - _ENUM_KEY_VALUE(TLS_LTS, 26) \ - _ENUM_KEY_VALUE(COMPRESS_CERTIFICATE, 27) \ - _ENUM_KEY_VALUE(RECORD_SIZE_LIMIT, 28) \ - _ENUM_KEY_VALUE(PWD_PROTECT, 29) \ - _ENUM_KEY_VALUE(PWD_CLEAR, 30) \ - _ENUM_KEY_VALUE(PASSWORD_SALT, 31) \ - _ENUM_KEY_VALUE(TICKET_PINNING, 32) \ - _ENUM_KEY_VALUE(TLS_CERT_WITH_EXTERN_PSK, 33) \ - _ENUM_KEY_VALUE(DELEGATED_CREDENTIALS, 34) \ - _ENUM_KEY_VALUE(SESSION_TICKET, 35) \ - _ENUM_KEY_VALUE(TLMSP, 36) \ - _ENUM_KEY_VALUE(TLMSP_PROXYING, 37) \ - _ENUM_KEY_VALUE(TLMSP_DELEGATE, 38) \ - _ENUM_KEY_VALUE(SUPPORTED_EKT_CIPHERS, 39) \ - _ENUM_KEY_VALUE(PRE_SHARED_KEY, 41) \ - _ENUM_KEY_VALUE(EARLY_DATA, 42) \ - _ENUM_KEY_VALUE(SUPPORTED_VERSIONS, 43) \ - _ENUM_KEY_VALUE(COOKIE, 44) \ - _ENUM_KEY_VALUE(PSK_KEY_EXCHANGE_MODES, 45) \ - _ENUM_KEY_VALUE(CERTIFICATE_AUTHORITIES, 47) \ - _ENUM_KEY_VALUE(OID_FILTERS, 48) \ - _ENUM_KEY_VALUE(POST_HANDSHAKE_AUTH, 49) \ - _ENUM_KEY_VALUE(SIGNATURE_ALGORITHMS_CERT, 50) \ - _ENUM_KEY_VALUE(KEY_SHARE, 51) \ - _ENUM_KEY_VALUE(TRANSPARENCY_INFO, 52) \ - _ENUM_KEY_VALUE(CONNECTION_ID_DEPRECATED, 53) \ - _ENUM_KEY_VALUE(CONNECTION_ID, 54) \ - _ENUM_KEY_VALUE(EXTERNAL_ID_HASH, 55) \ - _ENUM_KEY_VALUE(EXTERNAL_SESSION_ID, 56) \ - _ENUM_KEY_VALUE(QUIC_TRANSPORT_PARAMETERS, 57) \ - _ENUM_KEY_VALUE(TICKET_REQUEST, 58) \ - _ENUM_KEY_VALUE(DNSSEC_CHAIN, 59) \ - _ENUM_KEY_VALUE(RENEGOTIATION_INFO, 65281) - -enum class ExtensionType : u16 { - __ENUM_EXTENSION_TYPES -}; - -#define __ENUM_NAME_TYPES \ - _ENUM_KEY_VALUE(HOST_NAME, 0) - -enum class NameType : u8 { - __ENUM_NAME_TYPES -}; - -// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-10 -#define __ENUM_EC_CURVE_TYPES \ - _ENUM_KEY_VALUE(EXPLICIT_PRIME, 1) \ - _ENUM_KEY_VALUE(EXPLICIT_CHAR2, 2) \ - _ENUM_KEY_VALUE(NAMED_CURVE, 3) - -enum class ECCurveType : u8 { - __ENUM_EC_CURVE_TYPES -}; - -// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 -#define __ENUM_SUPPORTED_GROUPS \ - _ENUM_KEY_VALUE(SECT163K1, 0x0001) \ - _ENUM_KEY_VALUE(SECT163R1, 0x0002) \ - _ENUM_KEY_VALUE(SECT163R2, 0x0003) \ - _ENUM_KEY_VALUE(SECT193R1, 0x0004) \ - _ENUM_KEY_VALUE(SECT193R2, 0x0005) \ - _ENUM_KEY_VALUE(SECT233K1, 0x0006) \ - _ENUM_KEY_VALUE(SECT233R1, 0x0007) \ - _ENUM_KEY_VALUE(SECT239K1, 0x0008) \ - _ENUM_KEY_VALUE(SECT283K1, 0x0009) \ - _ENUM_KEY_VALUE(SECT283R1, 0x000a) \ - _ENUM_KEY_VALUE(SECT409K1, 0x000b) \ - _ENUM_KEY_VALUE(SECT409R1, 0x000c) \ - _ENUM_KEY_VALUE(SECT571K1, 0x000d) \ - _ENUM_KEY_VALUE(SECT571R1, 0x000e) \ - _ENUM_KEY_VALUE(SECP160K1, 0x000f) \ - _ENUM_KEY_VALUE(SECP160R1, 0x0010) \ - _ENUM_KEY_VALUE(SECP160R2, 0x0011) \ - _ENUM_KEY_VALUE(SECP192K1, 0x0012) \ - _ENUM_KEY_VALUE(SECP192R1, 0x0013) \ - _ENUM_KEY_VALUE(SECP224K1, 0x0014) \ - _ENUM_KEY_VALUE(SECP224R1, 0x0015) \ - _ENUM_KEY_VALUE(SECP256K1, 0x0016) \ - _ENUM_KEY_VALUE(SECP256R1, 0x0017) \ - _ENUM_KEY_VALUE(SECP384R1, 0x0018) \ - _ENUM_KEY_VALUE(SECP521R1, 0x0019) \ - _ENUM_KEY_VALUE(BRAINPOOLP256R1, 0x001a) \ - _ENUM_KEY_VALUE(BRAINPOOLP384R1, 0x001b) \ - _ENUM_KEY_VALUE(BRAINPOOLP512R1, 0x001c) \ - _ENUM_KEY_VALUE(X25519, 0x001d) \ - _ENUM_KEY_VALUE(X448, 0x001e) \ - _ENUM_KEY_VALUE(BRAINPOOLP256R1TLS13, 0x001f) \ - _ENUM_KEY_VALUE(BRAINPOOLP384R1TLS13, 0x0020) \ - _ENUM_KEY_VALUE(BRAINPOOLP512R1TLS13, 0x0021) \ - _ENUM_KEY_VALUE(GC256A, 0x0022) \ - _ENUM_KEY_VALUE(GC256B, 0x0023) \ - _ENUM_KEY_VALUE(GC256C, 0x0024) \ - _ENUM_KEY_VALUE(GC256D, 0x0025) \ - _ENUM_KEY_VALUE(GC512A, 0x0026) \ - _ENUM_KEY_VALUE(GC512B, 0x0027) \ - _ENUM_KEY_VALUE(GC512C, 0x0028) \ - _ENUM_KEY_VALUE(CURVESM2, 0x0029) \ - _ENUM_KEY_VALUE(FFDHE2048, 0x0100) \ - _ENUM_KEY_VALUE(FFDHE3072, 0x0101) \ - _ENUM_KEY_VALUE(FFDHE4096, 0x0102) \ - _ENUM_KEY_VALUE(FFDHE6144, 0x0103) \ - _ENUM_KEY_VALUE(FFDHE8192, 0x0104) \ - _ENUM_KEY_VALUE(ARBITRARY_EXPLICIT_PRIME_CURVES, 0xff01) \ - _ENUM_KEY_VALUE(ARBITRARY_EXPLICIT_CHAR2_CURVES, 0xff02) \ - _ENUM_KEY_VALUE(GREASE_0, 0x0A0A) \ - _ENUM_KEY_VALUE(GREASE_1, 0x1A1A) \ - _ENUM_KEY_VALUE(GREASE_2, 0x2A2A) \ - _ENUM_KEY_VALUE(GREASE_3, 0x3A3A) \ - _ENUM_KEY_VALUE(GREASE_4, 0x4A4A) \ - _ENUM_KEY_VALUE(GREASE_5, 0x5A5A) \ - _ENUM_KEY_VALUE(GREASE_6, 0x6A6A) \ - _ENUM_KEY_VALUE(GREASE_7, 0x7A7A) \ - _ENUM_KEY_VALUE(GREASE_8, 0x8A8A) \ - _ENUM_KEY_VALUE(GREASE_9, 0x9A9A) \ - _ENUM_KEY_VALUE(GREASE_A, 0xAAAA) \ - _ENUM_KEY_VALUE(GREASE_B, 0xBABA) \ - _ENUM_KEY_VALUE(GREASE_C, 0xCACA) \ - _ENUM_KEY_VALUE(GREASE_D, 0xDADA) \ - _ENUM_KEY_VALUE(GREASE_E, 0xEAEA) \ - _ENUM_KEY_VALUE(GREASE_F, 0xFAFA) - -enum class SupportedGroup : u16 { - __ENUM_SUPPORTED_GROUPS -}; - -// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-9 -#define __ENUM_EC_POINT_FORMATS \ - _ENUM_KEY_VALUE(UNCOMPRESSED, 0) \ - _ENUM_KEY_VALUE(ANSIX962_COMPRESSED_PRIME, 1) \ - _ENUM_KEY_VALUE(ANSIX962_COMPRESSED_CHAR2, 2) - -enum class ECPointFormat : u8 { - __ENUM_EC_POINT_FORMATS -}; - -// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-16 -#define __ENUM_SIGNATURE_ALGORITHM \ - _ENUM_KEY_VALUE(ANONYMOUS, 0) \ - _ENUM_KEY_VALUE(RSA, 1) \ - _ENUM_KEY_VALUE(DSA, 2) \ - _ENUM_KEY_VALUE(ECDSA, 3) \ - _ENUM_KEY_VALUE(ED25519, 7) \ - _ENUM_KEY_VALUE(ED448, 8) \ - _ENUM_KEY_VALUE(GOSTR34102012_256, 64) \ - _ENUM_KEY_VALUE(GOSTR34102012_512, 65) - -enum class SignatureAlgorithm : u8 { - __ENUM_SIGNATURE_ALGORITHM -}; - -// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-18 -#define __ENUM_HASH_ALGORITHM \ - _ENUM_KEY_VALUE(NONE, 0) \ - _ENUM_KEY_VALUE(MD5, 1) \ - _ENUM_KEY_VALUE(SHA1, 2) \ - _ENUM_KEY_VALUE(SHA224, 3) \ - _ENUM_KEY_VALUE(SHA256, 4) \ - _ENUM_KEY_VALUE(SHA384, 5) \ - _ENUM_KEY_VALUE(SHA512, 6) \ - _ENUM_KEY_VALUE(INTRINSIC, 8) - -enum class HashAlgorithm : u8 { - __ENUM_HASH_ALGORITHM -}; - -// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4 -#define __ENUM_CIPHER_SUITES \ - _ENUM_KEY_VALUE(TLS_NULL_WITH_NULL_NULL, 0x0000) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_NULL_MD5, 0x0001) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_NULL_SHA, 0x0002) \ - _ENUM_KEY_VALUE(TLS_RSA_EXPORT_WITH_RC4_40_MD5, 0x0003) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_RC4_128_MD5, 0x0004) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_RC4_128_SHA, 0x0005) \ - _ENUM_KEY_VALUE(TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, 0x0006) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_IDEA_CBC_SHA, 0x0007) \ - _ENUM_KEY_VALUE(TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, 0x0008) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_DES_CBC_SHA, 0x0009) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_3DES_EDE_CBC_SHA, 0x000A) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, 0x000B) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_DES_CBC_SHA, 0x000C) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, 0x000D) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, 0x000E) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_DES_CBC_SHA, 0x000F) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, 0x0010) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, 0x0011) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_DES_CBC_SHA, 0x0012) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, 0x0013) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, 0x0014) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_DES_CBC_SHA, 0x0015) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 0x0016) \ - _ENUM_KEY_VALUE(TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, 0x0017) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_RC4_128_MD5, 0x0018) \ - _ENUM_KEY_VALUE(TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, 0x0019) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_DES_CBC_SHA, 0x001A) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, 0x001B) \ - _ENUM_KEY_VALUE(TLS_KRB5_WITH_DES_CBC_SHA, 0x001E) \ - _ENUM_KEY_VALUE(TLS_KRB5_WITH_3DES_EDE_CBC_SHA, 0x001F) \ - _ENUM_KEY_VALUE(TLS_KRB5_WITH_RC4_128_SHA, 0x0020) \ - _ENUM_KEY_VALUE(TLS_KRB5_WITH_IDEA_CBC_SHA, 0x0021) \ - _ENUM_KEY_VALUE(TLS_KRB5_WITH_DES_CBC_MD5, 0x0022) \ - _ENUM_KEY_VALUE(TLS_KRB5_WITH_3DES_EDE_CBC_MD5, 0x0023) \ - _ENUM_KEY_VALUE(TLS_KRB5_WITH_RC4_128_MD5, 0x0024) \ - _ENUM_KEY_VALUE(TLS_KRB5_WITH_IDEA_CBC_MD5, 0x0025) \ - _ENUM_KEY_VALUE(TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, 0x0026) \ - _ENUM_KEY_VALUE(TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA, 0x0027) \ - _ENUM_KEY_VALUE(TLS_KRB5_EXPORT_WITH_RC4_40_SHA, 0x0028) \ - _ENUM_KEY_VALUE(TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5, 0x0029) \ - _ENUM_KEY_VALUE(TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5, 0x002A) \ - _ENUM_KEY_VALUE(TLS_KRB5_EXPORT_WITH_RC4_40_MD5, 0x002B) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_NULL_SHA, 0x002C) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_NULL_SHA, 0x002D) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_NULL_SHA, 0x002E) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_AES_128_CBC_SHA, 0x002F) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_AES_128_CBC_SHA, 0x0030) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_AES_128_CBC_SHA, 0x0031) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_AES_128_CBC_SHA, 0x0032) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_AES_128_CBC_SHA, 0x0033) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_AES_128_CBC_SHA, 0x0034) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_AES_256_CBC_SHA, 0x0035) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_AES_256_CBC_SHA, 0x0036) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_AES_256_CBC_SHA, 0x0037) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_AES_256_CBC_SHA, 0x0038) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 0x0039) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_AES_256_CBC_SHA, 0x003A) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_NULL_SHA256, 0x003B) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_AES_128_CBC_SHA256, 0x003C) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_AES_256_CBC_SHA256, 0x003D) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_AES_128_CBC_SHA256, 0x003E) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_AES_128_CBC_SHA256, 0x003F) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, 0x0040) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, 0x0041) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA, 0x0042) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA, 0x0043) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, 0x0044) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, 0x0045) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA, 0x0046) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, 0x0067) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_AES_256_CBC_SHA256, 0x0068) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_AES_256_CBC_SHA256, 0x0069) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, 0x006A) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, 0x006B) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_AES_128_CBC_SHA256, 0x006C) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_AES_256_CBC_SHA256, 0x006D) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, 0x0084) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA, 0x0085) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA, 0x0086) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, 0x0087) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, 0x0088) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA, 0x0089) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_RC4_128_SHA, 0x008A) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_3DES_EDE_CBC_SHA, 0x008B) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_AES_128_CBC_SHA, 0x008C) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_AES_256_CBC_SHA, 0x008D) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_RC4_128_SHA, 0x008E) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, 0x008F) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_AES_128_CBC_SHA, 0x0090) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_AES_256_CBC_SHA, 0x0091) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_RC4_128_SHA, 0x0092) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, 0x0093) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_AES_128_CBC_SHA, 0x0094) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, 0x0095) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_SEED_CBC_SHA, 0x0096) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_SEED_CBC_SHA, 0x0097) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_SEED_CBC_SHA, 0x0098) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_SEED_CBC_SHA, 0x0099) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_SEED_CBC_SHA, 0x009A) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_SEED_CBC_SHA, 0x009B) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_AES_128_GCM_SHA256, 0x009C) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_AES_256_GCM_SHA384, 0x009D) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, 0x009E) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, 0x009F) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_AES_128_GCM_SHA256, 0x00A0) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_AES_256_GCM_SHA384, 0x00A1) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, 0x00A2) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, 0x00A3) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_AES_128_GCM_SHA256, 0x00A4) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_AES_256_GCM_SHA384, 0x00A5) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_AES_128_GCM_SHA256, 0x00A6) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_AES_256_GCM_SHA384, 0x00A7) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_AES_128_GCM_SHA256, 0x00A8) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_AES_256_GCM_SHA384, 0x00A9) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, 0x00AA) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, 0x00AB) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, 0x00AC) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, 0x00AD) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_AES_128_CBC_SHA256, 0x00AE) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_AES_256_CBC_SHA384, 0x00AF) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_NULL_SHA256, 0x00B0) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_NULL_SHA384, 0x00B1) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, 0x00B2) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, 0x00B3) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_NULL_SHA256, 0x00B4) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_NULL_SHA384, 0x00B5) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, 0x00B6) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, 0x00B7) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_NULL_SHA256, 0x00B8) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_NULL_SHA384, 0x00B9) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, 0x00BA) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256, 0x00BB) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256, 0x00BC) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256, 0x00BD) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, 0x00BE) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256, 0x00BF) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, 0x00C0) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256, 0x00C1) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256, 0x00C2) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256, 0x00C3) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, 0x00C4) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256, 0x00C5) \ - _ENUM_KEY_VALUE(TLS_SM4_GCM_SM3, 0x00C6) \ - _ENUM_KEY_VALUE(TLS_SM4_CCM_SM3, 0x00C7) \ - _ENUM_KEY_VALUE(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, 0x00FF) \ - _ENUM_KEY_VALUE(TLS_AES_128_GCM_SHA256, 0x1301) \ - _ENUM_KEY_VALUE(TLS_AES_256_GCM_SHA384, 0x1302) \ - _ENUM_KEY_VALUE(TLS_CHACHA20_POLY1305_SHA256, 0x1303) \ - _ENUM_KEY_VALUE(TLS_AES_128_CCM_SHA256, 0x1304) \ - _ENUM_KEY_VALUE(TLS_AES_128_CCM_8_SHA256, 0x1305) \ - _ENUM_KEY_VALUE(TLS_FALLBACK_SCSV, 0x5600) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_NULL_SHA, 0xC001) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, 0xC002) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, 0xC003) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, 0xC004) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, 0xC005) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_NULL_SHA, 0xC006) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 0xC007) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, 0xC008) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 0xC009) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 0xC00A) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_NULL_SHA, 0xC00B) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_RC4_128_SHA, 0xC00C) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, 0xC00D) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, 0xC00E) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, 0xC00F) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_NULL_SHA, 0xC010) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_RC4_128_SHA, 0xC011) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 0xC012) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0xC013) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 0xC014) \ - _ENUM_KEY_VALUE(TLS_ECDH_anon_WITH_NULL_SHA, 0xC015) \ - _ENUM_KEY_VALUE(TLS_ECDH_anon_WITH_RC4_128_SHA, 0xC016) \ - _ENUM_KEY_VALUE(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, 0xC017) \ - _ENUM_KEY_VALUE(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, 0xC018) \ - _ENUM_KEY_VALUE(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, 0xC019) \ - _ENUM_KEY_VALUE(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, 0xC01A) \ - _ENUM_KEY_VALUE(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, 0xC01B) \ - _ENUM_KEY_VALUE(TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, 0xC01C) \ - _ENUM_KEY_VALUE(TLS_SRP_SHA_WITH_AES_128_CBC_SHA, 0xC01D) \ - _ENUM_KEY_VALUE(TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, 0xC01E) \ - _ENUM_KEY_VALUE(TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, 0xC01F) \ - _ENUM_KEY_VALUE(TLS_SRP_SHA_WITH_AES_256_CBC_SHA, 0xC020) \ - _ENUM_KEY_VALUE(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, 0xC021) \ - _ENUM_KEY_VALUE(TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, 0xC022) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 0xC023) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, 0xC024) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, 0xC025) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, 0xC026) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 0xC027) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, 0xC028) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, 0xC029) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, 0xC02A) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0xC02B) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 0xC02C) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, 0xC02D) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, 0xC02E) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0xC02F) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 0xC030) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, 0xC031) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, 0xC032) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_RC4_128_SHA, 0xC033) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, 0xC034) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 0xC035) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, 0xC036) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, 0xC037) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, 0xC038) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_NULL_SHA, 0xC039) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_NULL_SHA256, 0xC03A) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_NULL_SHA384, 0xC03B) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_ARIA_128_CBC_SHA256, 0xC03C) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_ARIA_256_CBC_SHA384, 0xC03D) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256, 0xC03E) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384, 0xC03F) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256, 0xC040) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384, 0xC041) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256, 0xC042) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384, 0xC043) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256, 0xC044) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384, 0xC045) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_ARIA_128_CBC_SHA256, 0xC046) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_ARIA_256_CBC_SHA384, 0xC047) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256, 0xC048) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384, 0xC049) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256, 0xC04A) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384, 0xC04B) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, 0xC04C) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384, 0xC04D) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256, 0xC04E) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384, 0xC04F) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_ARIA_128_GCM_SHA256, 0xC050) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_ARIA_256_GCM_SHA384, 0xC051) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256, 0xC052) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384, 0xC053) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256, 0xC054) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384, 0xC055) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256, 0xC056) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384, 0xC057) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256, 0xC058) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384, 0xC059) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_ARIA_128_GCM_SHA256, 0xC05A) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_ARIA_256_GCM_SHA384, 0xC05B) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256, 0xC05C) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384, 0xC05D) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256, 0xC05E) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384, 0xC05F) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256, 0xC060) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384, 0xC061) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256, 0xC062) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384, 0xC063) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_ARIA_128_CBC_SHA256, 0xC064) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_ARIA_256_CBC_SHA384, 0xC065) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256, 0xC066) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384, 0xC067) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256, 0xC068) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384, 0xC069) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_ARIA_128_GCM_SHA256, 0xC06A) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_ARIA_256_GCM_SHA384, 0xC06B) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256, 0xC06C) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384, 0xC06D) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256, 0xC06E) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384, 0xC06F) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256, 0xC070) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384, 0xC071) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, 0xC072) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, 0xC073) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, 0xC074) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, 0xC075) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, 0xC076) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, 0xC077) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256, 0xC078) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384, 0xC079) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256, 0xC07A) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384, 0xC07B) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, 0xC07C) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, 0xC07D) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256, 0xC07E) \ - _ENUM_KEY_VALUE(TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384, 0xC07F) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256, 0xC080) \ - _ENUM_KEY_VALUE(TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384, 0xC081) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256, 0xC082) \ - _ENUM_KEY_VALUE(TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384, 0xC083) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256, 0xC084) \ - _ENUM_KEY_VALUE(TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384, 0xC085) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, 0xC086) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, 0xC087) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, 0xC088) \ - _ENUM_KEY_VALUE(TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, 0xC089) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, 0xC08A) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, 0xC08B) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256, 0xC08C) \ - _ENUM_KEY_VALUE(TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384, 0xC08D) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256, 0xC08E) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384, 0xC08F) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256, 0xC090) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384, 0xC091) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256, 0xC092) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384, 0xC093) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256, 0xC094) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384, 0xC095) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, 0xC096) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, 0xC097) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256, 0xC098) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384, 0xC099) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, 0xC09A) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, 0xC09B) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_AES_128_CCM, 0xC09C) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_AES_256_CCM, 0xC09D) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_AES_128_CCM, 0xC09E) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_AES_256_CCM, 0xC09F) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_AES_128_CCM_8, 0xC0A0) \ - _ENUM_KEY_VALUE(TLS_RSA_WITH_AES_256_CCM_8, 0xC0A1) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_AES_128_CCM_8, 0xC0A2) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_AES_256_CCM_8, 0xC0A3) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_AES_128_CCM, 0xC0A4) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_AES_256_CCM, 0xC0A5) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_AES_128_CCM, 0xC0A6) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_AES_256_CCM, 0xC0A7) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_AES_128_CCM_8, 0xC0A8) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_AES_256_CCM_8, 0xC0A9) \ - _ENUM_KEY_VALUE(TLS_PSK_DHE_WITH_AES_128_CCM_8, 0xC0AA) \ - _ENUM_KEY_VALUE(TLS_PSK_DHE_WITH_AES_256_CCM_8, 0xC0AB) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_AES_128_CCM, 0xC0AC) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_AES_256_CCM, 0xC0AD) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, 0xC0AE) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, 0xC0AF) \ - _ENUM_KEY_VALUE(TLS_ECCPWD_WITH_AES_128_GCM_SHA256, 0xC0B0) \ - _ENUM_KEY_VALUE(TLS_ECCPWD_WITH_AES_256_GCM_SHA384, 0xC0B1) \ - _ENUM_KEY_VALUE(TLS_ECCPWD_WITH_AES_128_CCM_SHA256, 0xC0B2) \ - _ENUM_KEY_VALUE(TLS_ECCPWD_WITH_AES_256_CCM_SHA384, 0xC0B3) \ - _ENUM_KEY_VALUE(TLS_SHA256_SHA256, 0xC0B4) \ - _ENUM_KEY_VALUE(TLS_SHA384_SHA384, 0xC0B5) \ - _ENUM_KEY_VALUE(TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC, 0xC100) \ - _ENUM_KEY_VALUE(TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC, 0xC101) \ - _ENUM_KEY_VALUE(TLS_GOSTR341112_256_WITH_28147_CNT_IMIT, 0xC102) \ - _ENUM_KEY_VALUE(TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L, 0xC103) \ - _ENUM_KEY_VALUE(TLS_GOSTR341112_256_WITH_MAGMA_MGM_L, 0xC104) \ - _ENUM_KEY_VALUE(TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S, 0xC105) \ - _ENUM_KEY_VALUE(TLS_GOSTR341112_256_WITH_MAGMA_MGM_S, 0xC106) \ - _ENUM_KEY_VALUE(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0xCCA8) \ - _ENUM_KEY_VALUE(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0xCCA9) \ - _ENUM_KEY_VALUE(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0xCCAA) \ - _ENUM_KEY_VALUE(TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, 0xCCAB) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, 0xCCAC) \ - _ENUM_KEY_VALUE(TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, 0xCCAD) \ - _ENUM_KEY_VALUE(TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256, 0xCCAE) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, 0xD001) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384, 0xD002) \ - _ENUM_KEY_VALUE(TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256, 0xD003) \ - _ENUM_KEY_VALUE(GREASE_0, 0x0A0A) \ - _ENUM_KEY_VALUE(GREASE_1, 0x1A1A) \ - _ENUM_KEY_VALUE(GREASE_2, 0x2A2A) \ - _ENUM_KEY_VALUE(GREASE_3, 0x3A3A) \ - _ENUM_KEY_VALUE(GREASE_4, 0x4A4A) \ - _ENUM_KEY_VALUE(GREASE_5, 0x5A5A) \ - _ENUM_KEY_VALUE(GREASE_6, 0x6A6A) \ - _ENUM_KEY_VALUE(GREASE_7, 0x7A7A) \ - _ENUM_KEY_VALUE(GREASE_8, 0x8A8A) \ - _ENUM_KEY_VALUE(GREASE_9, 0x9A9A) \ - _ENUM_KEY_VALUE(GREASE_A, 0xAAAA) \ - _ENUM_KEY_VALUE(GREASE_B, 0xBABA) \ - _ENUM_KEY_VALUE(GREASE_C, 0xCACA) \ - _ENUM_KEY_VALUE(GREASE_D, 0XDADA) \ - _ENUM_KEY_VALUE(GREASE_E, 0xEAEA) \ - _ENUM_KEY_VALUE(GREASE_F, 0xFAFA) - -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(CipherSuite descriptor) -{ -#define _ENUM_KEY_VALUE(name, value) \ - case CipherSuite::name: \ - return #name##sv; - - switch (descriptor) { - __ENUM_CIPHER_SUITES - } - - return "Unknown"sv; -#undef _ENUM_KEY_VALUE -} - -constexpr static StringView enum_to_string(ExtensionType descriptor) -{ -#define _ENUM_KEY_VALUE(name, value) \ - case ExtensionType::name: \ - return #name##sv; - - switch (descriptor) { - __ENUM_EXTENSION_TYPES - } - - return "Unknown"sv; -#undef _ENUM_KEY_VALUE -} - -constexpr static StringView enum_to_string(ContentType descriptor) -{ -#define _ENUM_KEY_VALUE(name, value) \ - case ContentType::name: \ - return #name##sv; - - switch (descriptor) { - __ENUM_CONTENT_TYPES - } - - return "Unknown"sv; -#undef _ENUM_KEY_VALUE -} - -constexpr static StringView enum_to_string(ProtocolVersion descriptor) -{ -#define _ENUM_KEY_VALUE(name, value) \ - case ProtocolVersion::name: \ - return #name##sv; - - switch (descriptor) { - __ENUM_PROTOCOL_VERSIONS - } - - return "Unknown"sv; -#undef _ENUM_KEY_VALUE -} - -constexpr static StringView enum_to_string(HandshakeType descriptor) -{ -#define _ENUM_KEY_VALUE(name, value) \ - case HandshakeType::name: \ - return #name##sv; - - switch (descriptor) { - __ENUM_HANDSHAKE_TYPES - } - - return "Unknown"sv; -#undef _ENUM_KEY_VALUE -} - -constexpr static StringView enum_to_string(SignatureAlgorithm descriptor) -{ -#define _ENUM_KEY_VALUE(name, value) \ - case SignatureAlgorithm::name: \ - return #name##sv; - - switch (descriptor) { - __ENUM_SIGNATURE_ALGORITHM - } - - return "Unknown"sv; -#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 -} - -constexpr static StringView const enum_to_value(AlertDescription descriptor) -{ - switch (descriptor) { - case AlertDescription::UNEXPECTED_MESSAGE: - return "An inappropriate message was received. " - "This alert is always fatal and should never be observed in communication between proper implementations."sv; - - case AlertDescription::BAD_RECORD_MAC: - return "This alert is returned if a record is received with an incorrect MAC. " - "This alert also MUST be returned if an alert is sent because a TLSCiphertext decrypted in an invalid way: " - "either it wasn't an even multiple of the block length, " - "or its padding values, when checked, weren't correct. " - "This message is always fatal."sv; - - case AlertDescription::DECRYPTION_FAILED_RESERVED: - return "This alert MAY be returned if a TLSCiphertext decrypted in an invalid way: " - "either it wasn't an even multiple of the block length, " - "or its padding values, when checked, weren't correct. " - "This message is always fatal."sv; - - case AlertDescription::RECORD_OVERFLOW: - return "A TLSCiphertext record was received that had a length more than 2^14 + 2048 bytes, " - "or a record decrypted to a TLSCompressed record with more than 2^14 + 1024 bytes. " - "This message is always fatal."sv; - - case AlertDescription::DECOMPRESSION_FAILURE_RESERVED: - return "The decompression function received improper input (e.g., data that would expand to excessive length). " - "This message is always fatal."sv; - - case AlertDescription::HANDSHAKE_FAILURE: - return "Reception of a handshake_failure alert message indicates that the sender " - "was unable to negotiate an acceptable set of security parameters given the options available. " - "This is a fatal error."sv; - - case AlertDescription::NO_CERTIFICATE_RESERVED: - return "This alert was used in SSLv3 but not in TLS. It should not be sent by compliant implementations."sv; - - case AlertDescription::BAD_CERTIFICATE: - return "A certificate was corrupt, contained signatures that did not verify correctly, etc."sv; - - case AlertDescription::UNSUPPORTED_CERTIFICATE: - return "A certificate was of an unsupported type."sv; - - case AlertDescription::CERTIFICATE_REVOKED: - return "A certificate was revoked by its signer."sv; - - case AlertDescription::CERTIFICATE_EXPIRED: - return "A certificate has expired or is not currently valid."sv; - - case AlertDescription::CERTIFICATE_UNKNOWN: - return "Some other (unspecified) issue arose in processing the certificate, rendering it unacceptable."sv; - - case AlertDescription::ILLEGAL_PARAMETER: - return "A field in the handshake was out of range or inconsistent with other fields. " - "This is always fatal."sv; - - case AlertDescription::UNKNOWN_CA: - return "A valid certificate chain or partial chain was received, but the certificate was not accepted " - "because the CA certificate could not be located " - "or couldn't be matched with a known, trusted CA. " - "This message is always fatal."sv; - - case AlertDescription::ACCESS_DENIED: - return "A valid certificate was received, but when access control was applied, " - "the sender decided not to proceed with negotiation. " - "This message is always fatal."sv; - - case AlertDescription::DECODE_ERROR: - return "A message could not be decoded because some field was out of the specified range " - "or the length of the message was incorrect. " - "This message is always fatal."sv; - - case AlertDescription::DECRYPT_ERROR: - return "A handshake cryptographic operation failed, " - "including being unable to correctly verify a signature, " - "decrypt a key exchange, or validate a finished message."sv; - - case AlertDescription::EXPORT_RESTRICTION_RESERVED: - return "This alert was used in TLS 1.0 but not TLS 1.1."sv; - - case AlertDescription::PROTOCOL_VERSION: - return "The protocol version the client has attempted to negotiate is recognized but not supported. " - "(For example, old protocol versions might be avoided for security reasons). " - "This message is always fatal."sv; - - case AlertDescription::INSUFFICIENT_SECURITY: - return "Returned instead of handshake_failure when a negotiation has failed" - "specifically because the server requires ciphers more secure than those supported by the client." - "This message is always fatal."sv; - - case AlertDescription::INTERNAL_ERROR: - return "An internal error unrelated to the peer " - "or the correctness of the protocol (such as a memory allocation failure) " - "makes it impossible to continue. " - "This message is always fatal."sv; - - case AlertDescription::USER_CANCELED: - return "This handshake is being canceled for some reason unrelated to a protocol failure. " - "If the user cancels an operation after the handshake is complete, " - "just closing the connection by sending a close_notify is more appropriate. " - "This alert should be followed by a close_notify. " - "This message is generally a warning."sv; - - case AlertDescription::NO_RENEGOTIATION_RESERVED: - return "Sent by the client in response to a hello request " - "or by the server in response to a client hello after initial handshaking. " - "Either of these would normally lead to renegotiation; " - "when that is not appropriate, the recipient should respond with this alert. " - "At that point, the original requester can decide whether to proceed with the connection. " - "One case where this would be appropriate is where a server has spawned a process to satisfy a request; " - "the process might receive security parameters(key length, authentication, etc.) at startup " - "and it might be difficult to communicate changes to these parameters after that point. " - "This message is always a warning."sv; - - case AlertDescription::CLOSE_NOTIFY: - return "This alert notifies the recipient that the sender will not send any more messages on this connection. " - "Any data received after a closure alert has been received MUST be ignored."sv; - - case AlertDescription::INAPPROPRIATE_FALLBACK: - return "Sent by a server in response to an invalid connection retry attempt from a client (see [RFC7507])."sv; - - case AlertDescription::MISSING_EXTENSION: - return "Sent by endpoints that receive a handshake message not containing an extension " - "that is mandatory to send for the offered TLS version or other negotiated parameters."sv; - - case AlertDescription::CERTIFICATE_REQUIRED: - return "Sent by servers when a client certificate is desired but none was provided by the client."sv; - - case AlertDescription::NO_APPLICATION_PROTOCOL: - return "Sent by servers when a client \"application_layer_protocol_negotiation\" extension " - "advertises only protocols that the server does not support (see [RFC7301])."sv; - - case AlertDescription::UNSUPPORTED_EXTENSION: - return "Sent by endpoints receiving any handshake message containing an extension known to be prohibited " - "for inclusion in the given handshake message, " - "or including any extensions in a ServerHello " - "or Certificate not first offered in the corresponding ClientHello or CertificateRequest."sv; - - case AlertDescription::CERTIFICATE_UNOBTAINABLE_RESERVED: - return "If a server is unable to obtain certificates in a given CertificateURL, " - "it MUST send a fatal certificate_unobtainable(111) alert " - "if it requires the certificates to complete the handshake."sv; - - case AlertDescription::TOO_MANY_CIDS_REQUESTED: - return "Endpoints MAY handle an excessive number of RequestConnectionId messages by terminating the connection."sv; - - case AlertDescription::UNRECOGNIZED_NAME: - return "The ServerNameList MUST NOT contain more than one name of the same name_type. " - "If the server understood the ClientHello extension but does not recognize the server name, " - "the server SHOULD take one of two actions: " - "either abort the handshake by sending a fatal-level unrecognized_name(112) alert or continue the handshake. " - "It is NOT RECOMMENDED to send a warning-level unrecognized_name(112) alert, " - "because the client's behavior in response to warning-level alerts is unpredictable."sv; - - case AlertDescription::BAD_CERTIFICATE_STATUS_RESPONSE: - return "Clients requesting an OCSP response and receiving an OCSP response " - "in a \"CertificateStatus\" message MUST check the OCSP response " - "and abort the handshake if the response is not satisfactory. " - "This alert is always fatal."sv; - - case AlertDescription::BAD_CERTIFICATE_HASH_VALUE_RESERVED: - return "The server MUST check that the SHA-1 hash of the contents of the object retrieved from that URL " - "(after decoding any MIME Content-Transfer-Encoding) matches the given hash. " - "If any retrieved object does not have the correct SHA-1 hash, " - "the server MUST abort the handshake. " - "This alert is always fatal."sv; - - case AlertDescription::UNKNOWN_PSK_IDENTITY: - return "If the server does not recognize the PSK identity, it MAY respond with this message." - "Alternatively, if the server wishes to hide the fact that the PSK identity was not known, " - "it MAY continue the protocol as if the PSK identity existed but the key was incorrect: " - "that is, respond with a \"DECRYPT_ERROR\" alert."sv; - } - - return "Unknown alert"sv; -} - -} diff --git a/Libraries/LibTLS/Handshake.cpp b/Libraries/LibTLS/Handshake.cpp deleted file mode 100644 index c74825b8c78..00000000000 --- a/Libraries/LibTLS/Handshake.cpp +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * Copyright (c) 2022, Michiel Visser - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -#include -#include -#include -#include - -namespace TLS { - -ByteBuffer TLSv12::build_hello() -{ - ::Crypto::fill_with_secure_random(m_context.local_random); - - auto packet_version = (u16)m_context.options.version; - auto version = (u16)m_context.options.version; - PacketBuilder builder { ContentType::HANDSHAKE, packet_version }; - - builder.append(to_underlying(HandshakeType::CLIENT_HELLO)); - - // 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_empty()) { - 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_empty() && m_context.options.use_sni) - sni_length = m_context.extensions.SNI.length(); - - auto elliptic_curves_length = 2 * m_context.options.elliptic_curves.size(); - auto supported_ec_point_formats_length = m_context.options.supported_ec_point_formats.size(); - bool supports_elliptic_curves = elliptic_curves_length && supported_ec_point_formats_length; - bool enable_extended_master_secret = m_context.options.enable_extended_master_secret; - - // 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; - - // Only send elliptic_curves and ec_point_formats extensions if both are supported - if (supports_elliptic_curves) - extension_length += 6 + elliptic_curves_length + 5 + supported_ec_point_formats_length; - - if (enable_extended_master_secret) - extension_length += 4; - - builder.append((u16)extension_length); - - if (sni_length) { - // SNI extension - builder.append((u16)ExtensionType::SERVER_NAME); - // 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((u8 const*)m_context.extensions.SNI.characters(), sni_length); - } - - // signature_algorithms extension - builder.append((u16)ExtensionType::SIGNATURE_ALGORITHMS); - // 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 (supports_elliptic_curves) { - // elliptic_curves extension - builder.append((u16)ExtensionType::SUPPORTED_GROUPS); - builder.append((u16)(2 + elliptic_curves_length)); - builder.append((u16)elliptic_curves_length); - for (auto& curve : m_context.options.elliptic_curves) - builder.append((u16)curve); - - // ec_point_formats extension - builder.append((u16)ExtensionType::EC_POINT_FORMATS); - builder.append((u16)(1 + supported_ec_point_formats_length)); - builder.append((u8)supported_ec_point_formats_length); - for (auto& format : m_context.options.supported_ec_point_formats) - builder.append((u8)format); - } - - if (enable_extended_master_secret) { - // extended_master_secret extension - builder.append((u16)ExtensionType::EXTENDED_MASTER_SECRET); - builder.append((u16)0); - } - - 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_change_cipher_spec() -{ - PacketBuilder builder { ContentType::CHANGE_CIPHER_SPEC, m_context.options.version, 64 }; - builder.append((u8)1); - auto packet = builder.build(); - update_packet(packet); - m_context.local_sequence_number = 0; - return packet; -} - -ByteBuffer TLSv12::build_handshake_finished() -{ - PacketBuilder builder { ContentType::HANDSHAKE, m_context.options.version, 12 + 64 }; - builder.append((u8)HandshakeType::FINISHED); - - // 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(verify_data_length); - - u8 out[verify_data_length]; - auto outbuffer = Bytes { out, verify_data_length }; - ByteBuffer dummy; - - 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, (u8 const*)"client finished", 15, hashbuf, dummy); - - builder.append(outbuffer); - auto packet = builder.build(); - update_packet(packet); - - return packet; -} - -ssize_t TLSv12::handle_handshake_finished(ReadonlyBytes buffer, WritePacketStage& write_packets) -{ - if (m_context.connection_status < ConnectionStatus::KeyExchange || m_context.connection_status == ConnectionStatus::Established) { - dbgln("unexpected finished message"); - return (i8)Error::UnexpectedMessage; - } - - write_packets = WritePacketStage::Initial; - - if (buffer.size() < 3) { - return (i8)Error::NeedMoreData; - } - - size_t index = 3; - - u32 size = buffer[0] * 0x10000 + buffer[1] * 0x100 + buffer[2]; - - if (size < 12) { - dbgln_if(TLS_DEBUG, "finished packet smaller than minimum size: {}", size); - return (i8)Error::BrokenPacket; - } - - if (size < buffer.size() - index) { - dbgln_if(TLS_DEBUG, "not enough data after length: {} > {}", size, buffer.size() - index); - return (i8)Error::NeedMoreData; - } - - // TODO: Compare Hashes - dbgln_if(TLS_DEBUG, "FIXME: handle_handshake_finished :: Check message validity"); - m_context.connection_status = ConnectionStatus::Established; - - if (m_handshake_timeout_timer) { - // Disable the handshake timeout timer as handshake has been established. - m_handshake_timeout_timer->stop(); - m_handshake_timeout_timer->remove_from_parent(); - m_handshake_timeout_timer = nullptr; - } - - if (on_connected) - on_connected(); - - return index + size; -} - -ssize_t TLSv12::handle_handshake_payload(ReadonlyBytes vbuffer) -{ - if (m_context.connection_status == ConnectionStatus::Established) { - dbgln_if(TLS_DEBUG, "Renegotiation attempt ignored"); - // FIXME: We should properly say "NoRenegotiation", but that causes a handshake failure - // so we just roll with it and pretend that we _did_ renegotiate - // This will cause issues when we decide to have long-lasting connections, but - // we do not have those at the moment :^) - return 1; - } - auto buffer = vbuffer; - auto buffer_length = buffer.size(); - auto original_length = buffer_length; - while (buffer_length >= 4 && !m_context.critical_error) { - ssize_t payload_res = 0; - auto type = static_cast(buffer[0]); - auto write_packets { WritePacketStage::Initial }; - size_t payload_size = buffer[1] * 0x10000 + buffer[2] * 0x100 + buffer[3] + 3; - dbgln_if(TLS_DEBUG, "payload size: {} buffer length: {}", payload_size, buffer_length); - if (payload_size + 1 > buffer_length) - return (i8)Error::NeedMoreData; - - switch (type) { - case HandshakeType::HELLO_REQUEST_RESERVED: - if (m_context.handshake_messages[0] >= 1) { - dbgln("unexpected hello request message"); - payload_res = (i8)Error::UnexpectedMessage; - break; - } - ++m_context.handshake_messages[0]; - dbgln("hello request (renegotiation?)"); - if (m_context.connection_status == ConnectionStatus::Established) { - // renegotiation - payload_res = (i8)Error::NoRenegotiation; - } else { - // :shrug: - payload_res = (i8)Error::UnexpectedMessage; - } - break; - case HandshakeType::CLIENT_HELLO: - // FIXME: We only support client mode right now - if (m_context.is_server) { - VERIFY_NOT_REACHED(); - } - payload_res = (i8)Error::UnexpectedMessage; - break; - case HandshakeType::SERVER_HELLO: - if (m_context.handshake_messages[2] >= 1) { - dbgln("unexpected server hello message"); - payload_res = (i8)Error::UnexpectedMessage; - break; - } - ++m_context.handshake_messages[2]; - dbgln_if(TLS_DEBUG, "server hello"); - if (m_context.is_server) { - dbgln("unsupported: server mode"); - VERIFY_NOT_REACHED(); - } - payload_res = handle_server_hello(buffer.slice(1, payload_size), write_packets); - break; - case HandshakeType::HELLO_VERIFY_REQUEST_RESERVED: - dbgln("unsupported: DTLS"); - payload_res = (i8)Error::UnexpectedMessage; - break; - case HandshakeType::CERTIFICATE: - if (m_context.handshake_messages[4] >= 1) { - dbgln("unexpected certificate message"); - payload_res = (i8)Error::UnexpectedMessage; - break; - } - ++m_context.handshake_messages[4]; - dbgln_if(TLS_DEBUG, "certificate"); - if (m_context.connection_status == ConnectionStatus::Negotiating) { - if (m_context.is_server) { - dbgln("unsupported: server mode"); - VERIFY_NOT_REACHED(); - } - payload_res = handle_certificate(buffer.slice(1, payload_size)); - } else { - payload_res = (i8)Error::UnexpectedMessage; - } - break; - case HandshakeType::SERVER_KEY_EXCHANGE_RESERVED: - if (m_context.handshake_messages[5] >= 1) { - dbgln("unexpected server key exchange message"); - payload_res = (i8)Error::UnexpectedMessage; - break; - } - ++m_context.handshake_messages[5]; - dbgln_if(TLS_DEBUG, "server key exchange"); - if (m_context.is_server) { - dbgln("unsupported: server mode"); - VERIFY_NOT_REACHED(); - } else { - payload_res = handle_server_key_exchange(buffer.slice(1, payload_size)); - } - break; - case HandshakeType::CERTIFICATE_REQUEST: - if (m_context.handshake_messages[6] >= 1) { - dbgln("unexpected certificate request message"); - payload_res = (i8)Error::UnexpectedMessage; - break; - } - ++m_context.handshake_messages[6]; - if (m_context.is_server) { - dbgln("invalid request"); - dbgln("unsupported: server mode"); - VERIFY_NOT_REACHED(); - } else { - // we do not support "certificate request" - dbgln("certificate request"); - if (on_tls_certificate_request) - on_tls_certificate_request(*this); - m_context.client_verified = VerificationNeeded; - } - break; - case HandshakeType::SERVER_HELLO_DONE_RESERVED: - if (m_context.handshake_messages[7] >= 1) { - dbgln("unexpected server hello done message"); - payload_res = (i8)Error::UnexpectedMessage; - break; - } - ++m_context.handshake_messages[7]; - dbgln_if(TLS_DEBUG, "server hello done"); - if (m_context.is_server) { - dbgln("unsupported: server mode"); - VERIFY_NOT_REACHED(); - } else { - payload_res = handle_server_hello_done(buffer.slice(1, payload_size)); - if (payload_res > 0) - write_packets = WritePacketStage::ClientHandshake; - } - break; - case HandshakeType::CERTIFICATE_VERIFY: - if (m_context.handshake_messages[8] >= 1) { - dbgln("unexpected certificate verify message"); - payload_res = (i8)Error::UnexpectedMessage; - break; - } - ++m_context.handshake_messages[8]; - dbgln_if(TLS_DEBUG, "certificate verify"); - if (m_context.connection_status == ConnectionStatus::KeyExchange) { - payload_res = handle_certificate_verify(buffer.slice(1, payload_size)); - } else { - payload_res = (i8)Error::UnexpectedMessage; - } - break; - case HandshakeType::CLIENT_KEY_EXCHANGE_RESERVED: - if (m_context.handshake_messages[9] >= 1) { - dbgln("unexpected client key exchange message"); - payload_res = (i8)Error::UnexpectedMessage; - break; - } - ++m_context.handshake_messages[9]; - dbgln_if(TLS_DEBUG, "client key exchange"); - if (m_context.is_server) { - dbgln("unsupported: server mode"); - VERIFY_NOT_REACHED(); - } else { - payload_res = (i8)Error::UnexpectedMessage; - } - break; - case HandshakeType::FINISHED: - m_context.cached_handshake.clear(); - if (m_context.handshake_messages[10] >= 1) { - dbgln("unexpected finished message"); - payload_res = (i8)Error::UnexpectedMessage; - break; - } - ++m_context.handshake_messages[10]; - dbgln_if(TLS_DEBUG, "finished"); - payload_res = handle_handshake_finished(buffer.slice(1, payload_size), write_packets); - if (payload_res > 0) { - memset(m_context.handshake_messages, 0, sizeof(m_context.handshake_messages)); - } - break; - default: - dbgln("message type not understood: {}", enum_to_string(type)); - return (i8)Error::NotUnderstood; - } - - if (type != HandshakeType::HELLO_REQUEST_RESERVED) { - update_hash(buffer.slice(0, payload_size + 1), 0); - } - - // if something went wrong, send an alert about it - if (payload_res < 0) { - switch ((Error)payload_res) { - case Error::UnexpectedMessage: { - auto packet = build_alert(true, (u8)AlertDescription::UNEXPECTED_MESSAGE); - write_packet(packet); - break; - } - case Error::CompressionNotSupported: { - auto packet = build_alert(true, (u8)AlertDescription::DECOMPRESSION_FAILURE_RESERVED); - write_packet(packet); - break; - } - case Error::BrokenPacket: { - auto packet = build_alert(true, (u8)AlertDescription::DECODE_ERROR); - write_packet(packet); - break; - } - case Error::NotVerified: { - auto packet = build_alert(true, (u8)AlertDescription::BAD_RECORD_MAC); - write_packet(packet); - break; - } - case Error::BadCertificate: { - auto packet = build_alert(true, (u8)AlertDescription::BAD_CERTIFICATE); - write_packet(packet); - break; - } - case Error::UnsupportedCertificate: { - auto packet = build_alert(true, (u8)AlertDescription::UNSUPPORTED_CERTIFICATE); - write_packet(packet); - break; - } - case Error::NoCommonCipher: { - 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::INTERNAL_ERROR); - write_packet(packet); - break; - } - case Error::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::DECRYPTION_FAILED_RESERVED); - write_packet(packet); - break; - } - case Error::NotSafe: { - auto packet = build_alert(true, (u8)AlertDescription::DECRYPT_ERROR); - write_packet(packet); - break; - } - case Error::NeedMoreData: - // Ignore this, as it's not an "error" - dbgln_if(TLS_DEBUG, "More data needed"); - break; - default: - dbgln("Unknown TLS::Error with value {}", payload_res); - VERIFY_NOT_REACHED(); - break; - } - if (payload_res < 0) - return payload_res; - } - switch (write_packets) { - case WritePacketStage::Initial: - // nothing to write - break; - case WritePacketStage::ClientHandshake: - if (m_context.client_verified == VerificationNeeded) { - dbgln_if(TLS_DEBUG, "> Client Certificate"); - auto packet = build_certificate(); - write_packet(packet); - m_context.client_verified = Verified; - } - { - dbgln_if(TLS_DEBUG, "> Key exchange"); - auto packet = build_client_key_exchange(); - write_packet(packet); - } - { - dbgln_if(TLS_DEBUG, "> change cipher spec"); - auto packet = build_change_cipher_spec(); - write_packet(packet); - } - m_context.cipher_spec_set = 1; - m_context.local_sequence_number = 0; - { - dbgln_if(TLS_DEBUG, "> client finished"); - auto packet = build_handshake_finished(); - write_packet(packet); - } - m_context.cipher_spec_set = 0; - break; - case WritePacketStage::ServerHandshake: - // server handshake - dbgln("UNSUPPORTED: Server mode"); - VERIFY_NOT_REACHED(); - break; - case WritePacketStage::Finished: - // finished - { - dbgln_if(TLS_DEBUG, "> change cipher spec"); - auto packet = build_change_cipher_spec(); - write_packet(packet); - } - { - dbgln_if(TLS_DEBUG, "> client finished"); - auto packet = build_handshake_finished(); - write_packet(packet); - } - m_context.connection_status = ConnectionStatus::Established; - break; - } - payload_size++; - buffer_length -= payload_size; - buffer = buffer.slice(payload_size, buffer_length); - } - return original_length; -} -} diff --git a/Libraries/LibTLS/HandshakeCertificate.cpp b/Libraries/LibTLS/HandshakeCertificate.cpp deleted file mode 100644 index 8c79e4afc84..00000000000 --- a/Libraries/LibTLS/HandshakeCertificate.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -#include -#include -#include - -namespace TLS { - -ssize_t TLSv12::handle_certificate(ReadonlyBytes buffer) -{ - ssize_t res = 0; - - if (buffer.size() < 3) { - dbgln_if(TLS_DEBUG, "not enough certificate header data"); - return (i8)Error::NeedMoreData; - } - - u32 certificate_total_length = buffer[0] * 0x10000 + buffer[1] * 0x100 + buffer[2]; - - dbgln_if(TLS_DEBUG, "total length: {}", certificate_total_length); - - if (certificate_total_length <= 4) - return 3 * certificate_total_length; - - res += 3; - - if (certificate_total_length > buffer.size() - res) { - dbgln_if(TLS_DEBUG, "not enough data for claimed total cert length"); - return (i8)Error::NeedMoreData; - } - size_t size = certificate_total_length; - - bool valid_certificate = false; - - while (size > 0) { - if (buffer.size() - res < 3) { - dbgln_if(TLS_DEBUG, "not enough data for certificate length"); - return (i8)Error::NeedMoreData; - } - size_t certificate_size = buffer[res] * 0x10000 + buffer[res + 1] * 0x100 + buffer[res + 2]; - res += 3; - - if (buffer.size() - res < certificate_size) { - dbgln_if(TLS_DEBUG, "not enough data for certificate body"); - return (i8)Error::NeedMoreData; - } - - auto res_cert = res; - auto remaining = certificate_size; - - do { - if (remaining <= 3) { - dbgln("Ran out of data"); - break; - } - if (buffer.size() < (size_t)res_cert + 3) { - dbgln("not enough data to read cert size ({} < {})", buffer.size(), res_cert + 3); - break; - } - size_t certificate_size_specific = buffer[res_cert] * 0x10000 + buffer[res_cert + 1] * 0x100 + buffer[res_cert + 2]; - res_cert += 3; - remaining -= 3; - - if (certificate_size_specific > remaining) { - dbgln("invalid certificate size (expected {} but got {})", remaining, certificate_size_specific); - break; - } - remaining -= certificate_size_specific; - - auto certificate = Certificate::parse_certificate(buffer.slice(res_cert, certificate_size_specific), false); - if (!certificate.is_error()) { - m_context.certificates.empend(certificate.value()); - valid_certificate = true; - } else { - dbgln("Failed to parse client cert: {}", certificate.error()); - dbgln("{:hex-dump}", buffer.slice(res_cert, certificate_size_specific)); - dbgln(""); - } - res_cert += certificate_size_specific; - } while (remaining > 0); - if (remaining) { - dbgln("extraneous {} bytes left over after parsing certificates", remaining); - } - size -= certificate_size + 3; - res += certificate_size; - } - if (!valid_certificate) - return (i8)Error::UnsupportedCertificate; - - if ((size_t)res != buffer.size()) - dbgln("some data left unread: {} bytes out of {}", res, buffer.size()); - - return res; -} - -ssize_t TLSv12::handle_certificate_verify(ReadonlyBytes) -{ - dbgln("FIXME: parse_verify"); - return 0; -} - -} diff --git a/Libraries/LibTLS/HandshakeClient.cpp b/Libraries/LibTLS/HandshakeClient.cpp deleted file mode 100644 index 032faaf1d4d..00000000000 --- a/Libraries/LibTLS/HandshakeClient.cpp +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * Copyright (c) 2022, Michiel Visser - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace TLS { - -bool TLSv12::expand_key() -{ - u8 key[192]; // soooooooo many constants - auto key_buffer = Bytes { key, sizeof(key) }; - - auto is_aead = this->is_aead(); - - if (m_context.master_key.size() == 0) { - dbgln("expand_key() with empty master key"); - return false; - } - - auto key_size = key_length(); - VERIFY(key_size); - auto mac_size = mac_length(); - auto iv_size = iv_length(); - - pseudorandom_function( - key_buffer, - m_context.master_key, - (u8 const*)"key expansion", 13, - ReadonlyBytes { m_context.remote_random, sizeof(m_context.remote_random) }, - ReadonlyBytes { m_context.local_random, sizeof(m_context.local_random) }); - - size_t offset = 0; - if (is_aead) { - iv_size = 4; // Explicit IV size. - } else { - memcpy(m_context.crypto.local_mac, key + offset, mac_size); - offset += mac_size; - memcpy(m_context.crypto.remote_mac, key + offset, mac_size); - offset += mac_size; - } - - auto client_key = key + offset; - offset += key_size; - auto server_key = key + offset; - offset += key_size; - auto client_iv = key + offset; - offset += iv_size; - auto server_iv = key + offset; - offset += iv_size; - - if constexpr (TLS_DEBUG) { - dbgln("client key"); - print_buffer(client_key, key_size); - dbgln("server key"); - print_buffer(server_key, key_size); - dbgln("client iv"); - print_buffer(client_iv, iv_size); - dbgln("server iv"); - print_buffer(server_iv, iv_size); - if (!is_aead) { - dbgln("client mac key"); - print_buffer(m_context.crypto.local_mac, mac_size); - dbgln("server mac key"); - print_buffer(m_context.crypto.remote_mac, mac_size); - } - } - - switch (get_cipher_algorithm(m_context.cipher)) { - case CipherAlgorithm::AES_128_CBC: - case CipherAlgorithm::AES_256_CBC: { - VERIFY(!is_aead); - memcpy(m_context.crypto.local_iv, client_iv, iv_size); - memcpy(m_context.crypto.remote_iv, server_iv, iv_size); - - m_cipher_local = Crypto::Cipher::AESCipher::CBCMode(ReadonlyBytes { client_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Encryption, Crypto::Cipher::PaddingMode::RFC5246); - m_cipher_remote = Crypto::Cipher::AESCipher::CBCMode(ReadonlyBytes { server_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Decryption, Crypto::Cipher::PaddingMode::RFC5246); - break; - } - case CipherAlgorithm::AES_128_GCM: - case CipherAlgorithm::AES_256_GCM: { - VERIFY(is_aead); - memcpy(m_context.crypto.local_aead_iv, client_iv, iv_size); - memcpy(m_context.crypto.remote_aead_iv, server_iv, iv_size); - - m_cipher_local = Crypto::Cipher::AESCipher::GCMMode(ReadonlyBytes { client_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Encryption, Crypto::Cipher::PaddingMode::RFC5246); - m_cipher_remote = Crypto::Cipher::AESCipher::GCMMode(ReadonlyBytes { server_key, key_size }, key_size * 8, Crypto::Cipher::Intent::Decryption, Crypto::Cipher::PaddingMode::RFC5246); - break; - } - case CipherAlgorithm::AES_128_CCM: - dbgln("Requested unimplemented AES CCM cipher"); - TODO(); - case CipherAlgorithm::AES_128_CCM_8: - dbgln("Requested unimplemented AES CCM-8 block cipher"); - TODO(); - default: - dbgln("Requested unknown block cipher"); - VERIFY_NOT_REACHED(); - } - - m_context.crypto.created = 1; - - return true; -} - -bool TLSv12::compute_master_secret_from_pre_master_secret(size_t length) -{ - if (m_context.premaster_key.size() == 0 || length < 48) { - dbgln("there's no way I can make a master secret like this"); - dbgln("I'd like to talk to your manager about this length of {}", length); - return false; - } - - if (m_context.master_key.try_resize(length).is_error()) { - dbgln("Couldn't allocate enough space for the master key :("); - return false; - } - - if (m_context.extensions.extended_master_secret) { - Crypto::Hash::Manager handshake_hash_copy = m_context.handshake_hash.copy(); - auto digest = handshake_hash_copy.digest(); - auto session_hash = ReadonlyBytes { digest.immutable_data(), handshake_hash_copy.digest_size() }; - - pseudorandom_function( - m_context.master_key, - m_context.premaster_key, - (u8 const*)"extended master secret", 22, - session_hash, - {}); - } else { - pseudorandom_function( - m_context.master_key, - m_context.premaster_key, - (u8 const*)"master secret", 13, - ReadonlyBytes { m_context.local_random, sizeof(m_context.local_random) }, - ReadonlyBytes { m_context.remote_random, sizeof(m_context.remote_random) }); - } - - m_context.premaster_key.clear(); - if constexpr (TLS_DEBUG) { - dbgln("master key:"); - print_buffer(m_context.master_key); - } - - expand_key(); - return true; -} - -void TLSv12::build_rsa_pre_master_secret(PacketBuilder& builder) -{ - u8 random_bytes[48]; - size_t bytes = 48; - - Crypto::fill_with_secure_random(random_bytes); - - // remove zeros from the random bytes - for (size_t i = 0; i < bytes; ++i) { - if (!random_bytes[i]) - random_bytes[i--] = get_random(); - } - - if (m_context.is_server) { - dbgln("Server mode not supported"); - return; - } else { - *(u16*)random_bytes = AK::convert_between_host_and_network_endian((u16)ProtocolVersion::VERSION_1_2); - } - - auto premaster_key_result = ByteBuffer::copy(random_bytes, bytes); - if (premaster_key_result.is_error()) { - dbgln("RSA premaster key generation failed, not enough memory"); - return; - } - m_context.premaster_key = premaster_key_result.release_value(); - - // RFC5246 section 7.4.2: The sender's certificate MUST come first in the list. - auto& certificate = m_context.certificates.first(); - if constexpr (TLS_DEBUG) { - dbgln("PreMaster secret"); - print_buffer(m_context.premaster_key); - } - - Crypto::PK::RSA_PKCS1_EME rsa(certificate.public_key.rsa); - auto outbuf = MUST(rsa.encrypt(m_context.premaster_key)); - - if constexpr (TLS_DEBUG) { - dbgln("Encrypted: "); - print_buffer(outbuf); - } - - builder.append_u24(outbuf.size() + 2); - builder.append((u16)outbuf.size()); - builder.append(outbuf); -} - -void TLSv12::build_dhe_rsa_pre_master_secret(PacketBuilder& builder) -{ - auto& dh = m_context.server_diffie_hellman_params; - auto dh_p = Crypto::UnsignedBigInteger::import_data(dh.p.data(), dh.p.size()); - auto dh_g = Crypto::UnsignedBigInteger::import_data(dh.g.data(), dh.g.size()); - auto dh_Ys = Crypto::UnsignedBigInteger::import_data(dh.Ys.data(), dh.Ys.size()); - auto dh_key_size = dh.p.size(); - - auto dh_random = Crypto::NumberTheory::random_number(0, dh_p); - auto dh_Yc = Crypto::NumberTheory::ModularPower(dh_g, dh_random, dh_p); - auto dh_Yc_bytes_result = ByteBuffer::create_uninitialized(dh_key_size); - if (dh_Yc_bytes_result.is_error()) { - dbgln("Failed to build DHE_RSA premaster secret: not enough memory"); - return; - } - auto dh_Yc_bytes = dh_Yc_bytes_result.release_value(); - dh_Yc.export_data(dh_Yc_bytes); - - auto premaster_key = Crypto::NumberTheory::ModularPower(dh_Ys, dh_random, dh_p); - auto premaster_key_result = ByteBuffer::create_uninitialized(dh_key_size); - if (premaster_key_result.is_error()) { - dbgln("Failed to build DHE_RSA premaster secret: not enough memory"); - return; - } - m_context.premaster_key = premaster_key_result.release_value(); - premaster_key.export_data(m_context.premaster_key, true); - - dh.p.clear(); - dh.g.clear(); - dh.Ys.clear(); - - if constexpr (TLS_DEBUG) { - dbgln("dh_random: {}", dh_random.to_base_deprecated(16)); - dbgln("dh_Yc: {:hex-dump}", (ReadonlyBytes)dh_Yc_bytes); - dbgln("premaster key: {:hex-dump}", (ReadonlyBytes)m_context.premaster_key); - } - - builder.append_u24(dh_key_size + 2); - builder.append((u16)dh_key_size); - builder.append(dh_Yc_bytes); -} - -void TLSv12::build_ecdhe_rsa_pre_master_secret(PacketBuilder& builder) -{ - // Create a random private key - auto private_key_result = m_context.server_key_exchange_curve->generate_private_key(); - if (private_key_result.is_error()) { - dbgln("Failed to build ECDHE_RSA premaster secret: not enough memory"); - return; - } - auto private_key = private_key_result.release_value(); - - // Calculate the public key from the private key - auto public_key_result = m_context.server_key_exchange_curve->generate_public_key(private_key); - if (public_key_result.is_error()) { - dbgln("Failed to build ECDHE_RSA premaster secret: not enough memory"); - return; - } - auto public_key = public_key_result.release_value(); - - // Calculate the shared point by multiplying the client private key and the server public key - ReadonlyBytes server_public_key_bytes = m_context.server_diffie_hellman_params.p; - auto shared_point_result = m_context.server_key_exchange_curve->compute_coordinate(private_key, server_public_key_bytes); - if (shared_point_result.is_error()) { - dbgln("Failed to build ECDHE_RSA premaster secret: not enough memory"); - return; - } - auto shared_point = shared_point_result.release_value(); - - // Derive the premaster key from the shared point - auto premaster_key_result = m_context.server_key_exchange_curve->derive_premaster_key(shared_point); - if (premaster_key_result.is_error()) { - dbgln("Failed to build ECDHE_RSA premaster secret: not enough memory"); - return; - } - m_context.premaster_key = premaster_key_result.release_value(); - - if constexpr (TLS_DEBUG) { - dbgln("Build ECDHE_RSA pre master secret"); - dbgln("client private key: {:hex-dump}", (ReadonlyBytes)private_key); - dbgln("client public key: {:hex-dump}", (ReadonlyBytes)public_key); - dbgln("premaster key: {:hex-dump}", (ReadonlyBytes)m_context.premaster_key); - } - - builder.append_u24(public_key.size() + 1); - builder.append((u8)public_key.size()); - builder.append(public_key); -} - -ByteBuffer TLSv12::build_certificate() -{ - PacketBuilder builder { ContentType::HANDSHAKE, m_context.options.version }; - - Vector certificates; - Vector* local_certificates = nullptr; - - if (m_context.is_server) { - dbgln("Unsupported: Server mode"); - VERIFY_NOT_REACHED(); - } else { - local_certificates = &m_context.client_certificates; - } - - constexpr size_t der_length_delta = 3; - constexpr size_t certificate_vector_header_size = 3; - - size_t total_certificate_size = 0; - - for (size_t i = 0; i < local_certificates->size(); ++i) { - auto& certificate = local_certificates->at(i); - if (!certificate.der.is_empty()) { - total_certificate_size += certificate.der.size() + der_length_delta; - - // FIXME: Check for and respond with only the requested certificate types. - if (true) { - certificates.append(certificate); - } - } - } - - builder.append((u8)HandshakeType::CERTIFICATE); - - if (!total_certificate_size) { - dbgln_if(TLS_DEBUG, "No certificates, sending empty certificate message"); - builder.append_u24(certificate_vector_header_size); - builder.append_u24(total_certificate_size); - } else { - builder.append_u24(total_certificate_size + certificate_vector_header_size); // 3 bytes for header - builder.append_u24(total_certificate_size); - - for (auto& certificate : certificates) { - if (!certificate.der.is_empty()) { - builder.append_u24(certificate.der.size()); - builder.append(certificate.der.bytes()); - } - } - } - auto packet = builder.build(); - update_packet(packet); - return packet; -} - -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::BAD_CERTIFICATE); - return {}; - } - - PacketBuilder builder { ContentType::HANDSHAKE, m_context.options.version }; - builder.append((u8)HandshakeType::CLIENT_KEY_EXCHANGE_RESERVED); - - switch (get_key_exchange_algorithm(m_context.cipher)) { - case KeyExchangeAlgorithm::RSA: - build_rsa_pre_master_secret(builder); - break; - case KeyExchangeAlgorithm::DHE_DSS: - dbgln("Client key exchange for DHE_DSS is not implemented"); - TODO(); - break; - case KeyExchangeAlgorithm::DH_DSS: - case KeyExchangeAlgorithm::DH_RSA: - dbgln("Client key exchange for DH algorithms is not implemented"); - TODO(); - break; - case KeyExchangeAlgorithm::DHE_RSA: - build_dhe_rsa_pre_master_secret(builder); - break; - case KeyExchangeAlgorithm::DH_anon: - dbgln("Client key exchange for DH_anon is not implemented"); - 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::ECDH_anon: - dbgln("Client key exchange for ECDHE algorithms is not implemented"); - TODO(); - break; - default: - dbgln("Unknown client key exchange algorithm"); - VERIFY_NOT_REACHED(); - break; - } - - m_context.connection_status = ConnectionStatus::KeyExchange; - - auto packet = builder.build(); - - update_packet(packet); - - if (!compute_master_secret_from_pre_master_secret(48)) { - dbgln("oh noes we could not derive a master key :("); - } - - return packet; -} - -} diff --git a/Libraries/LibTLS/HandshakeServer.cpp b/Libraries/LibTLS/HandshakeServer.cpp deleted file mode 100644 index 616ced50211..00000000000 --- a/Libraries/LibTLS/HandshakeServer.cpp +++ /dev/null @@ -1,532 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * Copyright (c) 2022, Michiel Visser - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace TLS { - -ssize_t TLSv12::handle_server_hello(ReadonlyBytes buffer, WritePacketStage& write_packets) -{ - write_packets = WritePacketStage::Initial; - if (m_context.connection_status != ConnectionStatus::Disconnected && m_context.connection_status != ConnectionStatus::Renegotiating) { - dbgln("unexpected hello message"); - return (i8)Error::UnexpectedMessage; - } - ssize_t res = 0; - size_t min_hello_size = 41; - - if (min_hello_size > buffer.size()) { - dbgln("need more data"); - return (i8)Error::NeedMoreData; - } - size_t following_bytes = buffer[0] * 0x10000 + buffer[1] * 0x100 + buffer[2]; - res += 3; - if (buffer.size() - res < following_bytes) { - dbgln("not enough data after header: {} < {}", buffer.size() - res, following_bytes); - return (i8)Error::NeedMoreData; - } - - if (buffer.size() - res < 2) { - dbgln("not enough data for version"); - return (i8)Error::NeedMoreData; - } - auto version = static_cast(AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(res)))); - - res += 2; - if (!supports_version(version)) - return (i8)Error::NotSafe; - - memcpy(m_context.remote_random, buffer.offset_pointer(res), sizeof(m_context.remote_random)); - res += sizeof(m_context.remote_random); - - u8 session_length = buffer[res++]; - if (buffer.size() - res < session_length) { - dbgln("not enough data for session id"); - return (i8)Error::NeedMoreData; - } - - if (session_length && session_length <= 32) { - memcpy(m_context.session_id, buffer.offset_pointer(res), session_length); - m_context.session_id_size = session_length; - if constexpr (TLS_DEBUG) { - dbgln("Remote session ID:"); - print_buffer(ReadonlyBytes { m_context.session_id, session_length }); - } - } else { - m_context.session_id_size = 0; - } - res += session_length; - - if (buffer.size() - res < 2) { - dbgln("not enough data for cipher suite listing"); - return (i8)Error::NeedMoreData; - } - auto cipher = static_cast(AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(res)))); - res += 2; - if (!supports_cipher(cipher)) { - m_context.cipher = CipherSuite::TLS_NULL_WITH_NULL_NULL; - dbgln("No supported cipher could be agreed upon"); - return (i8)Error::NoCommonCipher; - } - m_context.cipher = cipher; - dbgln_if(TLS_DEBUG, "Cipher: {}", enum_to_string(cipher)); - - // Simplification: We only support handshake hash functions via HMAC - m_context.handshake_hash.initialize(hmac_hash()); - - // Compression method - if (buffer.size() - res < 1) - return (i8)Error::NeedMoreData; - u8 compression = buffer[res++]; - if (compression != 0) - return (i8)Error::CompressionNotSupported; - - if (m_context.connection_status != ConnectionStatus::Renegotiating) - m_context.connection_status = ConnectionStatus::Negotiating; - if (m_context.is_server) { - dbgln("unsupported: server mode"); - write_packets = WritePacketStage::ServerHandshake; - } - - // Presence of extensions is determined by availability of bytes after compression_method - if (buffer.size() - res >= 2) { - auto extensions_bytes_total = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(res += 2))); - dbgln_if(TLS_DEBUG, "Extensions bytes total: {}", extensions_bytes_total); - } - - while (buffer.size() - res >= 4) { - auto extension_type = (ExtensionType)AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(res))); - res += 2; - u16 extension_length = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(res))); - res += 2; - - dbgln_if(TLS_DEBUG, "Extension {} with length {}", enum_to_string(extension_type), extension_length); - - if (buffer.size() - res < extension_length) - return (i8)Error::NeedMoreData; - - if (extension_type == ExtensionType::SERVER_NAME) { - // RFC6066 section 3: SNI extension_data can be empty in the server hello - if (extension_length > 0) { - // ServerNameList total size - if (buffer.size() - res < 2) - return (i8)Error::NeedMoreData; - auto sni_name_list_bytes = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(res += 2))); - dbgln_if(TLS_DEBUG, "SNI: expecting ServerNameList of {} bytes", sni_name_list_bytes); - - // Exactly one ServerName should be present - if (buffer.size() - res < 3) - return (i8)Error::NeedMoreData; - auto sni_name_type = (NameType)(*(u8 const*)buffer.offset_pointer(res++)); - auto sni_name_length = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(res += 2))); - - if (sni_name_type != NameType::HOST_NAME) - return (i8)Error::NotUnderstood; - - if (sizeof(sni_name_type) + sizeof(sni_name_length) + sni_name_length != sni_name_list_bytes) - return (i8)Error::BrokenPacket; - - // Read out the host_name - if (buffer.size() - res < sni_name_length) - return (i8)Error::NeedMoreData; - m_context.extensions.SNI = ByteString { (char const*)buffer.offset_pointer(res), sni_name_length }; - res += sni_name_length; - dbgln("SNI host_name: {}", m_context.extensions.SNI); - } - } else if (extension_type == ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION && m_context.alpn.size()) { - if (buffer.size() - res > 2) { - auto alpn_length = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(res))); - if (alpn_length && alpn_length <= extension_length - 2) { - u8 const* alpn = buffer.offset_pointer(res + 2); - size_t alpn_position = 0; - while (alpn_position < alpn_length) { - u8 alpn_size = alpn[alpn_position++]; - if (alpn_size + alpn_position >= extension_length) - break; - ByteString alpn_str { (char const*)alpn + alpn_position, alpn_length }; - if (alpn_size && m_context.alpn.contains_slow(alpn_str)) { - m_context.negotiated_alpn = alpn_str; - dbgln("negotiated alpn: {}", alpn_str); - break; - } - alpn_position += alpn_length; - if (!m_context.is_server) // server hello must contain one ALPN - break; - } - } - } - res += extension_length; - } else if (extension_type == ExtensionType::SIGNATURE_ALGORITHMS) { - dbgln("supported signatures: "); - print_buffer(buffer.slice(res, extension_length)); - res += extension_length; - // FIXME: what are we supposed to do here? - } else if (extension_type == ExtensionType::EC_POINT_FORMATS) { - // RFC8422 section 5.2: A server that selects an ECC cipher suite in response to a ClientHello message - // including a Supported Point Formats Extension appends this extension (along with others) to its - // ServerHello message, enumerating the point formats it can parse. The Supported Point Formats Extension, - // when used, MUST contain the value 0 (uncompressed) as one of the items in the list of point formats. - // - // The current implementation only supports uncompressed points, and the server is required to support - // uncompressed points. Therefore, this extension can be safely ignored as it should always inform us - // that the server supports uncompressed points. - res += extension_length; - } else if (extension_type == ExtensionType::EXTENDED_MASTER_SECRET) { - m_context.extensions.extended_master_secret = true; - res += extension_length; - } else { - dbgln("Encountered unknown extension {} with length {}", enum_to_string(extension_type), extension_length); - res += extension_length; - } - } - - return res; -} - -ssize_t TLSv12::handle_server_hello_done(ReadonlyBytes buffer) -{ - if (buffer.size() < 3) - return (i8)Error::NeedMoreData; - - size_t size = buffer[0] * 0x10000 + buffer[1] * 0x100 + buffer[2]; - - if (buffer.size() - 3 < size) - return (i8)Error::NeedMoreData; - - return size + 3; -} - -ByteBuffer TLSv12::build_server_key_exchange() -{ - dbgln("FIXME: build_server_key_exchange"); - return {}; -} - -ssize_t TLSv12::handle_server_key_exchange(ReadonlyBytes buffer) -{ - switch (get_key_exchange_algorithm(m_context.cipher)) { - case KeyExchangeAlgorithm::RSA: - case KeyExchangeAlgorithm::DH_DSS: - case KeyExchangeAlgorithm::DH_RSA: - // RFC 5246 section 7.4.3. Server Key Exchange Message - // It is not legal to send the server key exchange message for RSA, DH_DSS, DH_RSA - dbgln("Server key exchange received for RSA, DH_DSS or DH_RSA is not legal"); - return (i8)Error::UnexpectedMessage; - case KeyExchangeAlgorithm::DHE_DSS: - dbgln("Server key exchange for DHE_DSS is not implemented"); - TODO(); - break; - case KeyExchangeAlgorithm::DHE_RSA: - return handle_dhe_rsa_server_key_exchange(buffer); - case KeyExchangeAlgorithm::DH_anon: - dbgln("Server key exchange for DH_anon is not implemented"); - TODO(); - 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::ECDH_anon: - dbgln("Server key exchange for ECDHE algorithms is not implemented"); - TODO(); - break; - default: - dbgln("Unknown server key exchange algorithm"); - VERIFY_NOT_REACHED(); - break; - } - return 0; -} - -ssize_t TLSv12::handle_dhe_rsa_server_key_exchange(ReadonlyBytes buffer) -{ - auto dh_p_length = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(3))); - auto dh_p = buffer.slice(5, dh_p_length); - auto p_result = ByteBuffer::copy(dh_p); - if (p_result.is_error()) { - dbgln("dhe_rsa_server_key_exchange failed: Not enough memory"); - return (i8)Error::OutOfMemory; - } - m_context.server_diffie_hellman_params.p = p_result.release_value(); - - auto dh_g_length = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(5 + dh_p_length))); - auto dh_g = buffer.slice(7 + dh_p_length, dh_g_length); - auto g_result = ByteBuffer::copy(dh_g); - if (g_result.is_error()) { - dbgln("dhe_rsa_server_key_exchange failed: Not enough memory"); - return (i8)Error::OutOfMemory; - } - m_context.server_diffie_hellman_params.g = g_result.release_value(); - - auto dh_Ys_length = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(7 + dh_p_length + dh_g_length))); - auto dh_Ys = buffer.slice(9 + dh_p_length + dh_g_length, dh_Ys_length); - auto Ys_result = ByteBuffer::copy(dh_Ys); - if (Ys_result.is_error()) { - dbgln("dhe_rsa_server_key_exchange failed: Not enough memory"); - return (i8)Error::OutOfMemory; - } - m_context.server_diffie_hellman_params.Ys = Ys_result.release_value(); - - if constexpr (TLS_DEBUG) { - dbgln("dh_p: {:hex-dump}", dh_p); - dbgln("dh_g: {:hex-dump}", dh_g); - dbgln("dh_Ys: {:hex-dump}", dh_Ys); - } - - auto server_key_info = buffer.slice(3, 6 + dh_p_length + dh_g_length + dh_Ys_length); - auto signature = buffer.slice(9 + dh_p_length + dh_g_length + dh_Ys_length); - return verify_rsa_server_key_exchange(server_key_info, signature); -} - -ssize_t TLSv12::handle_ecdhe_server_key_exchange(ReadonlyBytes buffer, u8& server_public_key_length) -{ - if (buffer.size() < 7) - return (i8)Error::NeedMoreData; - - auto curve_type = buffer[3]; - if (curve_type != (u8)ECCurveType::NAMED_CURVE) - return (i8)Error::NotUnderstood; - - auto curve = static_cast(AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(4)))); - if (!m_context.options.elliptic_curves.contains_slow(curve)) - return (i8)Error::NotUnderstood; - - switch ((SupportedGroup)curve) { - case SupportedGroup::X25519: - m_context.server_key_exchange_curve = make(); - break; - case SupportedGroup::X448: - m_context.server_key_exchange_curve = make(); - break; - case SupportedGroup::SECP256R1: - m_context.server_key_exchange_curve = make(); - break; - case SupportedGroup::SECP384R1: - m_context.server_key_exchange_curve = make(); - break; - default: - return (i8)Error::NotUnderstood; - } - - server_public_key_length = buffer[6]; - if (server_public_key_length != m_context.server_key_exchange_curve->key_size()) - return (i8)Error::NotUnderstood; - - if (buffer.size() < 7u + server_public_key_length) - return (i8)Error::NeedMoreData; - - auto server_public_key = buffer.slice(7, server_public_key_length); - auto server_public_key_copy_result = ByteBuffer::copy(server_public_key); - if (server_public_key_copy_result.is_error()) { - dbgln("ecdhe_rsa_server_key_exchange failed: Not enough memory"); - return (i8)Error::OutOfMemory; - } - m_context.server_diffie_hellman_params.p = server_public_key_copy_result.release_value(); - - if constexpr (TLS_DEBUG) { - 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); -} - -ssize_t TLSv12::verify_rsa_server_key_exchange(ReadonlyBytes server_key_info_buffer, ReadonlyBytes signature_buffer) -{ - auto signature_hash = signature_buffer[0]; - auto signature_algorithm = static_cast(signature_buffer[1]); - if (signature_algorithm != SignatureAlgorithm::RSA) { - dbgln("verify_rsa_server_key_exchange failed: Signature algorithm is not RSA, instead {}", enum_to_string(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_rsa_server_key_exchange failed: Attempting to verify signature without certificates"); - return (i8)Error::NotSafe; - } - // RFC5246 section 7.4.2: The sender's certificate MUST come first in the list. - - auto message_result = ByteBuffer::create_uninitialized(64 + server_key_info_buffer.size()); - if (message_result.is_error()) { - dbgln("verify_rsa_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::SHA1: - hash_kind = Crypto::Hash::HashKind::SHA1; - break; - 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_rsa_server_key_exchange failed: Hash algorithm is not SHA1/256/384/512, instead {}", signature_hash); - return (i8)Error::NotUnderstood; - } - - auto certificate_public_key = m_context.certificates.first().public_key; - auto rsa = Crypto::PK::RSA_PKCS1_EMSA(hash_kind, certificate_public_key.rsa); - auto verification = MUST(rsa.verify(message, signature)); - - if (!verification) { - dbgln("verify_rsa_server_key_exchange failed: Verification of signature inconsistent"); - return (i8)Error::NotSafe; - } - - 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_bytes = 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; - } - auto server_point = m_context.certificates.first().public_key.ec.to_secpxxxr1_point(); - - 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 res = AK::Error::from_errno(ENOTSUP); - auto& public_key = m_context.certificates.first().public_key; - auto ec_curve = oid_to_curve(public_key.algorithm.ec_parameters.value_or({})); - if (ec_curve.is_error()) { - dbgln("verify_ecdsa_server_key_exchange failed: Unknown curve for ECDSA signature verification"); - return (i8)Error::NotUnderstood; - } - - auto maybe_signature = Crypto::Curves::SECPxxxr1Signature::from_asn(*public_key.algorithm.ec_parameters, signature_bytes, {}); - if (maybe_signature.is_error()) { - dbgln("verify_ecdsa_server_key_exchange failed: Signature is not ASN.1 DER encoded"); - return (i8)Error::NotUnderstood; - } - - auto signature = maybe_signature.release_value(); - - switch (ec_curve.release_value()) { - case SupportedGroup::SECP256R1: { - Crypto::Hash::Manager manager(hash_kind); - manager.update(message); - auto digest = manager.digest(); - - Crypto::Curves::SECP256r1 curve; - res = curve.verify_point(digest.bytes(), server_point, signature); - break; - } - case SupportedGroup::SECP384R1: { - Crypto::Hash::Manager manager(hash_kind); - manager.update(message); - auto digest = manager.digest(); - - Crypto::Curves::SECP384r1 curve; - res = curve.verify_point(digest.bytes(), server_point, signature); - break; - } - default: { - dbgln("verify_ecdsa_server_key_exchange failed: Server certificate public key algorithm is not supported: {}", to_underlying(ec_curve.release_value())); - 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; -} - -} diff --git a/Libraries/LibTLS/OpenSSLForward.h b/Libraries/LibTLS/OpenSSLForward.h new file mode 100644 index 00000000000..24ac99947da --- /dev/null +++ b/Libraries/LibTLS/OpenSSLForward.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2025, Altomani Gianluca + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +extern "C" { +typedef struct ssl_ctx_st SSL_CTX; +typedef struct ssl_st SSL; +typedef struct bio_st BIO; +} diff --git a/Libraries/LibTLS/Record.cpp b/Libraries/LibTLS/Record.cpp deleted file mode 100644 index eb3ef549686..00000000000 --- a/Libraries/LibTLS/Record.cpp +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace TLS { - -ByteBuffer TLSv12::build_alert(bool critical, u8 code) -{ - PacketBuilder builder(ContentType::ALERT, (u16)m_context.options.version); - builder.append((u8)(critical ? AlertLevel::FATAL : AlertLevel::WARNING)); - builder.append(code); - - if (critical) - m_context.critical_error = code; - - auto packet = builder.build(); - update_packet(packet); - - return packet; -} - -void TLSv12::alert(AlertLevel level, AlertDescription code) -{ - auto the_alert = build_alert(level == AlertLevel::FATAL, (u8)code); - write_packet(the_alert, true); - MUST(flush()); -} - -void TLSv12::write_packet(ByteBuffer& packet, bool immediately) -{ - auto schedule_or_perform_flush = [&](bool immediate) { - if (m_context.connection_status > ConnectionStatus::Disconnected) { - if (!m_has_scheduled_write_flush && !immediate) { - dbgln_if(TLS_DEBUG, "Scheduling write of {}", m_context.tls_buffer.size()); - Core::deferred_invoke([this] { write_into_socket(); }); - m_has_scheduled_write_flush = true; - } else { - // multiple packet are available, let's flush some out - dbgln_if(TLS_DEBUG, "Flushing scheduled write of {}", m_context.tls_buffer.size()); - write_into_socket(); - // the deferred invoke is still in place - m_has_scheduled_write_flush = true; - } - } - }; - // Record size limit is 18432 bytes, leave some headroom and flush at 16K. - if (m_context.tls_buffer.size() + packet.size() > 16 * KiB) - schedule_or_perform_flush(true); - - if (m_context.tls_buffer.try_append(packet.data(), packet.size()).is_error()) { - // Toooooo bad, drop the record on the ground. - return; - } - schedule_or_perform_flush(immediately); -} - -void TLSv12::update_packet(ByteBuffer& packet) -{ - u32 header_size = 5; - ByteReader::store(packet.offset_pointer(3), AK::convert_between_host_and_network_endian((u16)(packet.size() - header_size))); - - if (packet[0] != (u8)ContentType::CHANGE_CIPHER_SPEC) { - if (packet[0] == (u8)ContentType::HANDSHAKE && packet.size() > header_size) { - auto handshake_type = static_cast(packet[header_size]); - if (handshake_type != HandshakeType::HELLO_REQUEST_RESERVED && handshake_type != HandshakeType::HELLO_VERIFY_REQUEST_RESERVED) { - update_hash(packet.bytes(), header_size); - } - } - if (m_context.cipher_spec_set && m_context.crypto.created) { - size_t length = packet.size() - header_size; - size_t block_size = 0; - size_t padding = 0; - size_t mac_size = 0; - - m_cipher_local.visit( - [&](Empty&) { VERIFY_NOT_REACHED(); }, - [&](Crypto::Cipher::AESCipher::GCMMode& gcm) { - VERIFY(is_aead()); - block_size = gcm.cipher().block_size(); - padding = 0; - mac_size = 0; // AEAD provides its own authentication scheme. - }, - [&](Crypto::Cipher::AESCipher::CBCMode& cbc) { - VERIFY(!is_aead()); - block_size = cbc.cipher().block_size(); - // If the length is already a multiple a block_size, - // an entire block of padding is added. - // In short, we _never_ have no padding. - mac_size = mac_length(); - length += mac_size; - padding = block_size - length % block_size; - length += padding; - }); - - if (m_context.crypto.created == 1) { - // `buffer' will continue to be encrypted - auto buffer_result = ByteBuffer::create_uninitialized(length); - if (buffer_result.is_error()) { - dbgln("LibTLS: Failed to allocate enough memory"); - VERIFY_NOT_REACHED(); - } - auto buffer = buffer_result.release_value(); - size_t buffer_position = 0; - auto iv_size = iv_length(); - - // copy the packet, sans the header - buffer.overwrite(buffer_position, packet.offset_pointer(header_size), packet.size() - header_size); - buffer_position += packet.size() - header_size; - - ByteBuffer ct; - - m_cipher_local.visit( - [&](Empty&) { VERIFY_NOT_REACHED(); }, - [&](Crypto::Cipher::AESCipher::GCMMode& gcm) { - VERIFY(is_aead()); - // We need enough space for a header, the data, a tag, and the IV - auto ct_buffer_result = ByteBuffer::create_uninitialized(length + header_size + iv_size + 16); - if (ct_buffer_result.is_error()) { - dbgln("LibTLS: Failed to allocate enough memory for the ciphertext"); - VERIFY_NOT_REACHED(); - } - ct = ct_buffer_result.release_value(); - - // copy the header over - ct.overwrite(0, packet.data(), header_size - 2); - - // AEAD AAD (13) - // Seq. no (8) - // content type (1) - // version (2) - // length (2) - u8 aad[13]; - Bytes aad_bytes { aad, 13 }; - FixedMemoryStream aad_stream { aad_bytes }; - - u64 seq_no = AK::convert_between_host_and_network_endian(m_context.local_sequence_number); - u16 len = AK::convert_between_host_and_network_endian((u16)(packet.size() - header_size)); - - MUST(aad_stream.write_value(seq_no)); // sequence number - MUST(aad_stream.write_until_depleted(packet.bytes().slice(0, 3))); // content-type + version - MUST(aad_stream.write_value(len)); // length - VERIFY(MUST(aad_stream.tell()) == MUST(aad_stream.size())); - - // AEAD IV (12) - // IV (4) - // (Nonce) (8) - u8 iv[12]; - Bytes iv_bytes { iv, 12 }; - Bytes { m_context.crypto.local_aead_iv, 4 }.copy_to(iv_bytes); - Crypto::fill_with_secure_random(iv_bytes.slice(4, 8)); - - // write the random part of the iv out - iv_bytes.slice(4, 8).copy_to(ct.bytes().slice(header_size)); - - // Write the encrypted data and the tag - gcm.encrypt( - packet.bytes().slice(header_size, length), - ct.bytes().slice(header_size + 8, length), - iv_bytes, - aad_bytes, - ct.bytes().slice(header_size + 8 + length, 16)); - - VERIFY(header_size + 8 + length + 16 == ct.size()); - }, - [&](Crypto::Cipher::AESCipher::CBCMode& cbc) { - VERIFY(!is_aead()); - // We need enough space for a header, iv_length bytes of IV and whatever the packet contains - auto ct_buffer_result = ByteBuffer::create_uninitialized(length + header_size + iv_size); - if (ct_buffer_result.is_error()) { - dbgln("LibTLS: Failed to allocate enough memory for the ciphertext"); - VERIFY_NOT_REACHED(); - } - ct = ct_buffer_result.release_value(); - - // copy the header over - ct.overwrite(0, packet.data(), header_size - 2); - - // get the appropriate HMAC value for the entire packet - auto mac = hmac_message(packet, {}, mac_size, true); - - // write the MAC - buffer.overwrite(buffer_position, mac.data(), mac.size()); - buffer_position += mac.size(); - - // Apply the padding (a packet MUST always be padded) - memset(buffer.offset_pointer(buffer_position), padding - 1, padding); - buffer_position += padding; - - VERIFY(buffer_position == buffer.size()); - - auto iv_buffer_result = ByteBuffer::create_uninitialized(iv_size); - if (iv_buffer_result.is_error()) { - dbgln("LibTLS: Failed to allocate memory for IV"); - VERIFY_NOT_REACHED(); - } - auto iv = iv_buffer_result.release_value(); - Crypto::fill_with_secure_random(iv); - - // write it into the ciphertext portion of the message - ct.overwrite(header_size, iv.data(), iv.size()); - - VERIFY(header_size + iv_size + length == ct.size()); - VERIFY(length % block_size == 0); - - // get a block to encrypt into - auto view = ct.bytes().slice(header_size + iv_size, length); - cbc.encrypt(buffer, view, iv); - // Note: 'view' is dropped without checking 'view.size()'. - // This is okay because TLSv12::expand_key sets PaddingMode::RFC5246, which never adds a block. - }); - - // store the correct ciphertext length into the packet - u16 ct_length = (u16)ct.size() - header_size; - - ByteReader::store(ct.offset_pointer(header_size - 2), AK::convert_between_host_and_network_endian(ct_length)); - - // replace the packet with the ciphertext - packet = ct; - } - } - } - ++m_context.local_sequence_number; -} - -void TLSv12::update_hash(ReadonlyBytes message, size_t header_size) -{ - dbgln_if(TLS_DEBUG, "Update hash with message of size {}", message.size()); - m_context.handshake_hash.update(message.slice(header_size)); -} - -void TLSv12::ensure_hmac(size_t digest_size, bool local) -{ - if (local && m_hmac_local) - return; - - if (!local && m_hmac_remote) - return; - - auto hash_kind = Crypto::Hash::HashKind::None; - - switch (digest_size) { - case Crypto::Hash::SHA1::DigestSize: - hash_kind = Crypto::Hash::HashKind::SHA1; - break; - case Crypto::Hash::SHA256::DigestSize: - hash_kind = Crypto::Hash::HashKind::SHA256; - break; - case Crypto::Hash::SHA384::DigestSize: - hash_kind = Crypto::Hash::HashKind::SHA384; - break; - case Crypto::Hash::SHA512::DigestSize: - hash_kind = Crypto::Hash::HashKind::SHA512; - break; - default: - dbgln("Failed to find a suitable hash for size {}", digest_size); - break; - } - - auto hmac = make>(ReadonlyBytes { local ? m_context.crypto.local_mac : m_context.crypto.remote_mac, digest_size }, hash_kind); - if (local) - m_hmac_local = move(hmac); - else - m_hmac_remote = move(hmac); -} - -ByteBuffer TLSv12::hmac_message(ReadonlyBytes buf, Optional const buf2, size_t mac_length, bool local) -{ - u64 sequence_number = AK::convert_between_host_and_network_endian(local ? m_context.local_sequence_number : m_context.remote_sequence_number); - ensure_hmac(mac_length, local); - auto& hmac = local ? *m_hmac_local : *m_hmac_remote; - if constexpr (TLS_DEBUG) { - dbgln("========================= PACKET DATA =========================="); - print_buffer((u8 const*)&sequence_number, sizeof(u64)); - print_buffer(buf.data(), buf.size()); - if (buf2.has_value()) - print_buffer(buf2.value().data(), buf2.value().size()); - dbgln("========================= PACKET DATA =========================="); - } - hmac.update((u8 const*)&sequence_number, sizeof(u64)); - hmac.update(buf); - if (buf2.has_value() && buf2.value().size()) { - hmac.update(buf2.value()); - } - auto digest = hmac.digest(); - auto mac_result = ByteBuffer::copy(digest.immutable_data(), digest.data_length()); - if (mac_result.is_error()) { - dbgln("Failed to calculate message HMAC: Not enough memory"); - return {}; - } - - if constexpr (TLS_DEBUG) { - dbgln("HMAC of the block for sequence number {}", sequence_number); - print_buffer(mac_result.value()); - } - - return mac_result.release_value(); -} - -ssize_t TLSv12::handle_message(ReadonlyBytes buffer) -{ - auto res { 5ll }; - size_t header_size = res; - ssize_t payload_res = 0; - - dbgln_if(TLS_DEBUG, "buffer size: {}", buffer.size()); - - if (buffer.size() < 5) { - return (i8)Error::NeedMoreData; - } - - auto type = (ContentType)buffer[0]; - size_t buffer_position { 1 }; - - // FIXME: Read the version and verify it - - if constexpr (TLS_DEBUG) { - auto version = static_cast(ByteReader::load16(buffer.offset_pointer(buffer_position))); - dbgln("type={}, version={}", enum_to_string(type), enum_to_string(version)); - } - - buffer_position += 2; - - auto length = AK::convert_between_host_and_network_endian(ByteReader::load16(buffer.offset_pointer(buffer_position))); - - dbgln_if(TLS_DEBUG, "record length: {} at offset: {}", length, buffer_position); - buffer_position += 2; - - if (buffer_position + length > buffer.size()) { - dbgln_if(TLS_DEBUG, "record length more than what we have: {}", buffer.size()); - return (i8)Error::NeedMoreData; - } - - dbgln_if(TLS_DEBUG, "message type: {}, length: {}", enum_to_string(type), length); - auto plain = buffer.slice(buffer_position, buffer.size() - buffer_position); - - ByteBuffer decrypted; - - if (m_context.cipher_spec_set && type != ContentType::CHANGE_CIPHER_SPEC) { - if constexpr (TLS_DEBUG) { - dbgln("Encrypted: "); - print_buffer(buffer.slice(header_size, length)); - } - - Error return_value = Error::NoError; - m_cipher_remote.visit( - [&](Empty&) { VERIFY_NOT_REACHED(); }, - [&](Crypto::Cipher::AESCipher::GCMMode& gcm) { - VERIFY(is_aead()); - if (length < 24) { - dbgln("Invalid packet length"); - auto packet = build_alert(true, (u8)AlertDescription::DECRYPT_ERROR); - write_packet(packet); - return_value = Error::BrokenPacket; - return; - } - - auto packet_length = length - iv_length() - 16; - auto payload = plain; - auto decrypted_result = ByteBuffer::create_uninitialized(packet_length); - if (decrypted_result.is_error()) { - dbgln("Failed to allocate memory for the packet"); - return_value = Error::DecryptionFailed; - return; - } - decrypted = decrypted_result.release_value(); - - // AEAD AAD (13) - // Seq. no (8) - // content type (1) - // version (2) - // length (2) - u8 aad[13]; - Bytes aad_bytes { aad, 13 }; - FixedMemoryStream aad_stream { aad_bytes }; - - u64 seq_no = AK::convert_between_host_and_network_endian(m_context.remote_sequence_number); - u16 len = AK::convert_between_host_and_network_endian((u16)packet_length); - - MUST(aad_stream.write_value(seq_no)); // sequence number - MUST(aad_stream.write_until_depleted(buffer.slice(0, header_size - 2))); // content-type + version - MUST(aad_stream.write_value(len)); // length - VERIFY(MUST(aad_stream.tell()) == MUST(aad_stream.size())); - - auto nonce = payload.slice(0, iv_length()); - payload = payload.slice(iv_length()); - - // AEAD IV (12) - // IV (4) - // (Nonce) (8) - u8 iv[12]; - Bytes iv_bytes { iv, 12 }; - Bytes { m_context.crypto.remote_aead_iv, 4 }.copy_to(iv_bytes); - nonce.copy_to(iv_bytes.slice(4)); - - auto ciphertext = payload.slice(0, payload.size() - 16); - auto tag = payload.slice(ciphertext.size()); - - auto consistency = gcm.decrypt( - ciphertext, - decrypted, - iv_bytes, - aad_bytes, - tag); - - if (consistency != Crypto::VerificationConsistency::Consistent) { - dbgln("integrity check failed (tag length {})", tag.size()); - auto packet = build_alert(true, (u8)AlertDescription::BAD_RECORD_MAC); - write_packet(packet); - - return_value = Error::IntegrityCheckFailed; - return; - } - - plain = decrypted; - }, - [&](Crypto::Cipher::AESCipher::CBCMode& cbc) { - VERIFY(!is_aead()); - auto iv_size = iv_length(); - - auto decrypted_result = cbc.create_aligned_buffer(length - iv_size); - if (decrypted_result.is_error()) { - dbgln("Failed to allocate memory for the packet"); - return_value = Error::DecryptionFailed; - return; - } - decrypted = decrypted_result.release_value(); - auto iv = buffer.slice(header_size, iv_size); - - Bytes decrypted_span = decrypted; - cbc.decrypt(buffer.slice(header_size + iv_size, length - iv_size), decrypted_span, iv); - - length = decrypted_span.size(); - - if constexpr (TLS_DEBUG) { - dbgln("Decrypted: "); - print_buffer(decrypted); - } - - auto mac_size = mac_length(); - if (length < mac_size) { - dbgln("broken packet"); - auto packet = build_alert(true, (u8)AlertDescription::DECRYPT_ERROR); - write_packet(packet); - return_value = Error::BrokenPacket; - return; - } - - length -= mac_size; - - u8 const* message_hmac = decrypted_span.offset(length); - u8 temp_buf[5]; - memcpy(temp_buf, buffer.offset_pointer(0), 3); - *(u16*)(temp_buf + 3) = AK::convert_between_host_and_network_endian(length); - auto hmac = hmac_message({ temp_buf, 5 }, decrypted_span.slice(0, length), mac_size); - auto message_mac = ReadonlyBytes { message_hmac, mac_size }; - if (hmac != message_mac) { - dbgln("integrity check failed (mac length {})", mac_size); - dbgln("mac received:"); - print_buffer(message_mac); - dbgln("mac computed:"); - print_buffer(hmac); - auto packet = build_alert(true, (u8)AlertDescription::BAD_RECORD_MAC); - write_packet(packet); - - return_value = Error::IntegrityCheckFailed; - return; - } - plain = decrypted.bytes().slice(0, length); - }); - - if (return_value != Error::NoError) { - return (i8)return_value; - } - } - m_context.remote_sequence_number++; - - switch (type) { - case ContentType::APPLICATION_DATA: - if (m_context.connection_status != ConnectionStatus::Established) { - dbgln("unexpected application data"); - payload_res = (i8)Error::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).is_error()) { - payload_res = (i8)Error::DecryptionFailed; - auto packet = build_alert(true, (u8)AlertDescription::DECRYPTION_FAILED_RESERVED); - write_packet(packet); - } else { - notify_client_for_app_data(); - } - } - break; - case ContentType::HANDSHAKE: - dbgln_if(TLS_DEBUG, "tls handshake message"); - payload_res = handle_handshake_payload(plain); - break; - case ContentType::CHANGE_CIPHER_SPEC: - if (m_context.connection_status != ConnectionStatus::KeyExchange) { - dbgln("unexpected change cipher message"); - auto packet = build_alert(true, (u8)AlertDescription::UNEXPECTED_MESSAGE); - write_packet(packet); - payload_res = (i8)Error::UnexpectedMessage; - } else { - dbgln_if(TLS_DEBUG, "change cipher spec message"); - m_context.cipher_spec_set = true; - m_context.remote_sequence_number = 0; - } - break; - case ContentType::ALERT: - dbgln_if(TLS_DEBUG, "alert message of length {}", length); - if (length >= 2) { - if constexpr (TLS_DEBUG) - print_buffer(plain); - - auto level = plain[0]; - auto code = plain[1]; - 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, enum_to_string((AlertDescription)code)); - m_context.critical_error = code; - try_disambiguate_error(); - res = (i8)Error::UnknownError; - } - - if (code == (u8)AlertDescription::CLOSE_NOTIFY) { - res += 2; - 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::HANDSHAKE_FAILURE; - try_disambiguate_error(); - } - m_context.close_notify = true; - } - m_context.error_code = (Error)code; - check_connection_state(false); - notify_client_for_app_data(); // Give the user one more chance to observe the EOF - } - break; - default: - dbgln("message not understood"); - return (i8)Error::NotUnderstood; - } - - if (payload_res < 0) - return payload_res; - - if (res > 0) - return header_size + length; - - return res; -} - -} diff --git a/Libraries/LibTLS/Socket.cpp b/Libraries/LibTLS/Socket.cpp deleted file mode 100644 index 42eb9350fb3..00000000000 --- a/Libraries/LibTLS/Socket.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -// Each record can hold at most 18432 bytes, leaving some headroom and rounding down to -// a nice number gives us a maximum of 16 KiB for user-supplied application data, -// which will be sent as a single record containing a single ApplicationData message. -constexpr static size_t MaximumApplicationDataChunkSize = 16 * KiB; - -namespace TLS { - -ErrorOr TLSv12::read_some(Bytes bytes) -{ - m_eof = false; - auto size_to_read = min(bytes.size(), m_context.application_buffer.size()); - if (size_to_read == 0) { - m_eof = true; - return Bytes {}; - } - - m_context.application_buffer.transfer(bytes, size_to_read); - return Bytes { bytes.data(), size_to_read }; -} - -ErrorOr TLSv12::write_some(ReadonlyBytes bytes) -{ - if (m_context.connection_status != ConnectionStatus::Established) { - dbgln_if(TLS_DEBUG, "write request while not connected"); - return AK::Error::from_string_literal("TLS write request while not connected"); - } - - for (size_t offset = 0; offset < bytes.size(); offset += MaximumApplicationDataChunkSize) { - PacketBuilder builder { ContentType::APPLICATION_DATA, m_context.options.version, bytes.size() - offset }; - builder.append(bytes.slice(offset, min(bytes.size() - offset, MaximumApplicationDataChunkSize))); - auto packet = builder.build(); - - update_packet(packet); - write_packet(packet); - } - - return bytes.size(); -} - -ErrorOr> TLSv12::connect(ByteString const& host, u16 port, Options options) -{ -#ifdef AK_OS_WINDOWS - (void)host; - (void)port; - (void)options; - return AK::Error::from_string_literal("TODO: Unable to connect via hostname on Windows"); -#else - auto promise = Core::Promise::construct(); - OwnPtr tcp_socket = TRY(Core::TCPSocket::connect(host, port)); - TRY(tcp_socket->set_blocking(false)); - auto tls_socket = make(move(tcp_socket), move(options)); - tls_socket->set_sni(host); - tls_socket->on_connected = [&] { - promise->resolve({}); - }; - tls_socket->on_tls_error = [&](auto alert) { - tls_socket->try_disambiguate_error(); - promise->reject(AK::Error::from_string_view(enum_to_string(alert))); - }; - - TRY(promise->await()); - - tls_socket->on_tls_error = nullptr; - tls_socket->on_connected = nullptr; - tls_socket->m_context.should_expect_successful_read = true; - return tls_socket; -#endif -} - -ErrorOr> TLSv12::connect(Core::SocketAddress address, ByteString const& host, Options options) -{ -#ifdef AK_OS_WINDOWS - (void)address; - (void)host; - (void)options; - return AK::Error::from_string_literal("TODO: Unable to connect via address on Windows"); -#else - auto promise = Core::Promise::construct(); - OwnPtr tcp_socket = TRY(Core::TCPSocket::connect(address)); - TRY(tcp_socket->set_blocking(false)); - auto tls_socket = make(move(tcp_socket), move(options)); - tls_socket->set_sni(host); - tls_socket->on_connected = [&] { - promise->resolve({}); - }; - tls_socket->on_tls_error = [&](auto alert) { - tls_socket->try_disambiguate_error(); - promise->reject(AK::Error::from_string_view(enum_to_string(alert))); - }; - - TRY(promise->await()); - - tls_socket->on_tls_error = nullptr; - tls_socket->on_connected = nullptr; - tls_socket->m_context.should_expect_successful_read = true; - return tls_socket; -#endif -} - -ErrorOr> TLSv12::connect(ByteString const& host, Core::Socket& underlying_stream, Options options) -{ - auto promise = Core::Promise::construct(); - TRY(underlying_stream.set_blocking(false)); - auto tls_socket = make(&underlying_stream, move(options)); - tls_socket->set_sni(host); - tls_socket->on_connected = [&] { - promise->resolve({}); - }; - tls_socket->on_tls_error = [&](auto alert) { - tls_socket->try_disambiguate_error(); - promise->reject(AK::Error::from_string_view(enum_to_string(alert))); - }; - TRY(promise->await()); - - tls_socket->on_tls_error = nullptr; - tls_socket->on_connected = nullptr; - tls_socket->m_context.should_expect_successful_read = true; - return tls_socket; -} - -void TLSv12::setup_connection() -{ - Core::deferred_invoke([this] { - auto& stream = underlying_stream(); - stream.on_ready_to_read = [this] { - auto result = read_from_socket(); - if (result.is_error()) - dbgln("Read error: {}", result.error()); - }; - - m_handshake_timeout_timer = Core::Timer::create_single_shot( - m_max_wait_time_for_handshake_in_seconds * 1000, [&] { - dbgln("Handshake timeout :("); - auto timeout_diff = Core::DateTime::now().timestamp() - m_context.handshake_initiation_timestamp; - // If the timeout duration was actually within the max wait time (with a margin of error), - // we're not operating slow, so the server timed out. - // otherwise, it's our fault that the negotiation is taking too long, so extend the timer :P - 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::USER_CANCELED); - m_context.tls_buffer.clear(); - m_context.error_code = Error::TimedOut; - m_context.critical_error = (u8)Error::TimedOut; - check_connection_state(false); // Notify the client. - } else { - // Extend the timer, we are too slow. - m_handshake_timeout_timer->restart(m_max_wait_time_for_handshake_in_seconds * 1000); - } - }); - auto packet = build_hello(); - write_packet(packet); - write_into_socket(); - m_handshake_timeout_timer->start(); - m_context.handshake_initiation_timestamp = Core::DateTime::now().timestamp(); - }); - m_has_scheduled_write_flush = true; -} - -void TLSv12::notify_client_for_app_data() -{ - if (m_context.application_buffer.size() > 0) { - if (on_ready_to_read) - on_ready_to_read(); - } else { - if (m_context.connection_finished && !m_context.has_invoked_finish_or_error_callback) { - m_context.has_invoked_finish_or_error_callback = true; - if (on_tls_finished) - on_tls_finished(); - } - } - m_has_scheduled_app_data_flush = false; -} - -ErrorOr TLSv12::read_from_socket() -{ - // If there's anything before we consume stuff, let the client know - // since we won't be consuming things if the connection is terminated. - notify_client_for_app_data(); - - ScopeGuard notify_guard { - [this] { - // If anything new shows up, tell the client about the event. - notify_client_for_app_data(); - } - }; - - if (!check_connection_state(true)) - return {}; - - u8 buffer[16 * KiB]; - Bytes bytes { buffer, array_size(buffer) }; - Bytes read_bytes {}; - auto& stream = underlying_stream(); - do { - auto result = stream.read_some(bytes); - if (result.is_error()) { - if (result.error().is_errno() && result.error().code() != EINTR) { - if (result.error().code() != EAGAIN) - dbgln("TLS Socket read failed, error: {}", result.error()); - break; - } - continue; - } - read_bytes = result.release_value(); - consume(read_bytes); - } while (!read_bytes.is_empty() && !m_context.critical_error); - - if (m_context.should_expect_successful_read && read_bytes.is_empty()) { - // read_some() returned an empty span, this is either an EOF (from improper closure) - // or some sort of weird even that is showing itself as an EOF. - // To guard against servers closing the connection weirdly or just improperly, make sure - // to check the connection state here and send the appropriate notifications. - stream.close(); - - check_connection_state(true); - } - - return {}; -} - -void TLSv12::write_into_socket() -{ - dbgln_if(TLS_DEBUG, "Flushing cached records: {} established? {}", m_context.tls_buffer.size(), is_established()); - - m_has_scheduled_write_flush = false; - if (!check_connection_state(false)) - return; - - MUST(flush()); -} - -bool TLSv12::check_connection_state(bool read) -{ - if (m_context.connection_finished) - return false; - - if (m_context.close_notify) - m_context.connection_finished = true; - - auto& stream = underlying_stream(); - - if (!stream.is_open()) { - // an abrupt closure (the server is a jerk) - dbgln_if(TLS_DEBUG, "Socket not open, assuming abrupt closure"); - m_context.connection_finished = true; - m_context.connection_status = ConnectionStatus::Disconnected; - close(); - m_context.has_invoked_finish_or_error_callback = true; - if (on_ready_to_read) - on_ready_to_read(); // Notify the client about the weird event. - if (on_tls_finished) - on_tls_finished(); - return false; - } - - if (read && stream.is_eof()) { - if (m_context.application_buffer.size() == 0 && m_context.connection_status != ConnectionStatus::Disconnected) { - m_context.has_invoked_finish_or_error_callback = true; - if (on_tls_finished) - on_tls_finished(); - } - return false; - } - - if (m_context.critical_error) { - dbgln_if(TLS_DEBUG, "CRITICAL ERROR {} :(", m_context.critical_error); - - m_context.has_invoked_finish_or_error_callback = true; - if (on_tls_error) - on_tls_error((AlertDescription)m_context.critical_error); - m_context.connection_finished = true; - m_context.connection_status = ConnectionStatus::Disconnected; - close(); - return false; - } - - if (((read && m_context.application_buffer.size() == 0) || !read) && m_context.connection_finished) { - if (m_context.application_buffer.size() == 0 && m_context.connection_status != ConnectionStatus::Disconnected) { - m_context.has_invoked_finish_or_error_callback = true; - if (on_tls_finished) - on_tls_finished(); - } - m_context.connection_status = ConnectionStatus::Disconnected; - if (m_context.tls_buffer.size()) { - dbgln_if(TLS_DEBUG, "connection closed without finishing data transfer, {} bytes still in buffer and {} bytes in application buffer", - m_context.tls_buffer.size(), - m_context.application_buffer.size()); - } - if (!m_context.application_buffer.size()) { - return false; - } - } - return true; -} - -ErrorOr TLSv12::flush() -{ - ByteBuffer out = move(m_context.tls_buffer); - auto out_bytes = out.bytes(); - - if (out_bytes.is_empty()) - return true; - - if constexpr (TLS_DEBUG) { - dbgln("SENDING..."); - print_buffer(out_bytes); - } - - auto& stream = underlying_stream(); - Optional error; - size_t written; - do { - auto result = stream.write_some(out_bytes); - if (result.is_error()) { - if (result.error().code() != EINTR && result.error().code() != EAGAIN) { - error = result.release_error(); - dbgln("TLS Socket write error: {}", *error); - break; - } - continue; - } - written = result.value(); - out_bytes = out_bytes.slice(written); - } while (!out_bytes.is_empty()); - - if (out_bytes.is_empty() && !error.has_value()) - return true; - - if (!out_bytes.is_empty()) - dbgln("Dropping {} bytes worth of TLS records on the floor", out_bytes.size()); - return false; -} - -void TLSv12::close() -{ - if (underlying_stream().is_open()) - alert(AlertLevel::FATAL, AlertDescription::CLOSE_NOTIFY); - // bye bye. - m_context.connection_status = ConnectionStatus::Disconnected; -} - -} diff --git a/Libraries/LibTLS/TLSPacketBuilder.h b/Libraries/LibTLS/TLSPacketBuilder.h deleted file mode 100644 index 07076638024..00000000000 --- a/Libraries/LibTLS/TLSPacketBuilder.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace TLS { - -class PacketBuilder { -public: - PacketBuilder(ContentType type, u16 version, size_t size_hint = 0xfdf) - : PacketBuilder(type, (ProtocolVersion)version, size_hint) - { - } - - PacketBuilder(ContentType type, ProtocolVersion version, size_t size_hint = 0xfdf) - { - // FIXME: Handle possible OOM situation. - m_packet_data = ByteBuffer::create_uninitialized(size_hint + 16).release_value_but_fixme_should_propagate_errors(); - m_current_length = 5; - m_packet_data[0] = (u8)type; - ByteReader::store(m_packet_data.offset_pointer(1), AK::convert_between_host_and_network_endian((u16)version)); - } - - inline void append(u16 value) - { - value = AK::convert_between_host_and_network_endian(value); - append((u8 const*)&value, sizeof(value)); - } - inline void append(u8 value) - { - append((u8 const*)&value, sizeof(value)); - } - inline void append(ReadonlyBytes data) - { - append(data.data(), data.size()); - } - inline void append_u24(u32 value) - { - u8 buf[3]; - buf[0] = value / 0x10000; - value %= 0x10000; - buf[1] = value / 0x100; - value %= 0x100; - buf[2] = value; - - append(buf, 3); - } - inline void append(u8 const* data, size_t bytes) - { - if (bytes == 0) - return; - - auto old_length = m_current_length; - m_current_length += bytes; - - if (m_packet_data.size() < m_current_length) { - m_packet_data.resize(m_current_length); - } - - m_packet_data.overwrite(old_length, data, bytes); - } - inline ByteBuffer build() - { - auto length = m_current_length; - m_current_length = 0; - // FIXME: Propagate errors. - return MUST(m_packet_data.slice(0, length)); - } - inline void set(size_t offset, u8 value) - { - VERIFY(offset < m_current_length); - m_packet_data[offset] = value; - } - size_t length() const { return m_current_length; } - -private: - ByteBuffer m_packet_data; - size_t m_current_length; -}; - -} diff --git a/Libraries/LibTLS/TLSv12.cpp b/Libraries/LibTLS/TLSv12.cpp index ac07bd0723f..579c87b8249 100644 --- a/Libraries/LibTLS/TLSv12.cpp +++ b/Libraries/LibTLS/TLSv12.cpp @@ -1,518 +1,184 @@ /* * Copyright (c) 2020, Ali Mohammad Pur + * Copyright (c) 2025, Altomani Gianluca * * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include +#include +#include +#include + namespace TLS { -void TLSv12::consume(ReadonlyBytes record) +ErrorOr> TLSv12::connect(ByteString const& host, u16 port, Options options) { - if (m_context.critical_error) { - dbgln("There has been a critical error ({}), refusing to continue", (i8)m_context.critical_error); - return; - } + auto tcp_socket = TRY(Core::TCPSocket::connect(host, port)); + return connect_internal(move(tcp_socket), host, options); +} - if (record.size() == 0) { - return; - } +ErrorOr> TLSv12::connect(Core::SocketAddress address, ByteString const& host, Options options) +{ + auto tcp_socket = TRY(Core::TCPSocket::connect(address)); + return connect_internal(move(tcp_socket), host, options); +} - dbgln_if(TLS_DEBUG, "Consuming {} bytes", record.size()); +void TLSv12::wait_for_activity(bool read) +{ + auto sock = SSL_get_fd(m_ssl); - if (m_context.message_buffer.try_append(record).is_error()) { - dbgln("Not enough space in message buffer, dropping the record"); - return; - } + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); - size_t index { 0 }; - size_t buffer_length = m_context.message_buffer.size(); + if (read) + select(sock + 1, &fds, nullptr, nullptr, nullptr); + else + select(sock + 1, nullptr, &fds, nullptr, nullptr); +} - size_t size_offset { 3 }; // read the common record header - size_t header_size { 5 }; - - dbgln_if(TLS_DEBUG, "message buffer length {}", buffer_length); - - while (buffer_length >= 5) { - auto length = AK::convert_between_host_and_network_endian(ByteReader::load16(m_context.message_buffer.offset_pointer(index + size_offset))) + header_size; - if (length > buffer_length) { - dbgln_if(TLS_DEBUG, "Need more data: {} > {}", length, buffer_length); - break; - } - auto consumed = handle_message(m_context.message_buffer.bytes().slice(index, length)); - - if constexpr (TLS_DEBUG) { - if (consumed > 0) - dbgln("consumed {} bytes", consumed); - else - dbgln("error: {}", consumed); - } - - if (consumed != (i8)Error::NeedMoreData) { - if (consumed < 0) { - dbgln("Consumed an error: {}", consumed); - if (!m_context.critical_error) - m_context.critical_error = (i8)consumed; - m_context.error_code = (Error)consumed; - break; +ErrorOr TLSv12::read_some(Bytes bytes) +{ + while (true) { + auto ret = SSL_read(m_ssl, bytes.data(), bytes.size()); + if (ret <= 0) { + auto err = SSL_get_error(m_ssl, ret); + switch (err) { + case SSL_ERROR_ZERO_RETURN: + return Bytes { bytes.data(), 0 }; + case SSL_ERROR_WANT_READ: + wait_for_activity(true); + continue; + case SSL_ERROR_WANT_WRITE: + wait_for_activity(false); + continue; + default: + return AK::Error::from_string_literal("Failed reading from SSL connection"); } - } else { - continue; } - index += length; - buffer_length -= length; - if (m_context.critical_error) { - dbgln("Broken connection"); - m_context.error_code = Error::BrokenConnection; - break; - } - } - if (m_context.error_code != Error::NoError && m_context.error_code != Error::NeedMoreData) { - dbgln("consume error: {}", (i8)m_context.error_code); - m_context.message_buffer.clear(); - return; - } - - if (index) { - // FIXME: Propagate errors. - m_context.message_buffer = MUST(m_context.message_buffer.slice(index, m_context.message_buffer.size() - index)); + return Bytes { bytes.data(), static_cast(ret) }; } } -void TLSv12::try_disambiguate_error() const +ErrorOr TLSv12::write_some(ReadonlyBytes bytes) { - dbgln("Possible failure cause(s): "); - switch ((AlertDescription)m_context.critical_error) { - 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::INSUFFICIENT_SECURITY: - dbgln("- No cipher suite in common with {} (the server is oh so secure)", m_context.extensions.SNI); - break; - case AlertDescription::PROTOCOL_VERSION: - dbgln("- The server refused to negotiate with TLS 1.2 :("); - break; - case AlertDescription::UNEXPECTED_MESSAGE: - dbgln("- We sent an invalid message for the state we're in."); - break; - 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::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::DECOMPRESSION_FAILURE_RESERVED: - dbgln("- We sent invalid input for decompression (e.g. data that would expand to excessive length)"); - break; - 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::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::DECRYPT_ERROR: - dbgln("- A handshake crypto operation failed. This includes signature verification and validating Finished."); - break; - case AlertDescription::ACCESS_DENIED: - dbgln("- The certificate is valid, but once access control was applied, the sender decided to stop negotiation."); - break; - case AlertDescription::INTERNAL_ERROR: - dbgln("- No one knows, but it isn't a protocol failure."); - break; - 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: - dbgln("- No one knows."); - break; - } - - dbgln("- {}", enum_to_value((AlertDescription)m_context.critical_error)); -} - -void TLSv12::set_root_certificates(Vector certificates) -{ - if (!m_context.root_certificates.is_empty()) { - dbgln("TLS warn: resetting root certificates!"); - m_context.root_certificates.clear(); - } - - for (auto& cert : certificates) { - if (!cert.is_valid()) { - dbgln("Certificate for {} is invalid, things may or may not work!", cert.subject.to_string()); - } - // FIXME: Figure out what we should do when our root certs are invalid. - - m_context.root_certificates.set(MUST(cert.subject.to_string()).to_byte_string(), cert); - } - dbgln_if(TLS_DEBUG, "{}: Set {} root certificates", this, m_context.root_certificates.size()); -} - -static bool wildcard_matches(StringView host, StringView subject) -{ - if (host == subject) - return true; - - if (subject.starts_with("*."sv)) { - auto maybe_first_dot_index = host.find('.'); - if (maybe_first_dot_index.has_value()) { - auto first_dot_index = maybe_first_dot_index.release_value(); - return wildcard_matches(host.substring_view(first_dot_index + 1), subject.substring_view(2)); - } - } - - return false; -} - -static bool certificate_subject_matches_host(Certificate const& cert, StringView host) -{ - if (wildcard_matches(host, cert.subject.common_name())) - return true; - - for (auto& san : cert.SAN) { - if (wildcard_matches(host, san)) - return true; - } - - return false; -} - -bool Context::verify_chain(StringView host) const -{ - if (!options.validate_certificates) - return true; - - Vector const* local_chain = nullptr; - if (is_server) { - dbgln("Unsupported: Server mode"); - TODO(); - } else { - local_chain = &certificates; - } - - if (local_chain->is_empty()) { - dbgln("verify_chain: Attempting to verify an empty chain"); - return false; - } - - // RFC5246 section 7.4.2: The sender's certificate MUST come first in the list. Each following certificate - // MUST directly certify the one preceding it. Because certificate validation requires that root keys be - // distributed independently, the self-signed certificate that specifies the root certificate authority MAY be - // omitted from the chain, under the assumption that the remote end must already possess it in order to validate - // it in any case. - - if (!host.is_empty()) { - auto const& first_certificate = local_chain->first(); - auto subject_matches = certificate_subject_matches_host(first_certificate, host); - if (!subject_matches) { - dbgln("verify_chain: First certificate does not match the hostname"); - return false; - } - } else { - // FIXME: The host is taken from m_context.extensions.SNI, when is this empty? - dbgln("FIXME: verify_chain called without host"); - return false; - } - - for (size_t cert_index = 0; cert_index < local_chain->size(); ++cert_index) { - auto const& cert = local_chain->at(cert_index); - - auto subject_string = MUST(cert.subject.to_string()); - auto issuer_string = MUST(cert.issuer.to_string()); - - if (!cert.is_valid()) { - dbgln("verify_chain: Certificate is not valid {}", subject_string); - return false; - } - - auto maybe_root_certificate = root_certificates.get(issuer_string.to_byte_string()); - if (maybe_root_certificate.has_value()) { - auto& root_certificate = *maybe_root_certificate; - auto verification_correct = verify_certificate_pair(cert, root_certificate); - - if (!verification_correct) { - dbgln("verify_chain: Signature inconsistent, {} was not signed by {} (root certificate)", subject_string, issuer_string); - return false; + while (true) { + auto ret = SSL_write(m_ssl, bytes.data(), bytes.size()); + if (ret <= 0) { + auto err = SSL_get_error(m_ssl, ret); + switch (err) { + case SSL_ERROR_WANT_READ: + wait_for_activity(true); + continue; + case SSL_ERROR_WANT_WRITE: + wait_for_activity(false); + continue; + default: + return AK::Error::from_string_literal("Failed writing to SSL connection"); } - - // Root certificate reached, and correctly verified, so we can stop now - return true; } - if (subject_string == issuer_string) { - dbgln("verify_chain: Non-root self-signed certificate"); - return options.allow_self_signed_certificates; - } - if ((cert_index + 1) >= local_chain->size()) { - dbgln("verify_chain: No trusted root certificate found before end of certificate chain"); - dbgln("verify_chain: Last certificate in chain was signed by {}", issuer_string); - return false; - } - - auto const& parent_certificate = local_chain->at(cert_index + 1); - if (issuer_string != MUST(parent_certificate.subject.to_string())) { - dbgln("verify_chain: Next certificate in the chain is not the issuer of this certificate"); - return false; - } - - if (!(parent_certificate.is_allowed_to_sign_certificate && parent_certificate.is_certificate_authority)) { - dbgln("verify_chain: {} is not marked as certificate authority", issuer_string); - return false; - } - if (parent_certificate.path_length_constraint.has_value() && cert_index > parent_certificate.path_length_constraint.value()) { - dbgln("verify_chain: Path length for certificate exceeded"); - return false; - } - - bool verification_correct = verify_certificate_pair(cert, parent_certificate); - if (!verification_correct) { - dbgln("verify_chain: Signature inconsistent, {} was not signed by {}", subject_string, issuer_string); - return false; - } - } - - // Either a root certificate is reached, or parent validation fails as the end of the local chain is reached - VERIFY_NOT_REACHED(); -} - -bool Context::verify_certificate_pair(Certificate const& subject, Certificate const& issuer) const -{ - Crypto::Hash::HashKind kind = Crypto::Hash::HashKind::Unknown; - auto identifier = subject.signature_algorithm.identifier; - - bool is_rsa = true; - - if (identifier == Crypto::ASN1::rsa_encryption_oid) { - kind = Crypto::Hash::HashKind::None; - } else if (identifier == Crypto::ASN1::rsa_md5_encryption_oid) { - kind = Crypto::Hash::HashKind::MD5; - } else if (identifier == Crypto::ASN1::rsa_sha1_encryption_oid) { - kind = Crypto::Hash::HashKind::SHA1; - } else if (identifier == Crypto::ASN1::rsa_sha256_encryption_oid) { - kind = Crypto::Hash::HashKind::SHA256; - } else if (identifier == Crypto::ASN1::rsa_sha384_encryption_oid) { - kind = Crypto::Hash::HashKind::SHA384; - } else if (identifier == Crypto::ASN1::rsa_sha512_encryption_oid) { - kind = Crypto::Hash::HashKind::SHA512; - } else if (identifier == Crypto::ASN1::ecdsa_with_sha256_encryption_oid) { - kind = Crypto::Hash::HashKind::SHA256; - is_rsa = false; - } else if (identifier == Crypto::ASN1::ecdsa_with_sha384_encryption_oid) { - kind = Crypto::Hash::HashKind::SHA384; - is_rsa = false; - } else if (identifier == Crypto::ASN1::ecdsa_with_sha512_encryption_oid) { - kind = Crypto::Hash::HashKind::SHA512; - is_rsa = false; - } - - if (kind == Crypto::Hash::HashKind::Unknown) { - dbgln("verify_certificate_pair: Unknown signature algorithm, expected RSA or ECDSA with SHA1/256/384/512, got OID {}", identifier); - return false; - } - - if (is_rsa) { - auto rsa = Crypto::PK::RSA_PKCS1_EMSA(kind, issuer.public_key.rsa); - return MUST(rsa.verify(subject.tbs_asn1, subject.signature_value)); - } - - // ECDSA hash verification: hash, then check signature against the specific curve - auto ec_curve = oid_to_curve(issuer.public_key.algorithm.ec_parameters.value_or({})); - if (ec_curve.is_error()) { - dbgln("verify_certificate_pair: Unknown curve for ECDSA signature verification"); - return false; - } - - auto public_point = issuer.public_key.ec.to_secpxxxr1_point(); - - auto maybe_signature = Crypto::Curves::SECPxxxr1Signature::from_asn(*issuer.public_key.algorithm.ec_parameters, subject.signature_value, {}); - if (maybe_signature.is_error()) { - dbgln("verify_certificate_pair: Signature is not ASN.1 DER encoded"); - return false; - } - - auto signature = maybe_signature.release_value(); - - switch (ec_curve.release_value()) { - case SupportedGroup::SECP256R1: { - Crypto::Hash::Manager hasher(kind); - hasher.update(subject.tbs_asn1.bytes()); - auto hash = hasher.digest(); - - Crypto::Curves::SECP256r1 curve; - auto result = curve.verify_point(hash.bytes(), public_point, signature); - if (result.is_error()) { - dbgln("verify_certificate_pair: Failed to check SECP256r1 signature {}", result.release_error()); - return false; - } - return result.value(); - } - case SupportedGroup::SECP384R1: { - Crypto::Hash::Manager hasher(kind); - hasher.update(subject.tbs_asn1.bytes()); - auto hash = hasher.digest(); - - Crypto::Curves::SECP384r1 curve; - auto result = curve.verify_point(hash.bytes(), public_point, signature); - if (result.is_error()) { - dbgln("verify_certificate_pair: Failed to check SECP384r1 signature {}", result.release_error()); - return false; - } - return result.value(); - } - case SupportedGroup::X25519: { - Crypto::Curves::Ed25519 curve; - auto result = curve.verify(issuer.public_key.raw_key, subject.signature_value, subject.tbs_asn1.bytes()); - if (!result) { - dbgln("verify_certificate_pair: Failed to check Ed25519 signature"); - return false; - } - return result; - } - default: - dbgln("verify_certificate_pair: Don't know how to verify signature for curve {}", to_underlying(ec_curve.release_value())); - return false; + return ret; } } -template -static void hmac_pseudorandom_function(Bytes output, ReadonlyBytes secret, u8 const* label, size_t label_length, ReadonlyBytes seed, ReadonlyBytes seed_b) +bool TLSv12::is_eof() const { - if (!secret.size()) { - dbgln("null secret"); - return; - } + return BIO_eof(m_bio) == 1; +} - auto append_label_seed = [&](auto& hmac) { - hmac.update(label, label_length); - hmac.update(seed); - if (seed_b.size() > 0) - hmac.update(seed_b); +bool TLSv12::is_open() const +{ + return !BIO_get_close(m_bio); +} + +void TLSv12::close() +{ + SSL_shutdown(m_ssl); +} + +ErrorOr TLSv12::pending_bytes() const +{ + return SSL_pending(m_ssl); +} + +ErrorOr TLSv12::can_read_without_blocking(int count) const +{ + return SSL_pending(m_ssl) >= count; +} + +ErrorOr TLSv12::set_blocking(bool block) +{ + return m_socket->set_blocking(block); +} + +ErrorOr TLSv12::set_close_on_exec(bool enabled) +{ + return m_socket->set_close_on_exec(enabled); +} + +TLSv12::TLSv12(NonnullOwnPtr socket, SSL_CTX* ssl_ctx, SSL* ssl, BIO* bio) + : m_ssl_ctx(ssl_ctx) + , m_ssl(ssl) + , m_bio(bio) + , m_socket(move(socket)) +{ + m_socket->on_ready_to_read = [this] { + if (on_ready_to_read) + on_ready_to_read(); }; - - HMACType hmac(secret); - append_label_seed(hmac); - - auto digest_size = hmac.digest_size(); - auto digest_0 = MUST(ByteBuffer::create_uninitialized(digest_size)); - - digest_0.overwrite(0, hmac.digest().immutable_data(), digest_size); - - size_t index = 0; - while (index < output.size()) { - hmac.update(digest_0.bytes()); - append_label_seed(hmac); - auto digest_1 = hmac.digest(); - - auto copy_size = min(digest_size, output.size() - index); - - output.overwrite(index, digest_1.immutable_data(), copy_size); - index += copy_size; - - digest_0.overwrite(0, hmac.process(digest_0.bytes()).immutable_data(), digest_size); - } } -void TLSv12::pseudorandom_function(Bytes output, ReadonlyBytes secret, u8 const* label, size_t label_length, ReadonlyBytes seed, ReadonlyBytes seed_b) +TLSv12::~TLSv12() { - // 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>(output, secret, label, label_length, seed, seed_b); - break; - case Crypto::Hash::HashKind::SHA384: - hmac_pseudorandom_function>(output, secret, label, label_length, seed, seed_b); - break; - case Crypto::Hash::HashKind::SHA256: - hmac_pseudorandom_function>(output, secret, label, label_length, seed, seed_b); - break; - default: - dbgln("Failed to find a suitable HMAC hash"); - VERIFY_NOT_REACHED(); - break; - } + SSL_free(m_ssl); + SSL_CTX_free(m_ssl_ctx); } -TLSv12::TLSv12(StreamVariantType stream, Options options) - : m_stream(move(stream)) +ErrorOr> TLSv12::connect_internal(NonnullOwnPtr socket, ByteString const& host, Options options) { - m_context.options = move(options); - m_context.is_server = false; - m_context.tls_buffer = {}; + auto* ssl_ctx = OPENSSL_TRY_PTR(SSL_CTX_new(TLS_client_method())); + ArmedScopeGuard free_ssl_ctx = [&] { SSL_CTX_free(ssl_ctx); }; - set_root_certificates(m_context.options.root_certificates.has_value() - ? *m_context.options.root_certificates - : DefaultRootCACertificates::the().certificates()); + // Configure the client to abort the handshake if certificate verification fails. + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, nullptr); - setup_connection(); -} - -Vector TLSv12::parse_pem_certificate(ReadonlyBytes certificate_pem_buffer, ReadonlyBytes rsa_key) // FIXME: This should not be bound to RSA -{ - if (certificate_pem_buffer.is_empty() || rsa_key.is_empty()) { - return {}; + if (options.root_certificates_path.has_value()) { + auto path = options.root_certificates_path.value(); + SSL_CTX_load_verify_file(ssl_ctx, path.characters()); + } else { + // Use the default trusted certificate store + OPENSSL_TRY(SSL_CTX_set_default_verify_paths(ssl_ctx)); } - auto decoded_certificate = Crypto::decode_pem(certificate_pem_buffer); - if (decoded_certificate.type != Crypto::PEMType::Certificate) { - dbgln("Certificate not PEM"); - return {}; - } + // Require a minimum TLS version of TLSv1.2. + OPENSSL_TRY(SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_2_VERSION)); - auto maybe_certificate = Certificate::parse_certificate(decoded_certificate.data); - if (!maybe_certificate.is_error()) { - dbgln("Invalid certificate"); - return {}; - } + auto* ssl = OPENSSL_TRY_PTR(SSL_new(ssl_ctx)); + ArmedScopeGuard free_ssl = [&] { SSL_free(ssl); }; - Crypto::PK::RSA rsa(rsa_key); - auto certificate = maybe_certificate.release_value(); - certificate.private_key = rsa.private_key(); + // Tell the server which hostname we are attempting to connect to in case the server supports multiple hosts. + OPENSSL_TRY(SSL_set_tlsext_host_name(ssl, host.characters())); - return { move(certificate) }; -} + // Ensure we check that the server has supplied a certificate for the hostname that we were expecting. + OPENSSL_TRY(SSL_set1_host(ssl, host.characters())); -ErrorOr oid_to_curve(Vector curve) -{ - if (curve == Crypto::ASN1::secp384r1_oid) - return SupportedGroup::SECP384R1; - if (curve == Crypto::ASN1::secp256r1_oid) - return SupportedGroup::SECP256R1; + auto* bio = OPENSSL_TRY_PTR(BIO_new_socket(socket->fd(), 0)); - return AK::Error::from_string_literal("Unknown curve oid"); + // SSL takes ownership of the BIO and will handle freeing it + SSL_set_bio(ssl, bio, bio); + + OPENSSL_TRY(SSL_connect(ssl)); + + free_ssl.disarm(); + free_ssl_ctx.disarm(); + + return adopt_own(*new TLSv12(move(socket), ssl_ctx, ssl, bio)); } } diff --git a/Libraries/LibTLS/TLSv12.h b/Libraries/LibTLS/TLSv12.h index 7c456fd9883..901d1808aae 100644 --- a/Libraries/LibTLS/TLSv12.h +++ b/Libraries/LibTLS/TLSv12.h @@ -1,158 +1,19 @@ /* * Copyright (c) 2020, Ali Mohammad Pur + * Copyright (c) 2025, Altomani Gianluca * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once -#include -#include -#include -#include #include -#include -#include #include -#include -#include -#include -#include -#include +#include namespace TLS { -using Crypto::Certificate::Certificate; - -inline void print_buffer(ReadonlyBytes buffer) -{ - dbgln("{:hex-dump}", buffer); -} - -inline void print_buffer(ByteBuffer const& buffer) -{ - print_buffer(buffer.bytes()); -} - -inline void print_buffer(u8 const* buffer, size_t size) -{ - print_buffer(ReadonlyBytes { buffer, size }); -} - -class Socket; - -enum class Error : i8 { - NoError = 0, - UnknownError = -1, - BrokenPacket = -2, - NotUnderstood = -3, - NoCommonCipher = -5, - UnexpectedMessage = -6, - CloseConnection = -7, - CompressionNotSupported = -8, - NotVerified = -9, - NotSafe = -10, - IntegrityCheckFailed = -11, - ErrorAlert = -12, - BrokenConnection = -13, - BadCertificate = -14, - UnsupportedCertificate = -15, - NoRenegotiation = -16, - FeatureNotSupported = -17, - DecryptionFailed = -20, - NeedMoreData = -21, - TimedOut = -22, - OutOfMemory = -23, -}; - -enum class WritePacketStage { - Initial = 0, - ClientHandshake = 1, - ServerHandshake = 2, - Finished = 3, -}; - -enum class ConnectionStatus { - Disconnected, - Negotiating, - KeyExchange, - Renegotiating, - Established, -}; - -enum ClientVerificationStaus { - Verified, - VerificationNeeded, -}; - -// Note for the 16 iv length instead of 8: -// 4 bytes of fixed IV, 8 random (nonce) bytes, 4 bytes for counter -// GCM specifically asks us to transmit only the nonce, the counter is zero -// and the fixed IV is derived from the premaster key. -// -// The cipher suite list below is ordered based on the recommendations from Mozilla. -// When changing the supported cipher suites, please consult the webpage below for -// the preferred order. -// -// https://wiki.mozilla.org/Security/Server_Side_TLS -#define ENUMERATE_CIPHERS(C) \ - C(true, CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, KeyExchangeAlgorithm::ECDHE_ECDSA, CipherAlgorithm::AES_128_GCM, Crypto::Hash::SHA256, 8, true) \ - C(true, CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, KeyExchangeAlgorithm::ECDHE_RSA, CipherAlgorithm::AES_128_GCM, Crypto::Hash::SHA256, 8, true) \ - C(true, CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, KeyExchangeAlgorithm::ECDHE_ECDSA, CipherAlgorithm::AES_256_GCM, Crypto::Hash::SHA384, 8, true) \ - C(true, CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, KeyExchangeAlgorithm::ECDHE_RSA, CipherAlgorithm::AES_256_GCM, Crypto::Hash::SHA384, 8, true) \ - C(true, CipherSuite::TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, KeyExchangeAlgorithm::DHE_RSA, CipherAlgorithm::AES_128_GCM, Crypto::Hash::SHA256, 8, true) \ - C(true, CipherSuite::TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, KeyExchangeAlgorithm::DHE_RSA, CipherAlgorithm::AES_256_GCM, Crypto::Hash::SHA384, 8, true) \ - C(true, CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, KeyExchangeAlgorithm::ECDHE_ECDSA, CipherAlgorithm::AES_128_CBC, Crypto::Hash::SHA1, 16, false) \ - C(true, CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, KeyExchangeAlgorithm::ECDHE_RSA, CipherAlgorithm::AES_128_CBC, Crypto::Hash::SHA1, 16, false) \ - C(true, CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, KeyExchangeAlgorithm::ECDHE_ECDSA, CipherAlgorithm::AES_256_CBC, Crypto::Hash::SHA1, 16, false) \ - C(true, CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, KeyExchangeAlgorithm::ECDHE_RSA, CipherAlgorithm::AES_256_CBC, Crypto::Hash::SHA1, 16, false) \ - C(true, CipherSuite::TLS_RSA_WITH_AES_128_GCM_SHA256, KeyExchangeAlgorithm::RSA, CipherAlgorithm::AES_128_GCM, Crypto::Hash::SHA256, 8, true) \ - C(true, CipherSuite::TLS_RSA_WITH_AES_256_GCM_SHA384, KeyExchangeAlgorithm::RSA, CipherAlgorithm::AES_256_GCM, Crypto::Hash::SHA384, 8, true) \ - 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) - -constexpr KeyExchangeAlgorithm get_key_exchange_algorithm(CipherSuite suite) -{ - switch (suite) { -#define C(is_supported, suite, key_exchange, cipher, hash, iv_size, is_aead) \ - case suite: \ - return key_exchange; - ENUMERATE_CIPHERS(C) -#undef C - default: - return KeyExchangeAlgorithm::Invalid; - } -} - -constexpr CipherAlgorithm get_cipher_algorithm(CipherSuite suite) -{ - switch (suite) { -#define C(is_supported, suite, key_exchange, cipher, hash, iv_size, is_aead) \ - case suite: \ - return cipher; - ENUMERATE_CIPHERS(C) -#undef C - default: - return CipherAlgorithm::Invalid; - } -} - -ErrorOr oid_to_curve(Vector curve); - struct Options { - static Vector default_usable_cipher_suites() - { - Vector cipher_suites; -#define C(is_supported, suite, key_exchange, cipher, hash, iv_size, is_aead) \ - if constexpr (is_supported) \ - cipher_suites.empend(suite); - ENUMERATE_CIPHERS(C) -#undef C - return cipher_suites; - } - Vector usable_cipher_suites = default_usable_cipher_suites(); #define OPTION_WITH_DEFAULTS(typ, name, ...) \ static typ default_##name() \ @@ -171,384 +32,50 @@ struct Options { return move(*this); \ } - OPTION_WITH_DEFAULTS(ProtocolVersion, version, ProtocolVersion::VERSION_1_2) - OPTION_WITH_DEFAULTS(Vector, supported_signature_algorithms, - { HashAlgorithm::SHA512, SignatureAlgorithm::RSA }, - { HashAlgorithm::SHA384, SignatureAlgorithm::RSA }, - { HashAlgorithm::SHA256, SignatureAlgorithm::RSA }, - { HashAlgorithm::SHA1, SignatureAlgorithm::RSA }, - { HashAlgorithm::SHA256, SignatureAlgorithm::ECDSA }, - { HashAlgorithm::SHA384, SignatureAlgorithm::ECDSA }, - { HashAlgorithm::INTRINSIC, SignatureAlgorithm::ED25519 }); - OPTION_WITH_DEFAULTS(Vector, elliptic_curves, - SupportedGroup::X25519, - SupportedGroup::SECP256R1, - SupportedGroup::SECP384R1, - SupportedGroup::X448) - OPTION_WITH_DEFAULTS(Vector, supported_ec_point_formats, ECPointFormat::UNCOMPRESSED) - - OPTION_WITH_DEFAULTS(bool, use_sni, true) - OPTION_WITH_DEFAULTS(bool, use_compression, false) - OPTION_WITH_DEFAULTS(bool, validate_certificates, true) - OPTION_WITH_DEFAULTS(bool, allow_self_signed_certificates, false) - OPTION_WITH_DEFAULTS(Optional>, root_certificates, ) - OPTION_WITH_DEFAULTS(Function, alert_handler, [](auto) { }) - OPTION_WITH_DEFAULTS(Function, finish_callback, [] { }) - OPTION_WITH_DEFAULTS(Function()>, certificate_provider, [] { return Vector {}; }) - OPTION_WITH_DEFAULTS(bool, enable_extended_master_secret, true) - -#undef OPTION_WITH_DEFAULTS -}; - -class SegmentedBuffer { -public: - [[nodiscard]] size_t size() const { return m_size; } - [[nodiscard]] bool is_empty() const { return m_size == 0; } - void transfer(Bytes dest, size_t size) - { - VERIFY(size <= dest.size()); - size_t transferred = 0; - while (transferred < size) { - auto& buffer = m_buffers.head(); - size_t to_transfer = min(buffer.size() - m_offset_into_current_buffer, size - transferred); - memcpy(dest.offset(transferred), buffer.data() + m_offset_into_current_buffer, to_transfer); - transferred += to_transfer; - m_offset_into_current_buffer += to_transfer; - if (m_offset_into_current_buffer >= buffer.size()) { - m_buffers.dequeue(); - m_offset_into_current_buffer = 0; - } - m_size -= to_transfer; - } - } - - AK::ErrorOr try_append(ReadonlyBytes data) - { - if (Checked::addition_would_overflow(m_size, data.size())) - return AK::Error::from_errno(EOVERFLOW); - - m_size += data.size(); - m_buffers.enqueue(TRY(ByteBuffer::copy(data))); - return {}; - } - -private: - size_t m_size { 0 }; - Queue m_buffers; - size_t m_offset_into_current_buffer { 0 }; -}; - -struct Context { - bool verify_chain(StringView host) const; - bool verify_certificate_pair(Certificate const& subject, Certificate const& issuer) const; - - Options options; - - u8 remote_random[32]; - u8 local_random[32]; - u8 session_id[32]; - u8 session_id_size { 0 }; - CipherSuite cipher; - bool is_server { false }; - Vector certificates; - Certificate private_key; - Vector client_certificates; - ByteBuffer master_key; - ByteBuffer premaster_key; - u8 cipher_spec_set { 0 }; - struct { - int created { 0 }; - u8 remote_mac[32]; - u8 local_mac[32]; - u8 local_iv[16]; - u8 remote_iv[16]; - u8 local_aead_iv[4]; - u8 remote_aead_iv[4]; - } crypto; - - Crypto::Hash::Manager handshake_hash; - - ByteBuffer message_buffer; - u64 remote_sequence_number { 0 }; - u64 local_sequence_number { 0 }; - - ConnectionStatus connection_status { ConnectionStatus::Disconnected }; - bool should_expect_successful_read { false }; - u8 critical_error { 0 }; - Error error_code { Error::NoError }; - - ByteBuffer tls_buffer; - - SegmentedBuffer application_buffer; - - bool is_child { false }; - - struct { - // Server Name Indicator - ByteString SNI; // I hate your existence - bool extended_master_secret { false }; - } extensions; - - u8 request_client_certificate { 0 }; - - ByteBuffer cached_handshake; - - ClientVerificationStaus client_verified { Verified }; - - bool connection_finished { false }; - bool close_notify { false }; - bool has_invoked_finish_or_error_callback { false }; - - // message flags - u8 handshake_messages[11] { 0 }; - ByteBuffer user_data; - HashMap root_certificates; - - Vector alpn; - StringView negotiated_alpn; - - size_t send_retries { 0 }; - - time_t handshake_initiation_timestamp { 0 }; - - struct { - ByteBuffer p; - ByteBuffer g; - ByteBuffer Ys; - } server_diffie_hellman_params; - - OwnPtr server_key_exchange_curve; + OPTION_WITH_DEFAULTS(Optional, root_certificates_path, ) }; class TLSv12 final : public Core::Socket { -private: - Core::Socket& underlying_stream() - { - return *m_stream.visit([&](auto& stream) -> Core::Socket* { return stream; }); - } - Core::Socket const& underlying_stream() const - { - return *m_stream.visit([&](auto& stream) -> Core::Socket const* { return stream; }); - } - public: /// Reads into a buffer, with the maximum size being the size of the buffer. /// The amount of bytes read can be smaller than the size of the buffer. - /// Returns either the bytes that were read, or an errno in the case of + /// Returns either the bytes that were read, or an error in the case of /// failure. virtual ErrorOr read_some(Bytes) override; /// Tries to write the entire contents of the buffer. It is possible for /// less than the full buffer to be written. Returns either the amount of - /// bytes written into the stream, or an errno in the case of failure. + /// bytes written into the stream, or an error in the case of failure. virtual ErrorOr write_some(ReadonlyBytes) override; - virtual bool is_eof() const override { return m_context.application_buffer.is_empty() && (m_context.connection_finished || underlying_stream().is_eof()); } + virtual bool is_eof() const override; + virtual bool is_open() const override; - virtual bool is_open() const override { return is_established(); } virtual void close() override; - virtual ErrorOr pending_bytes() const override { return m_context.application_buffer.size(); } - virtual ErrorOr can_read_without_blocking(int = 0) const override { return !m_context.application_buffer.is_empty(); } - virtual ErrorOr set_blocking(bool block) override - { - VERIFY(!block); - return {}; - } - virtual ErrorOr set_close_on_exec(bool enabled) override { return underlying_stream().set_close_on_exec(enabled); } - - virtual void set_notifications_enabled(bool enabled) override { underlying_stream().set_notifications_enabled(enabled); } + virtual ErrorOr pending_bytes() const override; + virtual ErrorOr can_read_without_blocking(int = 0) const override; + virtual ErrorOr set_blocking(bool block) override; + virtual ErrorOr set_close_on_exec(bool enabled) override; static ErrorOr> connect(Core::SocketAddress, ByteString const& host, Options = {}); static ErrorOr> connect(ByteString const& host, u16 port, Options = {}); - static ErrorOr> connect(ByteString const& host, Core::Socket& underlying_stream, Options = {}); - using StreamVariantType = Variant, Core::Socket*>; - explicit TLSv12(StreamVariantType, Options); - - bool is_established() const { return m_context.connection_status == ConnectionStatus::Established; } - - void set_sni(StringView sni) - { - if (m_context.is_server || m_context.critical_error || m_context.connection_status != ConnectionStatus::Disconnected) { - dbgln("invalid state for set_sni"); - return; - } - m_context.extensions.SNI = sni; - } - - void set_root_certificates(Vector); - - static Vector parse_pem_certificate(ReadonlyBytes certificate_pem_buffer, ReadonlyBytes key_pem_buffer); - - StringView alpn() const { return m_context.negotiated_alpn; } - - bool supports_cipher(CipherSuite suite) const - { - switch (suite) { -#define C(is_supported, suite, key_exchange, cipher, hash, iv_size, is_aead) \ - case suite: \ - return is_supported; - ENUMERATE_CIPHERS(C) -#undef C - default: - return false; - } - } - - bool supports_version(ProtocolVersion v) const - { - return v == ProtocolVersion::VERSION_1_2; - } - - void alert(AlertLevel, AlertDescription); - - Function on_tls_error; - Function on_tls_finished; - Function on_tls_certificate_request; - Function on_connected; + ~TLSv12() override; private: - void setup_connection(); + explicit TLSv12(NonnullOwnPtr, SSL_CTX*, SSL*, BIO*); - void consume(ReadonlyBytes record); + static ErrorOr> connect_internal(NonnullOwnPtr, ByteString const&, Options); - ByteBuffer hmac_message(ReadonlyBytes buf, Optional const buf2, size_t mac_length, bool local = false); - void ensure_hmac(size_t digest_size, bool local); + void wait_for_activity(bool); - void update_packet(ByteBuffer& packet); - void update_hash(ReadonlyBytes in, size_t header_size); + SSL_CTX* m_ssl_ctx { nullptr }; + SSL* m_ssl { nullptr }; + BIO* m_bio { nullptr }; - void write_packet(ByteBuffer& packet, bool immediately = false); - - ByteBuffer build_client_key_exchange(); - ByteBuffer build_server_key_exchange(); - - ByteBuffer build_hello(); - ByteBuffer build_handshake_finished(); - ByteBuffer build_certificate(); - ByteBuffer build_alert(bool critical, u8 code); - ByteBuffer build_change_cipher_spec(); - void build_rsa_pre_master_secret(PacketBuilder&); - void build_dhe_rsa_pre_master_secret(PacketBuilder&); - void build_ecdhe_rsa_pre_master_secret(PacketBuilder&); - - ErrorOr flush(); - void write_into_socket(); - ErrorOr read_from_socket(); - - bool check_connection_state(bool read); - void notify_client_for_app_data(); - - ssize_t handle_server_hello(ReadonlyBytes, WritePacketStage&); - ssize_t handle_handshake_finished(ReadonlyBytes, WritePacketStage&); - 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); - ssize_t handle_message(ReadonlyBytes); - - 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 - { - switch (m_context.cipher) { -#define C(is_supported, suite, key_exchange, cipher, hash, iv_size, is_aead) \ - case suite: \ - return cipher_key_size(cipher) / 8; - ENUMERATE_CIPHERS(C) -#undef C - default: - return 128 / 8; - } - } - - size_t mac_length() const - { - switch (m_context.cipher) { -#define C(is_supported, suite, key_exchange, cipher, hash, iv_size, is_aead) \ - case suite: \ - return hash ::digest_size(); - ENUMERATE_CIPHERS(C) -#undef C - default: - return Crypto::Hash::SHA256::digest_size(); - } - } - - 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) { -#define C(is_supported, suite, key_exchange, cipher, hash, iv_size, is_aead) \ - case suite: \ - return iv_size; - ENUMERATE_CIPHERS(C) -#undef C - default: - return 16; - } - } - - bool is_aead() const - { - switch (m_context.cipher) { -#define C(is_supported, suite, key_exchange, cipher, hash, iv_size, is_aead) \ - case suite: \ - return is_aead; - ENUMERATE_CIPHERS(C) -#undef C - default: - return false; - } - } - - bool expand_key(); - - bool compute_master_secret_from_pre_master_secret(size_t length); - - void try_disambiguate_error() const; - - bool m_eof { false }; - StreamVariantType m_stream; - Context m_context; - - OwnPtr> m_hmac_local; - OwnPtr> m_hmac_remote; - - using CipherVariant = Variant< - Empty, - Crypto::Cipher::AESCipher::CBCMode, - Crypto::Cipher::AESCipher::GCMMode>; - CipherVariant m_cipher_local {}; - CipherVariant m_cipher_remote {}; - - bool m_has_scheduled_write_flush { false }; - bool m_has_scheduled_app_data_flush { false }; - i32 m_max_wait_time_for_handshake_in_seconds { 10 }; - - RefPtr m_handshake_timeout_timer; + // Keep this around or the socket will be closed + NonnullOwnPtr m_socket; }; } diff --git a/Libraries/LibWebSocket/Impl/WebSocketImplSerenity.cpp b/Libraries/LibWebSocket/Impl/WebSocketImplSerenity.cpp index f575cc0a2d3..9d18a27627d 100644 --- a/Libraries/LibWebSocket/Impl/WebSocketImplSerenity.cpp +++ b/Libraries/LibWebSocket/Impl/WebSocketImplSerenity.cpp @@ -45,13 +45,8 @@ void WebSocketImplSerenity::connect(ConnectionInfo const& connection_info) auto socket_result = [&]() -> ErrorOr> { auto host = connection_info.url().serialized_host().to_byte_string(); if (connection_info.is_secure()) { - TLS::Options options; - options.set_alert_handler([this](auto) { - on_connection_error(); - }); - return TRY(Core::BufferedSocket::create( - TRY(TLS::TLSv12::connect(host, connection_info.url().port_or_default(), move(options))))); + TRY(TLS::TLSv12::connect(host, connection_info.url().port_or_default())))); } return TRY(Core::BufferedTCPSocket::create( @@ -66,6 +61,7 @@ void WebSocketImplSerenity::connect(ConnectionInfo const& connection_info) } m_socket = socket_result.release_value(); + MUST(m_socket->set_blocking(false)); m_socket->on_ready_to_read = [this] { on_ready_to_read(); diff --git a/Tests/LibTLS/TestTLSHandshake.cpp b/Tests/LibTLS/TestTLSHandshake.cpp index 340f9664ead..be50d938a82 100644 --- a/Tests/LibTLS/TestTLSHandshake.cpp +++ b/Tests/LibTLS/TestTLSHandshake.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Peter Bocan + * Copyright (c) 2025, Altomani Gianluca * * SPDX-License-Identifier: BSD-2-Clause */ @@ -10,7 +11,6 @@ #include #include #include -#include #include #include @@ -24,10 +24,7 @@ static ByteBuffer operator""_b(char const* string, size_t length) return ByteBuffer::copy(string, length).release_value(); } -ErrorOr> load_certificates(); -ByteString locate_ca_certs_file(); - -ByteString locate_ca_certs_file() +static Optional locate_ca_certs_file() { if (FileSystem::exists(ca_certs_file)) { return ca_certs_file; @@ -36,50 +33,23 @@ ByteString locate_ca_certs_file() if (FileSystem::exists(on_target_path)) { return on_target_path; } - return ""; -} - -ErrorOr> load_certificates() -{ - auto cacert_file = TRY(Core::File::open(locate_ca_certs_file(), Core::File::OpenMode::Read)); - auto data = TRY(cacert_file->read_until_eof()); - return TRY(DefaultRootCACertificates::parse_pem_root_certificate_authorities(data)); + return {}; } TEST_CASE(test_TLS_hello_handshake) { - Core::EventLoop loop; TLS::Options options; - options.set_root_certificates(TRY_OR_FAIL(load_certificates())); - options.set_alert_handler([&](TLS::AlertDescription) { - FAIL("Connection failure"); - loop.quit(1); - }); - options.set_finish_callback([&] { - loop.quit(0); - }); + options.set_root_certificates_path(locate_ca_certs_file()); auto tls = TRY_OR_FAIL(TLS::TLSv12::connect(DEFAULT_SERVER, port, move(options))); - ByteBuffer contents; - tls->on_ready_to_read = [&] { - (void)TRY_OR_FAIL(tls->read_some(contents.must_get_bytes_for_writing(4 * KiB))); - loop.quit(0); - }; - if (tls->write_until_depleted("GET / HTTP/1.1\r\nHost: "_b).is_error()) { - FAIL("write(0) failed"); - return; - } + TRY_OR_FAIL(tls->write_until_depleted("GET /generate_204 HTTP/1.1\r\nHost: "_b)); auto the_server = DEFAULT_SERVER; - if (tls->write_until_depleted(the_server.bytes()).is_error()) { - FAIL("write(1) failed"); - return; - } - if (tls->write_until_depleted("\r\nConnection : close\r\n\r\n"_b).is_error()) { - FAIL("write(2) failed"); - return; - } + TRY_OR_FAIL(tls->write_until_depleted(the_server.bytes())); + TRY_OR_FAIL(tls->write_until_depleted("\r\nConnection: close\r\n\r\n"_b)); - loop.exec(); + auto tmp = TRY_OR_FAIL(ByteBuffer::create_zeroed(128)); + auto contents = TRY_OR_FAIL(tls->read_some(tmp)); + EXPECT(contents.starts_with("HTTP/1.1 204 No Content\r\n"_b)); }