9001039?: DHKeyAgreement calculates wrong TlsPremasterSecret 1 out of 256 times

Xuelei Fan xuelei.fan at oracle.com
Wed May 29 08:14:52 UTC 2013


Thank you for considering this improvement.  I'm planing to integrate
the patch into OpenJDK workspace this week.

Thanks & Regards,
Xuelei

On 5/29/2013 3:33 PM, Pasi Eronen wrote:
> Hi Xuelei,
> 
> I did notice that P11Util has a trimZeroes() function, but I didn't call 
> it since I didn't want to add a new package dependency. But now that you 
> mention it, moving it to KeyUtil seems like the best solution. 
> 
> I have submitted a revised patch to the Bugzilla ticket which does
> just this:
> 
> https://bugs.openjdk.java.net/attachment.cgi?id=307&action=diff
> 
> Best regards,
> Pasi
> 
> 
> 
> On Thu, May 23, 2013 at 1:39 PM, Xuelei Fan <xuelei.fan at oracle.com
> <mailto:xuelei.fan at oracle.com>> wrote:
> 
> 
>     On 5/23/2013 6:03 PM, Andrew Hughes wrote:
>     > ----- Original Message -----
>     >> On 5/20/2013 5:28 PM, Pasi Eronen wrote:
>     >>> Hi Xuelei,
>     >>>
>     >>> It seems the PKSC11 doesn't actually have this bug.
>     >>>
>     >>> P11KeyAgreement has a separate code path for the
>     "TlsPremasterSecret"
>     >>> algorithm, which strips leading zeroes if the key can be
>     extracted from
>     >>> the token. (And if the key cannot be extracted, then the token
>     is doing
>     >>> the premaster secret->master secret computation, and has to do the
>     >>> stripping -- it can't be done from the Java PKSC11 provider.)
>     >>>
>     >> It makes sense to me.
>     >>
>     >>> To make sure this behavior doesn't change, I added a test case
>     >>> for the PKSC11 provider to the Bugzilla (which passes with the
>     >>> "SunPKCS11-NSS" provider without any changes).
>     >>>
>     >> That's great.  Would you mind to contribute the regression test for
>     >> PKCS11 provider?
>     >>
>     >
>     > It's been attached to the bug report:
>     https://bugs.openjdk.java.net/show_bug.cgi?id=100316
>     >
>     Thanks Andrew!
> 
>     > Is there any reason the original patch can't be committed?  I
>     haven't seen any mentioned.
>     >
>     It is accepted.  The minor comment I mentioned in the previous mail is
>     that we may want to merge the functions to trim leading zeros in one
>     method.
> 
>     There is a method sun.security.pkcs11.P11Util.trimZeroes(byte[] b) which
>     is used to trim leading zeros.  I think it would be nice to move the
>     method to sun.security.util.KeyUtil, and make use of this method in the
>     patch of DHKeyAgreement.engineGenerateSecret(String algorithm) as well.
> 
>     Pasi, what do you think?
> 
>     Otherwise, the patch looks fine to me.
> 
>     I can be the sponsor if you won't able to merge the changes into openJDk
>     workspace.
> 
>     Thanks,
>     Xuelei
> 
>     >> Thanks,
>     >> Xuelei
>     >>
>     >>> Best regards,
>     >>> Pasi
>     >>>
>     >>>
>     >>>
>     >>> On Thu, May 16, 2013 at 10:56 AM, Xuelei Fan
>     <xuelei.fan at oracle.com <mailto:xuelei.fan at oracle.com>
>     >>> <mailto:xuelei.fan at oracle.com <mailto:xuelei.fan at oracle.com>>>
>     wrote:
>     >>>
>     >>>     Hi Pasi,
>     >>>
>     >>>     Thank you for your patience, and contribution to OpenJDK.
>      The bug is
>     >>>     accepted, and you should be able to review it at:
>     >>>
>     >>>        http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8014618
>     >>>
>     >>>     Let's use the above bug ID to track the issue.
>     >>>
>     >>>     Your patch looks fine in general (I may have some very minor
>     comments
>     >>>     later).  We also have similar problems in PKCS11 provider
>     because of
>     >>>     the
>     >>>     update of P11KeyAgreement.java in changeset:
>     >>>
>     >>>        
>     http://hg.openjdk.java.net/jdk7u/jdk7u-gate/jdk/rev/e574e475c8a6
>     >>>
>     >>>     Would you like to also fix it in your patch?
>     >>>
>     >>>     Thanks again for your nice work.
>     >>>
>     >>>     Regards,
>     >>>     Xuelei
>     >>>
>     >>>
>     >>>     On 5/10/2013 5:00 PM, Pasi Eronen wrote:
>     >>>     > AKA "1 out of 256 SSL/TLS handshakes fails with DHE cipher
>     suites"
>     >>>     >
>     >>>     > I reported this bug over a month of ago, but for some
>     reason, it's
>     >>>     > not
>     >>>     > yet visible at bugs.sun.com <http://bugs.sun.com>
>     <http://bugs.sun.com>
>     >>>     <http://bugs.sun.com>. I've included the bug
>     >>>     > report below just in
>     >>>     > case.
>     >>>     >
>     >>>     > It seems this commit from March 2012 inadvertently broke
>     SSL/TLS DHE
>     >>>     > cipher suites, causing the SSL/TLS handshake to fail
>     approximately
>     >>>     > 1 out of 256 times:
>     >>>     >
>     >>>     >
>     http://hg.openjdk.java.net/jdk7u/jdk7u-gate/jdk/rev/e574e475c8a6
>     >>>     >
>     >>>     > The commit was done to fix this bug:
>     >>>     >
>     >>>     > http://bugs.sun.com/view_bug.do?bug_id=7146728
>     >>>     >
>     >>>     > While generating a secret of the same length as modulus
>     may be the
>     >>>     right
>     >>>     > choice generally speaking (and it's what e.g. IPsec uses),
>     SSL/TLS
>     >>>     uses
>     >>>     > a different convention: leading zeroes must be stripped.
>     >>>     >
>     >>>     > This is currently blocking us from updating our production
>     systems to
>     >>>     > Java 7, so although I have not contributed to OpenJDK
>     before, I'd
>     >>>     > like
>     >>>     > to submit a patch and a test case for this (I've signed
>     the OCA
>     >>>     > already). But before I do this, I'd like to check that the
>     approach
>     >>>     > is
>     >>>     > agreeable.
>     >>>     >
>     >>>     > We have a separate "algorithm" value "TlsPremasterSecret", so
>     >>>     > behavior for other cases could stay the same. Would a patch
>     >>>     > like this:
>     >>>     >
>     >>>     >     } else if (algorithm.equals("TlsPremasterSecret")) {
>     >>>     >         // remove leading zero bytes per RFC 5246 Section
>     8.1.2
>     >>>     >         int i = 0;
>     >>>     >         while ((i < secret.length - 1) && (secret[i] == 0)) {
>     >>>     >             i++;
>     >>>     >         }
>     >>>     >         if (i == 0) {
>     >>>     >             return new SecretKeySpec(secret,
>     "TlsPremasterSecret");
>     >>>     >         } else {
>     >>>     >             byte[] secret2 = new byte[secret.length - i];
>     >>>     >             System.arraycopy(secret, i, secret2, 0,
>     secret2.length);
>     >>>     >             return new SecretKeySpec(secret2,
>     "TlsPremasterSecret");
>     >>>     >         }
>     >>>     >     }
>     >>>     >
>     >>>     > Plus a test case (with fixed keys) that checks that
>     leading zero is
>     >>>     > stripped
>     >>>     > for TlsPremasterSecret and is not stripped otherwise, be
>     sufficient?
>     >>>     >
>     >>>     > Best regards,
>     >>>     > Pasi
>     >>>     >
>     >>>     > ---snip---
>     >>>     >
>     >>>     > Synopsis:
>     >>>     > DHKeyAgreement calculates wrong TlsPremasterSecret 1 out
>     of 256 times
>     >>>     >
>     >>>     > Full OS version:
>     >>>     > Tested on Windows 7 (Microsoft Windows [Version
>     6.1.7601]), but
>     >>>     occurs in
>     >>>     > e..g OpenJDK 7 as well.
>     >>>     >
>     >>>     > Development Kit or Runtime version:
>     >>>     > java version "1.7.0_17"
>     >>>     > Java(TM) SE Runtime Environment (build 1.7.0_17-b02)
>     >>>     > Java HotSpot(TM) Client VM (build 23.7-b01, mixed mode,
>     sharing)
>     >>>     >
>     >>>     > Description:
>     >>>     > When performing Diffie-Hellman key agreement for SSL/TLS,
>     the TLS
>     >>>     > specification (RFC 5246) says that "Leading bytes of Z that
>     >>>     contain all zero
>     >>>     > bits are stripped before it is used as the pre_master_secret."
>     >>>     >
>     >>>     > However, com.sun.crypto.provider.DHKeyAgreement.java does not
>     >>>     strip leading
>     >>>     > zero bytes. This causes approximately 1 out 256 SSL/TLS
>     handshakes
>     >>>     with
>     >>>     > DH/DHE cipher suites to fail (when the leading byte
>     happens, by
>     >>>     chance, to
>     >>>     > be zero).
>     >>>     >
>     >>>     > Steps to Reproduce:
>     >>>     > 1. Start a simple JSSE socket server with
>     -Djavax.net.debug=all.
>     >>>     >
>     >>>     > 2. Connect to the server with e.g. OpenSSL command line tool,
>     >>>     ensuring that
>     >>>     > DHE cipher suite gets selected (e.g. "openssl s_client -cipher
>     >>>     > DHE-RSA-AES128-SHA -connect 192.168.81.1:9999
>     <http://192.168.81.1:9999>
>     >>>     <http://192.168.81.1:9999>
>     >>>     > <http://192.168.81.1:9999>") repeatedly. Other SSL
>     >>>     > clients can be used -- this is not an OpenSSL bug (see below).
>     >>>     >
>     >>>     > 3. Repeat the connection. After a couple of hundred successful
>     >>>     connections,
>     >>>     > the connection will fail with handshake_failure alert.
>     >>>     >
>     >>>     > 4. Examine the JSSE debug logs produced by the server: the
>     failed
>     >>>     connection
>     >>>     > will have a PreMaster secret that begins with zero byte
>     >>>     > (while all other connections have non-zero byte here). For
>     example:
>     >>>     >
>     >>>     > SESSION KEYGEN:
>     >>>     > PreMaster Secret:
>     >>>     > 0000: 00 70 C5 7E 91 38 C8 DE   ED 75 3D 76 8A B5 44 69
>     >>>      .p...8...u=v..Di
>     >>>     > 0010: E7 32 1C EE 80 77 50 C7   A9 51 24 2E E3 15 11 30
>     >>>      .2...wP..Q$....0
>     >>>     > 0020: 9D F6 9F BC 9D EB 5C 18   F7 A4 19 ED 1A AC 2E 0C
>     >>>      ......\.........
>     >>>     > 0030: E3 18 C5 11 B1 80 07 7D   B1 C6 70 A8 D7 EB CF DD
>     >>>      ..........p.....
>     >>>     > 0040: 2D B5 1D BC 01 3E 28 2A   2B 5B 38 8F EB 20 F2 A2
>     >>>      -....>(*+[8.. ..
>     >>>     > 0050: 00 07 47 F7 87 B8 99 CB   EF B4 13 04 C8 8B 82 FB
>     >>>      ..G.............
>     >>>     >
>     >>>     > Expected Result:
>     >>>     > Expected result is that every connection succeed.
>     >>>     >
>     >>>     > Actual Result:
>     >>>     > Roughly one out of 256 connections fail.
>     >>>     >
>     >>>     > Source code for an executable test case:
>     >>>     >
>     >>>     > Java server:
>     >>>     >
>     >>>     > import javax.net.ssl.SSLServerSocket;
>     >>>     > import javax.net.ssl.SSLServerSocketFactory;
>     >>>     > import javax.net.ssl.SSLSocket;
>     >>>     >
>     >>>     > public class TestServer {
>     >>>     >     public static void main(String args[]) throws Exception {
>     >>>     >         SSLServerSocketFactory ssf = (SSLServerSocketFactory)
>     >>>     > SSLServerSocketFactory.getDefault();
>     >>>     >         SSLServerSocket ss = (SSLServerSocket)
>     >>>     ssf.createServerSocket(9999);
>     >>>     >         System.out.println("Listening on port 9999");
>     >>>     >         for (String cs : ss.getEnabledCipherSuites()) {
>     >>>     >             System.out.println(cs);
>     >>>     >         }
>     >>>     >         while (true) {
>     >>>     >             SSLSocket s = (SSLSocket) ss.accept();
>     >>>     >             System.out.println("Connected with
>     >>>     > "+s.getSession().getCipherSuite());
>     >>>     >             s.close();
>     >>>     >         }
>     >>>     >     }
>     >>>     > }
>     >>>     >
>     >>>     > Run as as follows:
>     >>>     >
>     >>>     > keytool -storepass "password" -keypass "password" -genkey
>     -keyalg RSA
>     >>>     > -keystore test_keystore.jks -dname CN=test
>     >>>     > javac TestServer.java
>     >>>     > java -Djavax.net.debug=all
>     >>>     -Djavax.net.ssl.keyStore=./test_keystore.jks
>     >>>     > -Djavax.net.ssl.keyStorePassword=password TestServer
>     >>>     >
>     >>>     > OpenSSL client:
>     >>>     >
>     >>>     > set -e
>     >>>     > while true; do
>     >>>     >   openssl s_client -cipher DHE-RSA-AES128-SHA -connect
>     >>>     127.0.0.1:9999 <http://127.0.0.1:9999> <http://127.0.0.1:9999>
>     >>>     > <http://127.0.0.1:9999> -quiet -no_ign_eof < /dev/null
>     >>>     > done
>     >>>     >
>     >>>     > Workaround:
>     >>>     > Disable Diffie-Hellman cipher suites.
>     >>>     >
>     >>>     > ---snip---
>     >>>     >
>     >>>
>     >>>
>     >>
>     >>
>     >
> 
> 




More information about the security-dev mailing list