Hi,
during some research we noticed an interesting implementation bug inside the
com.sun.crypto.provider.TlsPrfGenerator.expand(..) function.
The problem is that an internal for loop das some XOR magic on passed arrays:
for (int i = 0; i < secLen; i++) {
pad1[i] ^= secret[i + secOff];
pad2[i] ^= secret[i + secOff];
}
But nowhere is checked if the passed arrays are of a suitable length (at least
== secLen). We were able to get into a state where secLen is greather than
pad1.length and thus leading to an ArrayIndexOutOfBoundsException while
iterating.
This caused the SSLSocket to terminate (which is ok), but finally sending a
TLSv1 FATAL ALERT: internal_error where instead a TLSv1 FATAL ALERT:
handshake_failure should be returned.
>From developers point of view this seems to be a careless mistake, but from
cryptographers point of view these different error messages may give some
valuable hints on how the message was decrypted (chosen-ciphertext attacks).
The problem was found during research on Bleichenbacher's attack on SSL. A
non-conforming PKCS message with two 0x0 separation bytes in combination with
2048/4096 bit RSA keys will reproduce this scenario.
StackTraces (good/bad case) follow below:
how it should look like (1024 bit RSA keys):
--------------------------------------------
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1
SESSION KEYGEN:
PreMaster Secret:
0000: 29 1B DD F3 23 2D 59 1F 65 17 93 EF 85 F3 1F 7F )...#-Y.e.......
0010: 69 BB FF C9 57 0B 67 4B 41 69 F9 CB 85 D9 71 D7 i...W.gKAi....q.
0020: 8F 63 71 C9 8D AB 00 03 01 E5 A5 8B BD 45 C4 99 .cq..........E..
0030: FF 5B F5 D2 DB A1 59 21 30 37 94 7C 2E 48 6A 8D .[....Y!07...Hj.
0040: 08 9B 5F 91 2E 1C 49 8E FD 6B E8 A2 56 8F 81 A7 .._...I..k..V...
0050: CD CD 10 4C 03 28 6B ...L.(k
RSA PreMasterSecret version error: expectedTLSv1 or TLSv1, decrypted:
Unknown-41.27
Generating new random premaster secret
SESSION KEYGEN:
PreMaster Secret:
0000: 03 01 E0 75 34 84 96 F2 CB 65 3E 09 C8 82 E3 38 ...u4....e>....8
0010: CA 1B 0E 85 6B 8A E5 BA 7F C5 51 ED F1 ED 4F 8F ....k.....Q...O.
0020: BFinalizer, called close()
3 59Finalizer, called closeInternal(true)
C3 C7 72 B2 17 53 55 F3 40 3B A9 4C 16 42 .Y..r..SU.@;.L.B
CONNECTION KEYGEN:
Client Nonce:
0000: 00 00 01 37 28 27 B6 E0 3E D5 6F 8D 3D D6 B0 D8 ...7('..>.o.=...
0010: 13 D2 62 75 2F 21 0C 6E 3D 76 B1 86 12 18 81 55 ..bu/!.n=v.....U
Server Nonce:
0000: 4F C4 CF B6 42 29 3C CD 97 44 C1 66 1A 5F 3B 5A O...B)<..D.f._;Z
0010: 3A EF 06 08 8A 48 E2 39 A8 42 0C 96 52 1F 7F 4F :....H.9.B..R..O
Master Secret:
0000: C3 8F 4D 51 9D 20 BB 17 42 0F 70 E2 C2 5E BB AA ..MQ. ..B.p..^..
0010: E2 55 45 BE D6 3D D3 11 B5 E7 59 E3 A1 26 EB 14 .UE..=....Y..&..
0020: FE 07 AF 80 6D 5A EC FB 11 12 CD EF 08 ED 31 7E ....mZ........1.
Client MAC write Secret:
0000: F6 0B 0B 73 6E FC CE 0A F3 64 F2 6C 5E D9 DF F2 ...sn....d.l^...
0010: A8 A4 98 22 ..."
Server MAC write Secret:
0000: D8 AC 63 54 F3 EA F6 55 C7 FE 08 70 FA 7D B8 32 ..cT...U...p...2
0010: 7A 21 4E 1B z!N.
Client write key:
0000: 43 22 FA 3A B2 80 CE 5E 37 41 8C 23 7D 40 28 5C C".:...^7A.#.@(\
Server write key:
0000: DF CF 6F CD 1F FD F4 37 E1 93 DE BF 89 16 6E 5F ..o....7......n_
Client write IV:
0000: DC 57 88 79 7B 78 B2 30 29 D4 3C 3F BF CB 01 57 .W.y.x.0).<?...W
Server write IV:
0000: EA A7 4B 01 69 C6 10 5B 41 E3 CD 58 95 26 A0 F2 ..K.i..[A..X.&..
Thread-2, READ: TLSv1 Change Cipher Spec, length = 1
Thread-2, READ: TLSv1 Handshake, length = 48
========>
========>
========> Thread-2, SEND TLSv1 ALERT: fatal, description = handshake_failure
========>
========>
Thread-2, WRITE: TLSv1 Alert, length = 2
Thread-2, called closeSocket()
Thread-2, handling exception: javax.net.ssl.SSLHandshakeException: Invalid
padding
javax.net.ssl.SSLHandshakeException: Invalid padding
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1697)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:904)
at
sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1190)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:657)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:108)
at java.io.OutputStream.write(OutputStream.java:75)
at
de.rub.nds.research.ssl.stack.tests.common.SSLServer.run(SSLServer.java:86)
at java.lang.Thread.run(Thread.java:679)
Caused by: javax.crypto.BadPaddingException: Padding length invalid: 55
at sun.security.ssl.CipherBox.removePadding(CipherBox.java:423)
at sun.security.ssl.CipherBox.decrypt(CipherBox.java:271)
at sun.security.ssl.InputRecord.decrypt(InputRecord.java:172)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:892)
... 6 more
how it looks when dealing with 2048, 4096 bit RSA keys:
-------------------------------------------------------
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1
SESSION KEYGEN:
PreMaster Secret:
0000: 2B 05 89 91 6F F5 87 35 B9 8B 77 69 CF 83 8F CF +...o..5..wi....
0010: 6F 23 37 C9 E3 2F A9 51 C7 9D 3B 81 37 CB 61 F3 o#7../.Q..;.7.a.
0020: CB 29 21 E9 05 B7 73 8B 7F 6D 69 91 51 31 35 33 .)!...s..mi.Q153
0030: E5 03 A9 69 D3 23 9B 13 F3 4B 67 89 FD C9 9B 4D ...i.#...Kg....M
0040: A3 BB E5 AB 5D 85 D7 1D 79 8F 45 17 17 93 55 15 ....]...y.E...U.
0050: AD B7 17 33 CD 39 83 F7 6F 1F 4D EF A7 DD A5 55 ...3.9..o.M....U
0060: 0B A7 FB 99 33 09 00 03 01 1F EE 99 A8 6F C9 51 ....3........o.Q
0070: 7B 06 28 ED ED 34 84 65Finalizer, called close()
Finalizer, called closeInternal(true)
8B 7E 0A D3 05 57 1B E7 ..(..4.e.....W..
0080: CA 80 FC 34 6D A4 3D 9D B4 49 DB 85 24 71 3F CF ...4m.=..I..$q?.
0090: 8C E6 CA 63 1F 01 2A ...c..*
Thread-2, handling exception: java.lang.ArrayIndexOutOfBoundsException: 64
========>
========>
========> Thread-2, SEND TLSv1 ALERT: fatal, description = internal_error
========>
========>
Thread-2, WRITE: TLSv1 Alert, length = 2
Thread-2, called closeSocket()
javax.net.ssl.SSLException: java.lang.ArrayIndexOutOfBoundsException: 64
at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1697)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1660)
at
sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1643)
at
sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1569)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:113)
at java.io.OutputStream.write(OutputStream.java:75)
at
de.rub.nds.research.ssl.stack.tests.common.SSLServer.run(SSLServer.java:86)
at java.lang.Thread.run(Thread.java:679)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 64
at
com.sun.crypto.provider.TlsPrfGenerator.expand(TlsPrfGenerator.java:216)
at
com.sun.crypto.provider.TlsPrfGenerator.doPRF(TlsPrfGenerator.java:187)
at
com.sun.crypto.provider.TlsPrfGenerator.doPRF(TlsPrfGenerator.java:159)
at
com.sun.crypto.provider.TlsMasterSecretGenerator.engineGenerateKey(TlsMasterSecretGenerator.java:107)
at javax.crypto.KeyGenerator.generateKey(KeyGenerator.java:516)
at
sun.security.ssl.Handshaker.calculateMasterSecret(Handshaker.java:769)
at sun.security.ssl.Handshaker.calculateKeys(Handshaker.java:732)
at
sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:235)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:609)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:545)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:945)
at
sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1190)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:657)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:108)
... 3 more
We only tested this with 1024, 2048, 4096 bit keys.
Maybe a simple length check inside the expand function could solve the issue.
Regards,
Chris
______________________________________
Dipl.-Ing. Christopher Meyer
Horst Görtz Institute for IT-Security
Chair for Network and Data Security
Ruhr-University Bochum, Germany
Universitätsstr. 150, ID 2/415
D-44801 Bochum, Germany
http:// www.nds.rub.de
Phone: (+49) (0)234 / 32 - 29815
Fax: (+49) (0)234 / 32 - 14347