Closed saravananmk closed 6 years ago
maybe there is a confusion. All client key exchange messages are ephemeral. TLS-Attacker just uses the key from the config
maybe there is a confusion.
Sorry for the confusion.
Let me explain with an example.
For simplicity I am using the following names as alias: Alice = TLS-Attacker client Bob = Win2012R2 server - IIS in https mode
Normal DHE in TLS:
Bob sends DHE domain parameters g, p, and his public key B in the ServerKeyExchange message.
g = generator p = prime b = Bob ephemeral secret key B = g^b mod p = Bob ephemeral public key because b is ephemeral
Upon receiving this, Alice generate her own ephemeral secret key "a".
A = g^a mod p = Alice ephemeral public key because a is ephemeral
The point to note here is: a, A, b, B all are ephemeral. i.e. they are unique for each DHE keyexchange. They are not re-used for other sessions.
Now the shared secret Z = A^b mod p = B^a mod p = g^(ab) mod p.
DHE uses this Z as the premaster secret after stripping the leading 0x00 byte(s) if any as per TLS RFC.
In practice, many servers re-use the server ephemeral keys (b,B) for an hour or more for efficiency reasons. e.g. Windows servers always do that for two hours (this setting is hard coded). F5 BIG-IP load balancers always do that for one hour unless "Single DH Use" option is enabled in the corresponding SSL profile. Thus, in our example, Bob side it is not purely ephemeral due to the key reuse for two hours (being a Windows server).
What I noticed is, when Alice send her ClientKeyExchange, she is not using a fresh key (ephemeral) as well. Thus she always use the same {a,A}. Example:
Session#1:
DHClientKeyExchangePreparator - Computation PrivateKey: 30757838539894352412510553993926388250692636687493810307136098911018166940950 DHClientKeyExchangePreparator - PublicKey: B1 0B 88 E6 E5 A9 03 D9 46 BF 6D 7A CE DB 64 54 A0 A8 FA DD 4D B1 90 5A 71 07 B3 08 9E 52 CE 3A 2A 95 7A 5F 37 47 BC 5F A0 C2 E2 42 BF E5 AB A9 AB A7 A4 B0 A5 3C 39 E1 9A 4A DE F1 14 95 3C D7 13 2B 53 F9 0E BB 7B 53 45 ED 23 2F C9 5B 90 99 18 FE 3F 3E CA 14 14 28 01 59 0D 6F F7 30 96 10 6A AD AD EA 0E 52 78 2A B3 88 E4 32 D1 2C 90 37 B5 33 B1 79 DF 38 DE 7C 75 E4 45 ED 38 C8 4F BE 24 F8 3E A8 79 54 50 2B 81 B3 B8 34 C9 AC 62 7B 8C 45 05 1B 68 55 5A 05 E2 E8 81 DE BC 33 49 D8 4A FA 08 9B E2 40 5D 79 57 AA 68 C3 FF 90 92 AB 1D BA 8D 66 41 48 3F DF CC 38 CB 65 8F BB 0D C9 04 53 61 3C E9 6E 95 F4 7B D2 CC 65 91 01 88 11 11 89 48 95 1C FD 60 30 CF 17 3E 60 76 16 B2 EE B2 B8 30 F2 35 AE 4D 02 66 93 BC E0 93 1C F4 19 44 E9 48 4F DA 5E 99 0B 79 20 EC 71 B8 A9 63 83
Session#2:
DHClientKeyExchangePreparator - Computation PrivateKey: 30757838539894352412510553993926388250692636687493810307136098911018166940950 DHClientKeyExchangePreparator - PublicKey: B1 0B 88 E6 E5 A9 03 D9 46 BF 6D 7A CE DB 64 54 A0 A8 FA DD 4D B1 90 5A 71 07 B3 08 9E 52 CE 3A 2A 95 7A 5F 37 47 BC 5F A0 C2 E2 42 BF E5 AB A9 AB A7 A4 B0 A5 3C 39 E1 9A 4A DE F1 14 95 3C D7 13 2B 53 F9 0E BB 7B 53 45 ED 23 2F C9 5B 90 99 18 FE 3F 3E CA 14 14 28 01 59 0D 6F F7 30 96 10 6A AD AD EA 0E 52 78 2A B3 88 E4 32 D1 2C 90 37 B5 33 B1 79 DF 38 DE 7C 75 E4 45 ED 38 C8 4F BE 24 F8 3E A8 79 54 50 2B 81 B3 B8 34 C9 AC 62 7B 8C 45 05 1B 68 55 5A 05 E2 E8 81 DE BC 33 49 D8 4A FA 08 9B E2 40 5D 79 57 AA 68 C3 FF 90 92 AB 1D BA 8D 66 41 48 3F DF CC 38 CB 65 8F BB 0D C9 04 53 61 3C E9 6E 95 F4 7B D2 CC 65 91 01 88 11 11 89 48 95 1C FD 60 30 CF 17 3E 60 76 16 B2 EE B2 B8 30 F2 35 AE 4D 02 66 93 BC E0 93 1C F4 19 44 E9 48 4F DA 5E 99 0B 79 20 EC 71 B8 A9 63 83
Because of this all sessions for 2 hours (until Bob refresh his ephemeral key) ends up with the same shared secret and hence same Premaster secret.
Generally all clients (e.g. browsers) always use a fresh (ephemeral) key when DHE cipher is selected. Because of that, even though many servers re-use the ephemeral key for a duration, it will still result in different shared secret (and hence diff premaster secret) for each KeyEx session. So I was expecting a similar behaviour with Alice. But Alice is behaving as a static DH client using the same key {a,A} for all connections.
Even the message it is printing confirms she is behaving as DH client (not DHE client):
$ java -jar TLS-Client.jar -connect 192.168.1.1:443 -cipher TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 18:23:56 [main] INFO : DefaultWorkflowExecutor - Connecting to 192.168.1.1:443 18:23:56 [main] INFO : SendAction - Sending messages (client): CLIENT_HELLO, 18:23:56 [main] INFO : ReceiveAction - Received Messages (client): SERVER_HELLO, CERTIFICATE, DHE_SERVER_KEY_EXCHANGE, SERVER_HELLO_DONE, 18:23:56 [main] INFO : SendAction - Sending messages (client): DH_CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC, FINISHED, 18:23:57 [main] INFO : ReceiveAction - Received Messages (client): CHANGE_CIPHER_SPEC, FINISHED,
Note: for server it shows DHE_SERVER_KEY_EXCHANGE for client it shows DH_CLIENT_KEY_EXCHANGE
i.e. DHE (ephemeral) versus DH (static)
So that is what I asked in my original post:
+++++++++++++ Why it is sending static DH for ClientKeyExchange? Is there a way to enforce ephemeral DH for ClientKeyExchange? something like "DHE_CLIENT_KEY_EXCHANGE'? +++++++++++++
Hope my question is clear now.
TLS-Attacker is a tool meant for pentesters and researchers. It gives you as the user full control over which values it sends in the messages. The values TLS-Attacker uses for its messages are drawn from a configuration class called the Config. All values TLS-Attacker will ever use are dependent on this class and context of the session. The DH public key TLS-Attacker uses in its messages is also hard coded in the class. This is done to give you control over which public key will be used and makes debugging as well as the reproduceability of discovered issues easier. We are trying to remove randomness as far as possible from TLS-Attacker. Meaning that if TLS-Attacker encounters the same messages it should send the same messages itself again aswell. If you need TLS-Attacker to select different public keys in different Handshakes you need to manually configure this yourself. This can be done in the demo Client and Server with the -config flag, or in the in the code by changing the accoring values in the Config class.
For TLS-Attacker it makes no sense to randomize its inputs since it would make debugging of connections a nightmare. I hope this clarifies this.
Also related to your question: If TLS-Attacker really needs a Random source (for example CH Random Bytes) it uses a statically seeded PRNG.
I understand your justification. Thank you so much for the clarification.
Before you close this, one interesting info I wanted to share on why I wanted to use ephemeral keys for the ClientKeyExchange. Here is the background story:
I was testing Windows server (IIS in https mode) using curl.
With TLSv1.2, after client (curl) sent ClientKeyExchange, ChangeCipherSpec and Finished message, server is sending a TCP RST, for certain ciphers. The issue is intermittent in nature but easily reproducible. Say if you run a while loop and wait for a minute.
Server: Win2008R2 or Win2012R2 or Win2016 (all shows same behaviour) Client: Ubuntu - curl
$ curl --version curl 7.58.0 (x86_64-pc-linux-gnu) libcurl/7.58.0 OpenSSL/1.1.1 zlib/1.2.11 libidn2/2.0.4 libpsl/0.19.1 (+libidn2/2.0.4) nghttp2/1.30.0 librtmp/2.3 Release-Date: 2018-01-24 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL
run curl in a loop for say 1 minute and then you will hit the issue in one of the connection. I am able to reproduce this at will for DHE ciphers (e.g. 'DHE-RSA-AES128-GCM-SHA256', 'DHE-RSA-AES256-GCM-SHA384', etc).
$ while true; do curl -sS -k https://192.168.1.1 --cipher DHE-RSA-AES128-GCM-SHA256 --tlsv1.2 >/dev/null; done
curl will report: (intermittently) curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 192.168.1.1:443
A packet capture shows:
$ tshark -nr ./win2012r2-tcp-reset-issue.pcap -Y 'ssl.handshake.type == 2' -V | grep 'Cipher Suite:' Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)
$ tshark -nr ./win2012r2-tcp-reset-issue.pcap 1 0.000000 192.168.1.2 → 192.168.1.1 TCP 74 39290 → 443 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3428782366 TSecr=0 WS=128 2 0.000982 192.168.1.1 → 192.168.1.2 TCP 74 443 → 39290 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1 TSval=446369 TSecr=3428782366 3 0.001021 192.168.1.2 → 192.168.1.1 TCP 66 39290 → 443 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=3428782367 TSecr=446369 4 0.012760 192.168.1.2 → 192.168.1.1 TLSv1 325 Client Hello 5 0.016966 192.168.1.1 → 192.168.1.2 TCP 1514 [TCP segment of a reassembled PDU] 6 0.017007 192.168.1.2 → 192.168.1.1 TCP 66 39290 → 443 [ACK] Seq=260 Ack=1449 Win=32128 Len=0 TSval=3428782383 TSecr=446370 7 0.017026 192.168.1.1 → 192.168.1.2 TLSv1.2 120 Server Hello, Certificate, Server Key Exchange, Server Hello Done 8 0.017047 192.168.1.2 → 192.168.1.1 TCP 66 39290 → 443 [ACK] Seq=260 Ack=1503 Win=32128 Len=0 TSval=3428782383 TSecr=446370 9 0.019894 192.168.1.2 → 192.168.1.1 TLSv1.2 256 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message 10 0.022884 192.168.1.1 → 192.168.1.2 TCP 60 443 → 39290 [RST, ACK] Seq=1503 Ack=450 Win=0 Len=0
i.e. After client send the CKE, CCS, Finished (enc.handshake) message, the server will send a TCP RST. Windows event viewer shows this as following in the SYSTEM log:
Event ID:36888 Source: SChannel The following fatal alert was generated: 20. The internal error state is 960
MS documentation shows this as: 20 = Bad Record MAC 960 = Unwrap_DecryptFailure
With ubuntu/apache, using the same ciphers (for which I get intermittent failure on Windows) I do not see this issue. It is only happening with Windows servers.
I am able to reproduce this issue with both curl and python3 program as a client.
Upon further investigation, I learned that it was due to a Windows SChannel bug. When handling DHE (not-ECDHE) cipher, Schannel is not stripping the leading 0x00 byte(s) from the shared secret, which acts as Premaster secret. Thus Windows ends up with a wrong Master Secret and hence decrypting of Client FINISHED message fails resulting in Windows sending a TCP RST to the client.
The stripping of leading 0x00 byte(s) from the DHE shared secret is only applicable for DHE. ECDHE does use the leading zeroes as per RFC.
TLSv1.2 RFC5246: +++++++++++++++++ 8.1.2. Diffie-Hellman
A conventional Diffie-Hellman computation is performed. The negotiated key (Z) is used as the pre_master_secret, and is converted into the master_secret, as specified above. Leading bytes of Z that contain all zero bits are stripped before it is used as the pre_master_secret. ++++++++++++++++ RFC8422: Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS) Versions 1.2 and Earlier
5.10. ECDH, ECDSA, and RSA Computations
All ECDH calculations for the NIST curves (including parameter and key generation as well as the shared secret calculation) are performed according to [IEEE.P1363] using the ECKAS-DH1 scheme with the identity map as the Key Derivation Function (KDF) so that the premaster secret is the x-coordinate of the ECDH shared secret elliptic curve point represented as an octet string. Note that this octet string (Z in IEEE 1363 terminology), as output by FE2OSP (Field Element to Octet String Conversion Primitive), has constant length for any given field; leading zeros found in this octet string MUST NOT be truncated. ++++++++++++++++++
Just to confirm it is really Windows SChannel bug, I wanted to try with a different client and decided to use TLS-Attacker as a client for tesing. With curl, the issue is reproduceable in say one minute itself, running in a loop. Whereas when I used TLS-Attacker, even after one hour it was working fine. So I was wondering why I am unable to reproduce with TLS-Attacker.
Upon further investigation, I found Java also earlier had the same bug (not stripping the leading zeros in PMS while doing DHE handshakes) https://bugs.java.com/view_bug.do?bug_id=8014618 https://bugs.openjdk.java.net/browse/JDK-8014618
The Java version I used:
$ java -version java version "1.8.0_191" Java(TM) SE Runtime Environment (build 1.8.0_191-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)
It is already fixed in the version. So if SChannel has not fixed this issue, then it should fail intermittently with Java (as a client) as well. But when I used TLS-Attacker it is always working (I only ran it for few hours in a loop). So I was wondering why it is working and hence turned on the debug mode and noticed it is generating the same keys on the client side, ending up with the same shared secret until Windows generate a fresh ephemeral keys (say in 2 hours). In the few hours I ran TLS-Attacker only a few ephemeral keys changed on the Windows side. Luckily for all those keys, the resulting shared secret did not have any leading 0x00 byte(s). Hence it is always worked with TLS-Attacker as a client :-)
Since it is not possible to disable re-use of ephemeral keys on Windows Server via any Registry settings (I learned it is hardcoded; Ref: see the paper "Imperfect Forward Secrecy: How Diffie-Hellman Fails in Practice" by David Adrian, Karthikeyan Bhargavan, et.al), I was looking for a way, at least to enforce ephemeral key on the client side in TLS-Attacker.
Some links related to this Schannel bug: There is a Microsoft article about this issue, but it does not say their SChannel bug: https://blogs.technet.microsoft.com/keithab/2016/11/11/transport-layer-security-tls-handshake-failing-schannel-error-36888/
https://support.f5.com/csp/article/K10433354 {K10433354: TLS handshakes from some clients may intermittently fail when using Diffie-Hellman ciphers}
https://support.mulesoft.com/s/article/SSL-error-bad-MAC-on-connections {SSL error - Bad MAC on DHE connections}
Microsoft doc: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/9285068/ I am unable to access this any longer.
You can close this now. Thank you so much for your detailed clarification regarding my question.
Thanks for the insights! We have not analyzed S-Channel that much yet, mostly because I have no idea how to set it up properly and how to configure it. But I suspect more problems in TLS related Microsoft products.
Hi,
When I test with DHE ciphers, for e.g. like this:
$ java -jar TLS-Client.jar -connect 192.168.1.1:443 -cipher TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 18:23:56 [main] INFO : DefaultWorkflowExecutor - Connecting to 192.168.1.1:443 18:23:56 [main] INFO : SendAction - Sending messages (client): CLIENT_HELLO, 18:23:56 [main] INFO : ReceiveAction - Received Messages (client): SERVER_HELLO, CERTIFICATE, DHE_SERVER_KEY_EXCHANGE, SERVER_HELLO_DONE, 18:23:56 [main] INFO : SendAction - Sending messages (client): DH_CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC, FINISHED, 18:23:57 [main] INFO : ReceiveAction - Received Messages (client): CHANGE_CIPHER_SPEC, FINISHED,
Why it is sending static DH for ClientKeyExchange? Is there a way to enforce ephemeral DH for ClientKeyExchange? something like "DHE_CLIENT_KEY_EXCHANGE'?
with regards, Saravanan