Our company currently is developing some IOT products based on GSM modules which are mostly not up-to-date. Unfortunately, GSM module producers don't often update their firmwares according to the latest changes to the standards. Also many useful features of TLS are disabled in these modules because of limited amount of RAM and other resources. This causes working with TLS gets difficult in many scenarios.
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 63
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 59
Version: TLS 1.2 (0x0303)
Random: 3ff366e05d5db792843deb432d36a4308986842d0735aeb7bbdcdbebe560f271
GMT Unix Time: Jan 1, 2004 03:46:32.000000000 Iran Standard Time
Random Bytes: 5d5db792843deb432d36a4308986842d0735aeb7bbdcdbebe560f271
Session ID Length: 0
Cipher Suites Length: 20
Cipher Suites (10 suites)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
Compression Methods Length: 1
Compression Methods (1 method)
Compression Method: null (0)
[JA3 Fullstring: 771,49195-49199-49187-49191-49161-49171-156-60-49172-49162,,,]
[JA3: 9eed0872a18327d26a4f401325d75c78]
As you can see the module supports TLS1.2
. Besides Client Hello
doesn't provide any TLS extension at all. Here's the response from server:
TLSv1.2 Record Layer: Alert (Level: Fatal, Description: Handshake Failure)
Content Type: Alert (21)
Version: TLS 1.2 (0x0303)
Length: 2
Alert Message
Level: Fatal (2)
Description: Handshake Failure (40)
What I've tried
I've converted all standard ciphersuite names into openssl ciphersuite names (using 'openssl ciphers -convert') and set them in haproxy configuration:
bind X.Y.Z.W:12135 ssl crt /usr/local/full.pem ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA
I've limited TLS version to 1.2 in haproxy config.
I've tried setting minimum TLS version to 1.0 and maximum TLS version to 1.3.
I've tried both ecc and rsa keyfiles. We use letsencrypt to issue X.509 certificates for our domain.
I've tried self-signed certificates generated by openssl.
Actually I don't know what exactly is causing the issue. what I know is other clients can establish TLS connection to the server with those ciphersuites but GSM module can't. Is it possible that openssl is refusing client because of lack of any TLS extension support by the client? What else do you think?
I should also mention that I've inspected a successful TLS handshake to another server (which is third party and I don't have any access to it) and If you find it useful I can post it here. I can also build openssl with any special flags or configurations if needed.
The ClientHello is certainly unusual because it has no extensions at all which is likely to cause problems. Do you have any logs from the server that can throw more light on specifically what it doesn't like?
What OpenSSL version are you using on the server?
Notably the client is not sending the signature_algorithms extension. The TLSv1.2 RFC says this:
If the client does not send the signature_algorithms extension, the
server MUST do the following:
- If the negotiated key exchange algorithm is one of (RSA, DHE_RSA,
DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA), behave as if client had
sent the value {sha1,rsa}.
- If the negotiated key exchange algorithm is one of (DHE…
The ClientHello is certainly unusual because it has no extensions at all which is likely to cause problems. Do you have any logs from the server that can throw more light on specifically what it doesn't like?
What OpenSSL version are you using on the server?
Notably the client is not sending the signature_algorithms extension. The TLSv1.2 RFC says this:
If the client does not send the signature_algorithms extension, the
server MUST do the following:
- If the negotiated key exchange algorithm is one of (RSA, DHE_RSA,
DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA), behave as if client had
sent the value {sha1,rsa}.
- If the negotiated key exchange algorithm is one of (DHE_DSS,
DH_DSS), behave as if the client had sent the value {sha1,dsa}.
- If the negotiated key exchange algorithm is one of (ECDH_ECDSA,
ECDHE_ECDSA), behave as if the client had sent value {sha1,ecdsa}.
So, in all cases it attempts to fall back to a sigalg based on SHA1. However, SHA1 is not allowed in the default security level in OpenSSL 3.x - so this could well be the problem. I'm not familiar with haproxy configuration so I don't know how to set the security level using it. When passing a ciphersuite list direct to OpenSSL you can add @SECLEVEL=0
onto the end of the list to set the default security level to 0.
What OpenSSL version are you using on the server?
The output of haproxy -vv
shows that I'm using OpenSSL 3.0.2
:
Built with OpenSSL version : OpenSSL 3.0.2 15 Mar 2022
Running on OpenSSL version : OpenSSL 3.0.2 15 Mar 2022
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports : TLSv1.0 TLSv1.1 TLSv1.2 TLSv1.3
OpenSSL providers loaded : default
I will check the solution and report the result back.
@mattcaswell I've tried to add @SECLEVEL=0
onto the end of ciphersuite list in haproxy configuration and it seems haproxy passes the whole list + @SECLEVEL=0
to the openssl. The good news is it had worked and everything seems ok to me.
After two weeks of trial and error I cannot imagine that it is working! Now I can sleep well at night thanks to your guidance.
Wish you the best.
@mattcaswell By the way I've noticed the server decided to handle TLS handshake using TLS_RSA_WITH_AES_128_GCM_SHA256
:
Transport Layer Security
TLSv1.2 Record Layer: Handshake Protocol: Server Hello
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 74
Handshake Protocol: Server Hello
Handshake Type: Server Hello (2)
Length: 70
Version: TLS 1.2 (0x0303)
Random: 94d192c296e26b3877708aec8cfa4a30c34eae0fca6cca6d444f574e47524401
GMT Unix Time: Feb 12, 2049 20:39:22.000000000 Iran Standard Time
Random Bytes: 96e26b3877708aec8cfa4a30c34eae0fca6cca6d444f574e47524401
Session ID Length: 32
Session ID: 833f60b0d36afa37f08e6bb3802bebe1682a865766e1c1aa3960b128fa4c7ca9
Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
Compression Method: null (0)
[JA3S Fullstring: 771,156,]
[JA3S: ac4776ae2f7042ea107581e2be63ffa1]
TLSv1.2 Record Layer: Handshake Protocol: Certificate
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 3961
Handshake Protocol: Certificate
Handshake Type: Certificate (11)
Length: 3957
Certificates Length: 3954
Certificates (3954 bytes)
TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 4
Handshake Protocol: Server Hello Done
Handshake Type: Server Hello Done (14)
Length: 0
When I limit the ciphersuites to TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
& TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
on the server, handshake fails again (Handshake Failure (40)
). Why I cannot use ECDHE as key exchange algorithm?
I've also noticed that changing key type from RSA to ECDSA will cause handshake failure even without limiting ciphersuites. Why this is happening?
Is there anyway to preset an EC group and enforce client to use it?
Not with OpenSSL. Actually it appears OpenSSL is being a bit restrictive here.
RFC8422 introduced the elliptic_curves extension (which was later renamed to "supported_groups" in a subsequent RFC). It says this about it:
A TLS client that proposes ECC cipher suites in its ClientHello
message SHOULD include these extensions.
So, the TLS client here is technically conformant with the RFC because the above statement is a SHOULD but not a MUST.
Subsequently the RFC says:
A client that proposes ECC cipher suites may choose not to include these extensions. In this case, the server is free to choose any one of the elliptic curves or point formats listed in [Section 5](https://datatracker.ietf.org/doc/html/rfc8422#section-5).
So, this allows OpenSSL to just pick a curve if the client hasn't provided a list to choose from. There aren't any MUSTs here, so I think OpenSSL is also conformant in deciding to fail the handshake in this case. But it would be possible for us to add the ability to choose an arbitrary one and that would also be ok.
Could other SSL implementations like libreSSL / WolfSSL accept this ClientHello to use EC based ciphersuites?
Yes, that is possible.
In my opinion, It might be good to have that feature if it is not against security constraints of OpenSSL. GSM modules really become tricky and difficult when it comes to TLS. I think this can help our project a lot and also improves security of connection of GSM modules to the servers. Thank you by the way, you've helped me a lot.
@mattcaswell Shall I open a feature-request issue for that purpose or this discussion is enough by the way?
Sorry for asking, I'm newbie to openssl community.