-
Notifications
You must be signed in to change notification settings - Fork 921
Description
Contact Details
Version
v5.8.4-stable
Description
Hello wolfSSL Team,
I would like to report a behavior in wolfSSL that appears to violate RFC 8446 (TLS 1.3) regarding the handling of the client_certificate_type and server_certificate_type extensions.
In TLS 1.3, wolfSSL accepts the client_certificate_type and server_certificate_type extensions in a ServerHello message, which is not permitted by RFC 8446.
According to RFC 8446, Section 4.2 (Extensions), client_certificate_type and server_certificate_type MUST be sent in ClientHello(CH) or EncryptedExtensions(EE)
They are not allowed in ServerHello messages in TLS 1.3.
In the TLSX_Parse function, the message type is not checked when parsing these extensions:
#if defined(HAVE_RPK)
case TLSX_CLIENT_CERTIFICATE_TYPE:
WOLFSSL_MSG("Client Certificate Type extension received");
ret = CCT_PARSE(ssl, input + offset, size, msgType);
break;
case TLSX_SERVER_CERTIFICATE_TYPE:
WOLFSSL_MSG("Server Certificate Type extension received");
ret = SCT_PARSE(ssl, input + offset, size, msgType);
break;
#endif /* HAVE_RPK */As a result, these extensions can be included in arbitrary handshake messages.
While the corresponding parse functions appear to process only, ClientHello, ServerHello (which is valid for TLS 1.2) and EncryptedExtensions (potentially valid for TLS 1.3),
other handshake message types are not explicitly rejected. In such cases, the implementation should generate an unsupported_extension alert.
Additional Considerations
These extensions were originally defined for TLS 1.2 (RFC 7250). While RFC 8446 specifies limited usage of these extensions in TLS 1.3, their interoperability characteristics and precise semantics in TLS 1.3 are not described in the same level of detail as in TLS 1.2. As such, accepting them in a ServerHello message during TLS 1.3 negotiation may result in non-compliant behavior with respect to RFC 8446.
Best regards,
Jaehun Lee
Reproduction steps
Note that the reproduction steps provided in this report demonstrate the issue only for the client_certificate_type extension. However, based on the shared parsing logic in TLSX_Parse, it is evident that the same behavior applies to the server_certificate_type extension as well. Specifically, when the server_certificate_type extension is included in a ServerHello message, no unsupported_extension alert is generated.
- ./configure ./configure --enable-debug --enable-usersettings --enable-session-ticket --enable-savesession --enable-opensslextra --enable-psk
- make install
- python3 wrong-cli-type-ext.py
- ./examples/client/client -p 4444 -v 4 -l TLS_AES_128_CCM_SHA256
user_settings.h
#define PSK
#define OPENSSL_EXTRA
#define WOLFSSL_OPENSSL_COMPATIBLE
#define WOLFSSL_DTLS
#define HAVE_RPK
#define WC_NO_HARDEN
#define HAVE_SESSION_TICKET
#define PERSIST_SESSION_CACHE
#define WOLFSSL_STATIC_PSK
#define SESSION_INDEX
#define ENABLE_SESSION_CACHE_ROW_LOCK
#define WOLFSSL_SESSION_EXPORT
#define HAVE_ECC
#define HAVE_ECC_DHE
#define HAVE_ECC_KOBLITZ
#define WOLFSSL_CUSTOM_CURVES
//#define HAVE_CURVE25519 --- does not support arm architecture
#define HAVE_CURVE448
#define HAVE_ECC384
#define HAVE_ECC_SECPR2
#define HAVE_ECC192
#define HAVE_ECC224
#define HAVE_ECC512
#define HAVE_FFDHE_2048
#define HAVE_FFDHE_3072
#define HAVE_FFDHE_4092
#define HAVE_FFDHE_6144
#define HAVE_FFDHE_8192
#define HAVE_ALL_CURVES
#define HAVE_AESCCM
#define HAVE_AESGCM
#define HAVE_HKDF
#define BUILD_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
#define BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
#define BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
#define BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA
#define BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
#define BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
#define BUILD_TLS_RSA_WITH_NULL_MD5
#define BUILD_TLS_RSA_WITH_NULL_SHA
#define BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
#define BUILD_TLS_PSK_WITH_AES_128_CBC_SHA256
#define BUILD_TLS_PSK_WITH_AES_256_CBC_SHA384
#define BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
#define BUILD_TLS_PSK_WITH_NULL_SHA256
#define BUILD_TLS_PSK_WITH_NULL_SHA384
#define BUILD_TLS_PSK_WITH_NULL_SHA
#define BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
#define BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
#define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
#define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
#define BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
#define BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
#define BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
#define BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
#define BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
#define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
#define BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
#define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
#define BUILD_TLS_ECDHE_ECDSA_WITH_NULL_SHA
#define BUILD_TLS_ECDHE_PSK_WITH_NULL_SHA256
#define BUILD_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
#define BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
#define BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
#define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
#define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
#define BUILD_TLS_ECDH_RSA_WITH_RC4_128_SHA
#define BUILD_TLS_ECDH_ECDSA_WITH_RC4_128_SHA
#define BUILD_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
#define BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
#define BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
#define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
#define BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
#define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
#define BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
#define BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
#define BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
#define BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256
#define BUILD_TLS_RSA_WITH_NULL_SHA256
#define BUILD_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
#define BUILD_TLS_DHE_PSK_WITH_NULL_SHA256
#define BUILD_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
#define BUILD_TLS_DHE_PSK_WITH_NULL_SHA384
#define BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256
#define BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384
#define BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
#define BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
#define BUILD_TLS_DH_anon_WITH_AES_256_GCM_SHA384
#define BUILD_TLS_PSK_WITH_AES_128_GCM_SHA256
#define BUILD_TLS_PSK_WITH_AES_256_GCM_SHA384
#define BUILD_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
#define BUILD_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
#define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
#define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
#define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
#define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
#define BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
#define BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
#define BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
#define BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
#define BUILD_TLS_RSA_WITH_AES_128_CCM_8
#define BUILD_TLS_RSA_WITH_AES_256_CCM_8
#define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM
#define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
#define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
#define BUILD_TLS_PSK_WITH_AES_128_CCM
#define BUILD_TLS_PSK_WITH_AES_256_CCM
#define BUILD_TLS_PSK_WITH_AES_128_CCM_8
#define BUILD_TLS_PSK_WITH_AES_256_CCM_8
#define BUILD_TLS_DHE_PSK_WITH_AES_128_CCM
#define BUILD_TLS_DHE_PSK_WITH_AES_256_CCM
#define BUILD_TLS_AES_128_CCM_SHA256
#define BUILD_TLS_AES_128_CCM_8_SHA256
#define BUILD_TLS_AES_128_GCM_SHA256
#define BUILD_TLS_AES_256_GCM_SHA384
#define WOLFSSL_TLS12
#define WOLFSSL_SHA256
#define WOLFSSL_SHA384
#define WOLFSSL_SHA512
#undef WOLFSSL_MD5
#undef WOLFSSL_MD5_SHA
#define WOLFSSL_SP_4096
#define WOLFSSL_TLS13
#define WC_RSA_PSS
#define HAVE_PUBLIC_FFDHE
#define HAVE_FFDHE_2048
#define BUILD_TLS_AES_128_CCM_SHA256
#define WOLFSSL_ALT_CERT_CHAINS
#define HAVE_TLS_EXTENSIONS
#define HAVE_SUPPORTED_CURVES
#define DEBUG_WOLFSSL
#define DEBUG_WOLFSSL_VERBOSE
#define WOLFSSL_FUNC_TIME
wrong-cli-type-ext.py
import socket
import binascii
def send_hex_to_server():
server_hello = (
"16 03 03 00 80 02 00 00 7c 03 03 b9 82 1f dc b5"
"80 c1 dc e7 09 3f 34 ec 2a 96 7b 1c 8b 53 07 07"
"32 a6 e6 64 31 ba 8b 7b 39 d3 88 00 13 04 00 00"
"54 00 33 00 45 00 17 00 41 04 3f e1 d5 9a c7 7f"
"cd 32 a5 5a f3 c7 a0 8a 0c 7d 96 e7 b2 29 5d 78"
"fa e2 3f e9 28 af 36 9f 7a c6 3d 28 0f 03 3f ad"
"12 53 d3 1c e0 21 3b 85 88 50 3c a9 bd b4 fa 62"
"63 52 33 86 31 cf f0 b8 f2 99 00 2b 00 02 03 04"
"00 13 00 01 01"
)
server_hello_payload = binascii.unhexlify(server_hello.replace(" ", ""))
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(("127.0.0.1", 4444))
s.listen(1)
conn, addr = s.accept()
try:
client_hello = conn.recv(4096)
if not client_hello:
print("Connection closed")
print("Received: (hex):", client_hello.hex())
conn.sendall(server_hello_payload)
except KeyboardInterrupt:
print("End")
if __name__ == "__main__":
send_hex_to_server()