-
Notifications
You must be signed in to change notification settings - Fork 918
Description
Contact Details
Version
v5.8.4-stable
Description
Hello wolfSSL team,
I would like to report an RFC 5246 compliance violation related to the handling of an empty Certificate message sent by the server.
According to RFC 5246, Section 7.4.2 (Certificate):
The certificate MUST be appropriate for the negotiated cipher suite's
key exchange algorithm and any negotiated extensions.
When using the cipher suite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, the server is required to send a Certificate message containing a valid certificate. However, wolfSSL client accepts an empty server Certificate message during a TLS 1.2 handshake, which violates the RFC requirement.
In the ProcessPeerCerts function, the absence of a peer certificate is only treated as an error when the negotiated protocol version is TLS 1.3:
else if ((ssl->options.side == WOLFSSL_CLIENT_END) &&
IsAtLeastTLSv1_3(ssl->version)) {
WOLFSSL_MSG("No peer cert from Server");
ret = NO_PEER_CERT;
WOLFSSL_ERROR_VERBOSE(ret);
SendAlert(ssl, alert_fatal, decode_error);
}As a result, when the session is negotiated as TLS 1.2, an empty Certificate message from the server is incorrectly accepted. The DoCertificate function returns 0 (success), and the handshake continues to DoServerKeyExchange.
Subsequently, DoServerKeyExchange attempts to retrieve the peer’s public key from the certificate and reports a “need peer key” error. While this function detects the missing public key, the protocol violation has already occurred, as the handshake should have failed immediately upon processing an empty server Certificate message.
For TLS 1.2 handshakes using cipher suites that require server authentication, an empty Certificate message must be rejected during certificate processing. Deferring this failure to the ServerKeyExchange phase results in non-compliant behavior with RFC 5246.
Thank you for your attention to this issue.
Best regards,
Jaehun Lee
Reproduction steps
- ./configure --enable-debug --enable-usersettings
- make install
- python3 empty.py
- examples/client/client -p 4444 -v 3 -l TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
user_settings.h
#define WC_NO_HARDEN
#define HAVE_ECC
#define HAVE_ALL_CURVES
#define WOLFSSL_TLS12
#define WOLFSSL_ALT_CERT_CHAINS
#define DEBUG_WOLFSSL
#define DEBUG_WOLFSSL_VERBOSE
#define OPENSSL_EXTRA
#define HAVE_AESGCM
#define HAVE_AESCCM
#define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
#define BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256
#define WC_RSA_PSS
#define WOLFSSL_TLS12
#define WOLFSSL_SHA256
#define WOLFSSL_SHA384
#define WOLFSSL_SHA512
#undef WOLFSSL_MD5
#undef WOLFSSL_MD5_SHA
empty.py
import socket
import binascii
def send_hex_to_server():
server_hello = (
"16 03 03 00 4a 02 00 00 46 03 03 70 38 4c d1 5c"
"ab c3 27 a5 76 91 39 2e 7e a1 96 78 2b d1 0b 8d"
"da a0 86 7e 1a 7e d8 e8 50 32 72 20 0e 05 d5 15"
"1a 3d 33 4b 30 5b fa 81 c0 42 15 67 1c 77 06 b5"
"66 dc ff ad 3f d5 9e 23 81 fe 2b b9 c0 2b 00"
)
server_certificate = (
"16 03 03 00 07 0b 00 00 03 00 00 00"
)
server_key_exchange = (
"16 03 03 00 93 0c 00 00 8f 03 00 17 41 04 6d 3d"
"75 ca d3 ca 28 f5 35 4a 70 68 dd 5e c1 b0 c8 90"
"bc 3d 4c c8 b4 39 15 e4 27 4b e7 65 15 94 f7 09"
"94 d2 7c 5c 74 c9 74 74 e4 45 26 98 eb 8d 9b 3d"
"b7 48 b9 d9 82 e4 27 7e 2c 3f 89 13 ce ea 04 03"
"00 46 30 44 02 20 5f c0 ef 3c 86 13 f7 b8 93 23"
"2a 3d 4c 10 36 ab 65 70 47 b9 41 6f cf 64 c3 69"
"d7 88 1c 4f 1f b4 02 20 1d 4d 70 a0 45 48 19 c5"
"e8 a1 59 3b 2c a5 ba c4 5e c7 55 ff bd bc b2 cf"
"fe 58 fb cb 6b 6d 24 f0"
)
server_hello_payload = binascii.unhexlify(server_hello.replace(" ", ""))
server_certificate_payload = binascii.unhexlify(server_certificate.replace(" ", ""))
server_key_exchange_payload = binascii.unhexlify(server_key_exchange.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)
conn.sendall(server_certificate_payload)
conn.sendall(server_key_exchange_payload)
except KeyboardInterrupt:
print("End")
if __name__ == "__main__":
send_hex_to_server()