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