Mercurial > hg > openjdk > jigsaw > jdk
changeset 7346:f90b7503019f
Merge
author | vinnie |
---|---|
date | Wed, 17 Apr 2013 02:53:02 -0700 |
parents | 13e18d3ac414 (diff) 779ba708fee3 (current diff) |
children | 7ded74ffea36 |
files | src/share/lib/security/java.security-linux src/share/lib/security/java.security-macosx src/share/lib/security/java.security-solaris src/share/lib/security/java.security-windows src/share/native/java/lang/ResourceBundle.c |
diffstat | 59 files changed, 3043 insertions(+), 994 deletions(-) [+] |
line wrap: on
line diff
--- a/make/sun/splashscreen/Makefile Wed Apr 17 01:04:45 2013 -0700 +++ b/make/sun/splashscreen/Makefile Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -83,21 +83,17 @@ -framework JavaNativeFoundation else ifneq ($(PLATFORM), windows) CFLAGS += -DWITH_X11 - ifeq ($(PLATFORM), macosx)) - OTHER_LDLIBS += -liconv - CPPFLAGS += -I$(OPENWIN_HOME)/include \ - -I$(OPENWIN_HOME)/include/X11/extensions - OTHER_LDLIBS += -L$(OPENWIN_LIB) -lX11 -lXext $(LIBM) -pthread - else - CPPFLAGS += -I$(OPENWIN_HOME)/include -I$(OPENWIN_HOME)/include/X11/extensions - OTHER_LDLIBS += -L$(OPENWIN_LIB) -lX11 -lXext $(LIBM) -lpthread - endif + CPPFLAGS += -I$(OPENWIN_HOME)/include -I$(OPENWIN_HOME)/include/X11/extensions + OTHER_LDLIBS += -L$(OPENWIN_LIB) -lX11 -lXext $(LIBM) -lpthread else # PLATFORM CFLAGS += -DWITH_WIN32 OTHER_LDLIBS += kernel32.lib user32.lib gdi32.lib delayimp.lib /DELAYLOAD:user32.dll #$(JVMLIB) $(OBJDIR)/../../jpeg/$(OBJDIRNAME)/jpeg$(SUFFIX).lib endif # PLATFORM +# Add giflib include path for all platforms +CPPFLAGS += -I$(SHARE_SRC)/native/sun/awt/giflib + # # Add to ambient vpath to get files in a subdirectory #
--- a/src/share/classes/com/sun/crypto/provider/CipherCore.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/CipherCore.java Wed Apr 17 02:53:02 2013 -0700 @@ -426,17 +426,13 @@ } } try { - params = AlgorithmParameters.getInstance(algName, "SunJCE"); + params = AlgorithmParameters.getInstance(algName, + SunJCE.getInstance()); + params.init(spec); } catch (NoSuchAlgorithmException nsae) { // should never happen throw new RuntimeException("Cannot find " + algName + " AlgorithmParameters implementation in SunJCE provider"); - } catch (NoSuchProviderException nspe) { - // should never happen - throw new RuntimeException("Cannot find SunJCE provider"); - } - try { - params.init(spec); } catch (InvalidParameterSpecException ipse) { // should never happen throw new RuntimeException(spec.getClass() + " not supported");
--- a/src/share/classes/com/sun/crypto/provider/CipherWithWrappingSpi.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/CipherWithWrappingSpi.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -169,7 +169,8 @@ try { KeyFactory keyFactory = - KeyFactory.getInstance(encodedKeyAlgorithm, "SunJCE"); + KeyFactory.getInstance(encodedKeyAlgorithm, + SunJCE.getInstance()); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); key = keyFactory.generatePublic(keySpec); } catch (NoSuchAlgorithmException nsae) { @@ -191,8 +192,6 @@ } } catch (InvalidKeySpecException ikse) { // Should never happen. - } catch (NoSuchProviderException nspe) { - // Should never happen. } return key; @@ -215,7 +214,8 @@ try { KeyFactory keyFactory = - KeyFactory.getInstance(encodedKeyAlgorithm, "SunJCE"); + KeyFactory.getInstance(encodedKeyAlgorithm, + SunJCE.getInstance()); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); return keyFactory.generatePrivate(keySpec); } catch (NoSuchAlgorithmException nsae) { @@ -237,8 +237,6 @@ } } catch (InvalidKeySpecException ikse) { // Should never happen. - } catch (NoSuchProviderException nspe) { - // Should never happen. } return key;
--- a/src/share/classes/com/sun/crypto/provider/ConstructKeys.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/ConstructKeys.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.security.PrivateKey; import java.security.KeyFactory; import java.security.InvalidKeyException; -import java.security.NoSuchProviderException; import java.security.NoSuchAlgorithmException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; @@ -66,7 +65,8 @@ try { KeyFactory keyFactory = - KeyFactory.getInstance(encodedKeyAlgorithm, "SunJCE"); + KeyFactory.getInstance(encodedKeyAlgorithm, + SunJCE.getInstance()); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); key = keyFactory.generatePublic(keySpec); } catch (NoSuchAlgorithmException nsae) { @@ -94,8 +94,6 @@ new InvalidKeyException("Cannot construct public key"); ike.initCause(ikse); throw ike; - } catch (NoSuchProviderException nspe) { - // Should never happen. } return key; @@ -118,7 +116,8 @@ try { KeyFactory keyFactory = - KeyFactory.getInstance(encodedKeyAlgorithm, "SunJCE"); + KeyFactory.getInstance(encodedKeyAlgorithm, + SunJCE.getInstance()); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); return keyFactory.generatePrivate(keySpec); } catch (NoSuchAlgorithmException nsae) { @@ -146,8 +145,6 @@ new InvalidKeyException("Cannot construct private key"); ike.initCause(ikse); throw ike; - } catch (NoSuchProviderException nspe) { - // Should never happen. } return key;
--- a/src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java Wed Apr 17 02:53:02 2013 -0700 @@ -389,17 +389,13 @@ if (iv != null) { String algo = cipherKey.getAlgorithm(); try { - params = AlgorithmParameters.getInstance(algo, "SunJCE"); + params = AlgorithmParameters.getInstance(algo, + SunJCE.getInstance()); + params.init(new IvParameterSpec(iv)); } catch (NoSuchAlgorithmException nsae) { // should never happen throw new RuntimeException("Cannot find " + algo + " AlgorithmParameters implementation in SunJCE provider"); - } catch (NoSuchProviderException nspe) { - // should never happen - throw new RuntimeException("Cannot find SunJCE provider"); - } - try { - params.init(new IvParameterSpec(iv)); } catch (InvalidParameterSpecException ipse) { // should never happen throw new RuntimeException("IvParameterSpec not supported");
--- a/src/share/classes/com/sun/crypto/provider/DHParameterGenerator.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/DHParameterGenerator.java Wed Apr 17 02:53:02 2013 -0700 @@ -151,7 +151,8 @@ dhParamSpec = new DHParameterSpec(dsaParamSpec.getP(), dsaParamSpec.getG()); } - algParams = AlgorithmParameters.getInstance("DH", "SunJCE"); + algParams = AlgorithmParameters.getInstance("DH", + SunJCE.getInstance()); algParams.init(dhParamSpec); } catch (InvalidParameterSpecException e) { // this should never happen @@ -159,11 +160,7 @@ } catch (NoSuchAlgorithmException e) { // this should never happen, because we provide it throw new RuntimeException(e.getMessage()); - } catch (NoSuchProviderException e) { - // this should never happen, because we provide it - throw new RuntimeException(e.getMessage()); } - return algParams; } }
--- a/src/share/classes/com/sun/crypto/provider/KeyProtector.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/KeyProtector.java Wed Apr 17 02:53:02 2013 -0700 @@ -81,8 +81,6 @@ // key protector private char[] password; - private static final Provider PROV = Security.getProvider("SunJCE"); - KeyProtector(char[] password) { if (password == null) { throw new IllegalArgumentException("password can't be null"); @@ -119,7 +117,7 @@ // wrap encrypted private key in EncryptedPrivateKeyInfo // (as defined in PKCS#8) AlgorithmParameters pbeParams = - AlgorithmParameters.getInstance("PBE", PROV); + AlgorithmParameters.getInstance("PBE", SunJCE.getInstance()); pbeParams.init(pbeSpec); AlgorithmId encrAlg = new AlgorithmId @@ -299,7 +297,7 @@ PBEWithMD5AndTripleDESCipher cipherSpi; cipherSpi = new PBEWithMD5AndTripleDESCipher(); - cipher = new CipherForKeyProtector(cipherSpi, PROV, + cipher = new CipherForKeyProtector(cipherSpi, SunJCE.getInstance(), "PBEWithMD5AndTripleDES"); cipher.init(Cipher.ENCRYPT_MODE, sKey, pbeSpec); return new SealedObjectForKeyProtector(key, cipher); @@ -330,8 +328,9 @@ } PBEWithMD5AndTripleDESCipher cipherSpi; cipherSpi = new PBEWithMD5AndTripleDESCipher(); - Cipher cipher = new CipherForKeyProtector(cipherSpi, PROV, - "PBEWithMD5AndTripleDES"); + Cipher cipher = new CipherForKeyProtector(cipherSpi, + SunJCE.getInstance(), + "PBEWithMD5AndTripleDES"); cipher.init(Cipher.DECRYPT_MODE, skey, params); return (Key)soForKeyProtector.getObject(cipher); } catch (NoSuchAlgorithmException ex) {
--- a/src/share/classes/com/sun/crypto/provider/PBECipherCore.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/PBECipherCore.java Wed Apr 17 02:53:02 2013 -0700 @@ -169,16 +169,12 @@ PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); try { params = AlgorithmParameters.getInstance("PBEWithMD5And" + - (algo.equalsIgnoreCase("DES")? "DES":"TripleDES"), "SunJCE"); + (algo.equalsIgnoreCase("DES")? "DES":"TripleDES"), + SunJCE.getInstance()); + params.init(pbeSpec); } catch (NoSuchAlgorithmException nsae) { // should never happen throw new RuntimeException("SunJCE called, but not configured"); - } catch (NoSuchProviderException nspe) { - // should never happen - throw new RuntimeException("SunJCE called, but not configured"); - } - try { - params.init(pbeSpec); } catch (InvalidParameterSpecException ipse) { // should never happen throw new RuntimeException("PBEParameterSpec not supported");
--- a/src/share/classes/com/sun/crypto/provider/PBES1Core.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/PBES1Core.java Wed Apr 17 02:53:02 2013 -0700 @@ -169,16 +169,12 @@ PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); try { params = AlgorithmParameters.getInstance("PBEWithMD5And" + - (algo.equalsIgnoreCase("DES")? "DES":"TripleDES"), "SunJCE"); + (algo.equalsIgnoreCase("DES")? "DES":"TripleDES"), + SunJCE.getInstance()); + params.init(pbeSpec); } catch (NoSuchAlgorithmException nsae) { // should never happen throw new RuntimeException("SunJCE called, but not configured"); - } catch (NoSuchProviderException nspe) { - // should never happen - throw new RuntimeException("SunJCE called, but not configured"); - } - try { - params.init(pbeSpec); } catch (InvalidParameterSpecException ipse) { // should never happen throw new RuntimeException("PBEParameterSpec not supported");
--- a/src/share/classes/com/sun/crypto/provider/PBES2Core.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/PBES2Core.java Wed Apr 17 02:53:02 2013 -0700 @@ -25,11 +25,9 @@ package com.sun.crypto.provider; -import java.io.UnsupportedEncodingException; import java.security.*; import java.security.spec.*; import javax.crypto.*; -import javax.crypto.interfaces.*; import javax.crypto.spec.*; /** @@ -145,16 +143,12 @@ } PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount, ivSpec); try { - params = AlgorithmParameters.getInstance(pbeAlgo, "SunJCE"); + params = AlgorithmParameters.getInstance(pbeAlgo, + SunJCE.getInstance()); + params.init(pbeSpec); } catch (NoSuchAlgorithmException nsae) { // should never happen throw new RuntimeException("SunJCE called, but not configured"); - } catch (NoSuchProviderException nspe) { - // should never happen - throw new RuntimeException("SunJCE called, but not configured"); - } - try { - params.init(pbeSpec); } catch (InvalidParameterSpecException ipse) { // should never happen throw new RuntimeException("PBEParameterSpec not supported");
--- a/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ import java.security.KeyRep; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; import java.security.spec.InvalidKeySpecException; import javax.crypto.Mac; import javax.crypto.SecretKey; @@ -102,21 +101,16 @@ int keyLength = keySpec.getKeyLength(); if (keyLength == 0) { throw new InvalidKeySpecException("Key length not found"); - } else if (keyLength == 0) { + } else if (keyLength < 0) { throw new InvalidKeySpecException("Key length is negative"); } try { - this.prf = Mac.getInstance(prfAlgo, "SunJCE"); + this.prf = Mac.getInstance(prfAlgo, SunJCE.getInstance()); } catch (NoSuchAlgorithmException nsae) { // not gonna happen; re-throw just in case InvalidKeySpecException ike = new InvalidKeySpecException(); ike.initCause(nsae); throw ike; - } catch (NoSuchProviderException nspe) { - // Again, not gonna happen; re-throw just in case - InvalidKeySpecException ike = new InvalidKeySpecException(); - ike.initCause(nspe); - throw ike; } this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength); }
--- a/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java Wed Apr 17 02:53:02 2013 -0700 @@ -25,7 +25,6 @@ package com.sun.crypto.provider; -import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.*; import java.security.spec.*; @@ -232,14 +231,13 @@ } PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); try { - params = AlgorithmParameters.getInstance(pbeAlgo, "SunJCE"); - } catch (GeneralSecurityException gse) { + params = AlgorithmParameters.getInstance(pbeAlgo, + SunJCE.getInstance()); + params.init(pbeSpec); + } catch (NoSuchAlgorithmException nsae) { // should never happen throw new RuntimeException( "SunJCE provider is not configured properly"); - } - try { - params.init(pbeSpec); } catch (InvalidParameterSpecException ipse) { // should never happen throw new RuntimeException("PBEParameterSpec not supported");
--- a/src/share/classes/com/sun/crypto/provider/RSACipher.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/RSACipher.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,16 +178,14 @@ if (spec != null) { try { AlgorithmParameters params = - AlgorithmParameters.getInstance("OAEP", "SunJCE"); + AlgorithmParameters.getInstance("OAEP", + SunJCE.getInstance()); params.init(spec); return params; } catch (NoSuchAlgorithmException nsae) { // should never happen throw new RuntimeException("Cannot find OAEP " + " AlgorithmParameters implementation in SunJCE provider"); - } catch (NoSuchProviderException nspe) { - // should never happen - throw new RuntimeException("Cannot find SunJCE provider"); } catch (InvalidParameterSpecException ipse) { // should never happen throw new RuntimeException("OAEPParameterSpec not supported");
--- a/src/share/classes/com/sun/crypto/provider/SealedObjectForKeyProtector.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/SealedObjectForKeyProtector.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,14 +46,15 @@ AlgorithmParameters params = null; if (super.encodedParams != null) { try { - params = AlgorithmParameters.getInstance("PBE", "SunJCE"); + params = AlgorithmParameters.getInstance("PBE", + SunJCE.getInstance()); params.init(super.encodedParams); - } catch (NoSuchProviderException nspe) { - // eat. } catch (NoSuchAlgorithmException nsae) { - //eat. - } catch (IOException ioe) { - //eat. + throw new RuntimeException( + "SunJCE provider is not configured properly"); + } catch (IOException io) { + throw new RuntimeException("Parameter failure: "+ + io.getMessage()); } } return params;
--- a/src/share/classes/com/sun/crypto/provider/SunJCE.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/SunJCE.java Wed Apr 17 02:53:02 2013 -0700 @@ -91,6 +91,10 @@ /* Are we debugging? -- for developers */ static final boolean debug = false; + // Instance of this provider, so we don't have to call the provider list + // to find ourselves or run the risk of not being in the list. + private static volatile SunJCE instance = null; + // lazy initialize SecureRandom to avoid potential recursion if Sun // provider has not been installed yet private static class SecureRandomHolder { @@ -770,5 +774,17 @@ return null; } }); + + if (instance == null) { + instance = this; + } + } + + // Return the instance of this class or create one if needed. + static SunJCE getInstance() { + if (instance == null) { + return new SunJCE(); + } + return instance; } }
--- a/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -165,16 +165,18 @@ // partition keyblock into individual secrets int ofs = 0; - byte[] tmp = new byte[macLength]; + if (macLength != 0) { + byte[] tmp = new byte[macLength]; - // mac keys - System.arraycopy(keyBlock, ofs, tmp, 0, macLength); - ofs += macLength; - clientMacKey = new SecretKeySpec(tmp, "Mac"); + // mac keys + System.arraycopy(keyBlock, ofs, tmp, 0, macLength); + ofs += macLength; + clientMacKey = new SecretKeySpec(tmp, "Mac"); - System.arraycopy(keyBlock, ofs, tmp, 0, macLength); - ofs += macLength; - serverMacKey = new SecretKeySpec(tmp, "Mac"); + System.arraycopy(keyBlock, ofs, tmp, 0, macLength); + ofs += macLength; + serverMacKey = new SecretKeySpec(tmp, "Mac"); + } if (keyLength == 0) { // SSL_RSA_WITH_NULL_* ciphersuites return new TlsKeyMaterialSpec(clientMacKey, serverMacKey); @@ -198,7 +200,7 @@ // IV keys if needed. if (ivLength != 0) { - tmp = new byte[ivLength]; + byte[] tmp = new byte[ivLength]; System.arraycopy(keyBlock, ofs, tmp, 0, ivLength); ofs += ivLength; @@ -220,8 +222,8 @@ // TLS 1.0 byte[] seed = concat(clientRandom, serverRandom); - tmp = doTLS10PRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed, - expandedKeyLength, md5, sha); + byte[] tmp = doTLS10PRF(clientKeyBytes, + LABEL_CLIENT_WRITE_KEY, seed, expandedKeyLength, md5, sha); clientCipherKey = new SecretKeySpec(tmp, alg); tmp = doTLS10PRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed, @@ -239,7 +241,7 @@ } } else { // SSLv3 - tmp = new byte[expandedKeyLength]; + byte[] tmp = new byte[expandedKeyLength]; md5.update(clientKeyBytes); md5.update(clientRandom);
--- a/src/share/classes/java/security/SecureRandom.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/java/security/SecureRandom.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package java.security; import java.util.*; +import java.util.regex.*; import java.security.Provider.Service; @@ -79,7 +80,7 @@ * * Note: Depending on the implementation, the <code>generateSeed</code> and * <code>nextBytes</code> methods may block as entropy is being gathered, - * for example, if they need to read from /dev/random on various unix-like + * for example, if they need to read from /dev/random on various Unix-like * operating systems. * * @see java.security.SecureRandomSpi @@ -428,6 +429,7 @@ * * @see #getSeed */ + @Override public void setSeed(long seed) { /* * Ignore call from super constructor (as well as any other calls @@ -450,7 +452,7 @@ * * @param bytes the array to be filled in with random bytes. */ - + @Override synchronized public void nextBytes(byte[] bytes) { secureRandomSpi.engineNextBytes(bytes); } @@ -469,14 +471,16 @@ * @return an <code>int</code> containing the user-specified number * of pseudo-random bits (right justified, with leading zeros). */ + @Override final protected int next(int numBits) { int numBytes = (numBits+7)/8; byte b[] = new byte[numBytes]; int next = 0; nextBytes(b); - for (int i = 0; i < numBytes; i++) + for (int i = 0; i < numBytes; i++) { next = (next << 8) + (b[i] & 0xFF); + } return next >>> (numBytes*8 - numBits); } @@ -499,8 +503,9 @@ * @see #setSeed */ public static byte[] getSeed(int numBytes) { - if (seedGenerator == null) + if (seedGenerator == null) { seedGenerator = new SecureRandom(); + } return seedGenerator.generateSeed(numBytes); } @@ -549,6 +554,104 @@ return null; } + /* + * Lazily initialize since Pattern.compile() is heavy. + * Effective Java (2nd Edition), Item 71. + */ + private static final class StrongPatternHolder { + /* + * Entries are alg:prov separated by , + * Allow for prepended/appended whitespace between entries. + * + * Capture groups: + * 1 - alg + * 2 - :prov (optional) + * 3 - prov (optional) + * 4 - ,nextEntry (optional) + * 5 - nextEntry (optional) + */ + private static Pattern pattern = + Pattern.compile( + "\\s*([\\S&&[^:,]]*)(\\:([\\S&&[^,]]*))?\\s*(\\,(.*))?"); + } + + /** + * Returns a {@code SecureRandom} object that was selected by using + * the algorithms/providers specified in the {@code + * securerandom.strongAlgorithms} Security property. + * <p> + * Some situations require strong random values, such as when + * creating high-value/long-lived secrets like RSA public/private + * keys. To help guide applications in selecting a suitable strong + * {@code SecureRandom} implementation, Java distributions should + * include a list of known strong {@code SecureRandom} + * implementations in the {@code securerandom.strongAlgorithms} + * Security property. + * + * <pre> + * SecureRandom sr = SecureRandom.getStrongSecureRandom(); + * + * if (sr == null) { + * // Decide if this is a problem, and whether to recover. + * sr = new SecureRandom(); + * if (!goodEnough(sr)) { + * return; + * } + * } + * + * keyPairGenerator.initialize(2048, sr); + * </pre> + * + * @return a strong {@code SecureRandom} implementation as indicated + * by the {@code securerandom.strongAlgorithms} Security property, or + * null if none are available. + * + * @see Security#getProperty(String) + * + * @since 1.8 + */ + public static SecureRandom getStrongSecureRandom() { + + String property = AccessController.doPrivileged( + new PrivilegedAction<String>() { + @Override + public String run() { + return Security.getProperty( + "securerandom.strongAlgorithms"); + } + }); + + if ((property == null) || (property.length() == 0)) { + return null; + } + + String remainder = property; + while (remainder != null) { + Matcher m; + if ((m = StrongPatternHolder.pattern.matcher( + remainder)).matches()) { + + String alg = m.group(1); + String prov = m.group(3); + + try { + if (prov == null) { + return SecureRandom.getInstance(alg); + } else { + return SecureRandom.getInstance(alg, prov); + } + } catch (NoSuchAlgorithmException | + NoSuchProviderException e) { + } + remainder = m.group(5); + } else { + remainder = null; + } + } + + return null; + } + // Declare serialVersionUID to be compatible with JDK1.1 static final long serialVersionUID = 4940670005562187L;
--- a/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -212,12 +212,6 @@ * generated. */ public int getIvLength() { - // TLS v1.1 or later uses an explicit IV to protect against - // the CBC attacks. - if (majorVersion >= 0x03 && minorVersion >= 0x02) { - return 0; - } - return ivLength; }
--- a/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,9 +58,8 @@ * <code>new TlsKeymaterialSpec(clientMacKey, serverMacKey, * null, null, null, null)</code>. * - * @param clientMacKey the client MAC key - * @param serverMacKey the server MAC key - * @throws NullPointerException if clientMacKey or serverMacKey is null + * @param clientMacKey the client MAC key (or null) + * @param serverMacKey the server MAC key (or null) */ public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey) { this(clientMacKey, serverMacKey, null, null, null, null); @@ -73,11 +72,10 @@ * <code>new TlsKeymaterialSpec(clientMacKey, serverMacKey, * clientCipherKey, serverCipherKey, null, null)</code>. * - * @param clientMacKey the client MAC key - * @param serverMacKey the server MAC key + * @param clientMacKey the client MAC key (or null) + * @param serverMacKey the server MAC key (or null) * @param clientCipherKey the client cipher key (or null) * @param serverCipherKey the server cipher key (or null) - * @throws NullPointerException if clientMacKey or serverMacKey is null */ public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey, SecretKey clientCipherKey, SecretKey serverCipherKey) { @@ -90,21 +88,17 @@ * keys, client and server cipher keys, and client and server * initialization vectors. * - * @param clientMacKey the client MAC key - * @param serverMacKey the server MAC key + * @param clientMacKey the client MAC key (or null) + * @param serverMacKey the server MAC key (or null) * @param clientCipherKey the client cipher key (or null) * @param clientIv the client initialization vector (or null) * @param serverCipherKey the server cipher key (or null) * @param serverIv the server initialization vector (or null) - * - * @throws NullPointerException if clientMacKey or serverMacKey is null */ public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey, SecretKey clientCipherKey, IvParameterSpec clientIv, SecretKey serverCipherKey, IvParameterSpec serverIv) { - if ((clientMacKey == null) || (serverMacKey == null)) { - throw new NullPointerException("MAC keys must not be null"); - } + this.clientMacKey = clientMacKey; this.serverMacKey = serverMacKey; this.clientCipherKey = clientCipherKey; @@ -143,7 +137,7 @@ /** * Returns the client MAC key. * - * @return the client MAC key. + * @return the client MAC key (or null). */ public SecretKey getClientMacKey() { return clientMacKey; @@ -152,7 +146,7 @@ /** * Return the server MAC key. * - * @return the server MAC key. + * @return the server MAC key (or null). */ public SecretKey getServerMacKey() { return serverMacKey;
--- a/src/share/classes/sun/security/pkcs11/P11SecureRandom.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/pkcs11/P11SecureRandom.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,9 @@ package sun.security.pkcs11; -import java.util.*; import java.io.*; import java.security.*; - import sun.security.pkcs11.wrapper.*; -import sun.security.pkcs11.wrapper.PKCS11Constants.*; /** * SecureRandom implementation class. Some tokens support only @@ -88,6 +85,7 @@ } // see JCA spec + @Override protected synchronized void engineSetSeed(byte[] seed) { if (seed == null) { throw new NullPointerException("seed must not be null"); @@ -119,6 +117,7 @@ } // see JCA spec + @Override protected void engineNextBytes(byte[] bytes) { if ((bytes == null) || (bytes.length == 0)) { return; @@ -149,6 +148,7 @@ } // see JCA spec + @Override protected byte[] engineGenerateSeed(int numBytes) { byte[] b = new byte[numBytes]; engineNextBytes(b);
--- a/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,10 +168,22 @@ // Note that the MAC keys do not inherit all attributes from the // template, but they do inherit the sensitive/extractable/token // flags, which is all P11Key cares about. - SecretKey clientMacKey = P11Key.secretKey + SecretKey clientMacKey, serverMacKey; + + // The MAC size may be zero for GCM mode. + // + // PKCS11 does not support GCM mode as the author made the comment, + // so the macBits is unlikely to be zero. It's only a place holder. + if (macBits != 0) { + clientMacKey = P11Key.secretKey (session, out.hClientMacSecret, "MAC", macBits, attributes); - SecretKey serverMacKey = P11Key.secretKey + serverMacKey = P11Key.secretKey (session, out.hServerMacSecret, "MAC", macBits, attributes); + } else { + clientMacKey = null; + serverMacKey = null; + } + SecretKey clientCipherKey, serverCipherKey; if (keyBits != 0) { clientCipherKey = P11Key.secretKey(session, out.hClientKey,
--- a/src/share/classes/sun/security/provider/SecureRandom.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/provider/SecureRandom.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,7 +79,7 @@ } /** - * This constructor is used to instatiate the private seeder object + * This constructor is used to instantiate the private seeder object * with a given seed from the SeedGenerator. * * @param seed the seed. @@ -94,7 +94,7 @@ */ private void init(byte[] seed) { try { - digest = MessageDigest.getInstance ("SHA"); + digest = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException e) { throw new InternalError("internal error: SHA-1 not available.", e); } @@ -120,7 +120,10 @@ * * @return the seed bytes. */ + @Override public byte[] engineGenerateSeed(int numBytes) { + // Neither of the SeedGenerator implementations require + // locking, so no sync needed here. byte[] b = new byte[numBytes]; SeedGenerator.generateSeed(b); return b; @@ -133,19 +136,21 @@ * * @param seed the seed. */ + @Override synchronized public void engineSetSeed(byte[] seed) { if (state != null) { digest.update(state); - for (int i = 0; i < state.length; i++) + for (int i = 0; i < state.length; i++) { state[i] = 0; + } } state = digest.digest(seed); } private static void updateState(byte[] state, byte[] output) { int last = 1; - int v = 0; - byte t = 0; + int v; + byte t; boolean zf = false; // state(n + 1) = (state(n) + output(n) + 1) % 2^160; @@ -162,8 +167,9 @@ } // Make sure at least one bit changes! - if (!zf) + if (!zf) { state[0]++; + } } /** @@ -193,6 +199,7 @@ * * @param bytes the array to be filled in with random bytes. */ + @Override public synchronized void engineNextBytes(byte[] result) { int index = 0; int todo; @@ -258,7 +265,7 @@ s.defaultReadObject (); try { - digest = MessageDigest.getInstance ("SHA"); + digest = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException e) { throw new InternalError("internal error: SHA-1 not available.", e); }
--- a/src/share/classes/sun/security/provider/SeedGenerator.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/provider/SeedGenerator.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,11 +26,13 @@ package sun.security.provider; /** - * <P> This class generates seeds for the cryptographically strong random - * number generator. - * <P> The seed is produced using one of two techniques, via a computation + * This class generates seeds for the SHA1PRNG cryptographically strong + * random number generator. + * <p> + * The seed is produced using one of two techniques, via a computation * of current system activity or from an entropy gathering device. - * <p> In the default technique the seed is produced by counting the + * <p> + * In the default technique the seed is produced by counting the * number of times the VM manages to loop in a given period. This number * roughly reflects the machine load at that point in time. * The samples are translated using a permutation (s-box) @@ -41,23 +43,24 @@ * We also create a number of sleeper threads which add entropy * to the system by keeping the scheduler busy. * Twenty such samples should give us roughly 160 bits of randomness. - * <P> These values are gathered in the background by a daemon thread + * <p> + * These values are gathered in the background by a daemon thread * thus allowing the system to continue performing it's different * activites, which in turn add entropy to the random seed. - * <p> The class also gathers miscellaneous system information, some + * <p> + * The class also gathers miscellaneous system information, some * machine dependent, some not. This information is then hashed together * with the 20 seed bytes. - * <P> The alternative to the above approach is to acquire seed material + * <p> + * The alternative to the above approach is to acquire seed material * from an entropy gathering device, such as /dev/random. This can be - * accomplished by setting the value of the "securerandom.source" - * security property (in the Java security properties file) to a URL - * specifying the location of the entropy gathering device. + * accomplished by setting the value of the {@code securerandom.source} + * Security property to a URL specifying the location of the entropy + * gathering device, or by setting the {@code java.security.egd} System + * property. + * <p> * In the event the specified URL cannot be accessed the default - * mechanism is used. - * The Java security properties file is located in the file named - * <JAVA_HOME>/lib/security/java.security. - * <JAVA_HOME> refers to the value of the java.home system property, - * and specifies the directory where the JRE is installed. + * threading mechanism is used. * * @author Joshua Bloch * @author Gadi Guy @@ -81,27 +84,28 @@ private static final Debug debug = Debug.getInstance("provider"); - final static String URL_DEV_RANDOM = SunEntries.URL_DEV_RANDOM; - final static String URL_DEV_URANDOM = SunEntries.URL_DEV_URANDOM; - // Static initializer to hook in selected or best performing generator static { String egdSource = SunEntries.getSeedSource(); - // Try the URL specifying the source - // e.g. file:/dev/random - // - // The URL file:/dev/random or file:/dev/urandom is used to indicate - // the SeedGenerator using OS support, if available. - // On Windows, the causes MS CryptoAPI to be used. - // On Solaris and Linux, this is the identical to using - // URLSeedGenerator to read from /dev/random - - if (egdSource.equals(URL_DEV_RANDOM) || egdSource.equals(URL_DEV_URANDOM)) { + /* + * Try the URL specifying the source (e.g. file:/dev/random) + * + * The URLs "file:/dev/random" or "file:/dev/urandom" are used to + * indicate the SeedGenerator should use OS support, if available. + * + * On Windows, this causes the MS CryptoAPI seeder to be used. + * + * On Solaris/Linux/MacOS, this is identical to using + * URLSeedGenerator to read from /dev/[u]random + */ + if (egdSource.equals(SunEntries.URL_DEV_RANDOM) || + egdSource.equals(SunEntries.URL_DEV_URANDOM)) { try { - instance = new NativeSeedGenerator(); + instance = new NativeSeedGenerator(egdSource); if (debug != null) { - debug.println("Using operating system seed generator"); + debug.println( + "Using operating system seed generator" + egdSource); } } catch (IOException e) { if (debug != null) { @@ -117,9 +121,10 @@ + egdSource); } } catch (IOException e) { - if (debug != null) + if (debug != null) { debug.println("Failed to create seed generator with " + egdSource + ": " + e.toString()); + } } } @@ -161,8 +166,8 @@ java.security.AccessController.doPrivileged (new java.security.PrivilegedAction<Void>() { + @Override public Void run() { - try { // System properties can change from machine to machine String s; @@ -180,7 +185,9 @@ // The temporary dir File f = new File(p.getProperty("java.io.tmpdir")); int count = 0; - try (DirectoryStream<Path> stream = Files.newDirectoryStream(f.toPath())) { + try ( + DirectoryStream<Path> stream = + Files.newDirectoryStream(f.toPath())) { // We use a Random object to choose what file names // should be used. Otherwise on a machine with too // many files, the same first 1024 files always get @@ -189,7 +196,8 @@ Random r = new Random(); for (Path entry: stream) { if (count < 512 || r.nextBoolean()) { - md.update(entry.getFileName().toString().getBytes()); + md.update(entry.getFileName() + .toString().getBytes()); } if (count++ > 1024) { break; @@ -236,7 +244,8 @@ */ - private static class ThreadedSeedGenerator extends SeedGenerator implements Runnable { + private static class ThreadedSeedGenerator extends SeedGenerator + implements Runnable { // Queue is used to collect seed bytes private byte[] pool; private int start, end, count; @@ -245,11 +254,10 @@ ThreadGroup seedGroup; /** - * The constructor is only called once to construct the one - * instance we actually use. It instantiates the message digest - * and starts the thread going. - */ - + * The constructor is only called once to construct the one + * instance we actually use. It instantiates the message digest + * and starts the thread going. + */ ThreadedSeedGenerator() { pool = new byte[20]; start = end = 0; @@ -266,16 +274,18 @@ final ThreadGroup[] finalsg = new ThreadGroup[1]; Thread t = java.security.AccessController.doPrivileged (new java.security.PrivilegedAction<Thread>() { + @Override public Thread run() { ThreadGroup parent, group = Thread.currentThread().getThreadGroup(); - while ((parent = group.getParent()) != null) + while ((parent = group.getParent()) != null) { group = parent; + } finalsg[0] = new ThreadGroup (group, "SeedGenerator ThreadGroup"); Thread newT = new Thread(finalsg[0], - ThreadedSeedGenerator.this, - "SeedGenerator Thread"); + ThreadedSeedGenerator.this, + "SeedGenerator Thread"); newT.setPriority(Thread.MIN_PRIORITY); newT.setDaemon(true); return newT; @@ -289,21 +299,23 @@ * This method does the actual work. It collects random bytes and * pushes them into the queue. */ + @Override final public void run() { try { while (true) { // Queue full? Wait till there's room. synchronized(this) { - while (count >= pool.length) + while (count >= pool.length) { wait(); + } } int counter, quanta; byte v = 0; // Spin count must not be under 64000 - for (counter = quanta = 0; (counter < 64000) && (quanta < 6); - quanta++) { + for (counter = quanta = 0; + (counter < 64000) && (quanta < 6); quanta++) { // Start some noisy threads try { @@ -313,14 +325,12 @@ t.start(); } catch (Exception e) { throw new InternalError("internal error: " + - "SeedGenerator thread creation error." - , e); + "SeedGenerator thread creation error.", e); } // We wait 250milli quanta, so the minimum wait time // cannot be under 250milli. int latch = 0; - latch = 0; long l = System.currentTimeMillis() + 250; while (System.currentTimeMillis() < l) { synchronized(this){}; @@ -339,16 +349,16 @@ pool[end] = v; end++; count++; - if (end >= pool.length) + if (end >= pool.length) { end = 0; + } notifyAll(); } } } catch (Exception e) { throw new InternalError("internal error: " + - "SeedGenerator thread generated an exception." - , e); + "SeedGenerator thread generated an exception.", e); } } @@ -360,19 +370,20 @@ } byte getSeedByte() { - byte b = 0; + byte b; try { // Wait for it... synchronized(this) { - while (count <= 0) + while (count <= 0) { wait(); + } } } catch (Exception e) { - if (count <= 0) + if (count <= 0) { throw new InternalError("internal error: " + - "SeedGenerator thread generated an exception." - ,e); + "SeedGenerator thread generated an exception.", e); + } } synchronized(this) { @@ -381,8 +392,9 @@ pool[start] = 0; start++; count--; - if (start == pool.length) + if (start == pool.length) { start = 0; + } // Notify the daemon thread, just in case it is // waiting for us to make room in the queue. @@ -430,12 +442,13 @@ * thus adding entropy to the system load. * At least one instance of this class is generated for every seed byte. */ - private static class BogusThread implements Runnable { + @Override final public void run() { try { - for(int i = 0; i < 5; i++) + for (int i = 0; i < 5; i++) { Thread.sleep(50); + } // System.gc(); } catch (Exception e) { } @@ -446,7 +459,7 @@ static class URLSeedGenerator extends SeedGenerator { private String deviceName; - private InputStream devRandom; + private InputStream seedStream; /** * The constructor is only called once to construct the one @@ -462,15 +475,12 @@ init(); } - URLSeedGenerator() throws IOException { - this(SeedGenerator.URL_DEV_RANDOM); - } - private void init() throws IOException { final URL device = new URL(deviceName); try { - devRandom = java.security.AccessController.doPrivileged + seedStream = java.security.AccessController.doPrivileged (new java.security.PrivilegedExceptionAction<InputStream>() { + @Override public InputStream run() throws IOException { /* * return a FileInputStream for file URLs and @@ -481,7 +491,8 @@ * can be slow to replenish. */ if (device.getProtocol().equalsIgnoreCase("file")) { - File deviceFile = getDeviceFile(device); + File deviceFile = + SunEntries.getDeviceFile(device); return new FileInputStream(deviceFile); } else { return device.openStream(); @@ -489,36 +500,8 @@ } }); } catch (Exception e) { - throw new IOException("Failed to open " + deviceName, e.getCause()); - } - } - - /* - * Use a URI to access this File. Previous code used a URL - * which is less strict on syntax. If we encounter a - * URISyntaxException we make best efforts for backwards - * compatibility. e.g. space character in deviceName string. - * - * Method called within PrivilegedExceptionAction block. - */ - private File getDeviceFile(URL device) throws IOException { - try { - URI deviceURI = device.toURI(); - if(deviceURI.isOpaque()) { - // File constructor does not accept opaque URI - URI localDir = new File(System.getProperty("user.dir")).toURI(); - String uriPath = localDir.toString() + - deviceURI.toString().substring(5); - return new File(URI.create(uriPath)); - } else { - return new File(deviceURI); - } - } catch (URISyntaxException use) { - /* - * Make best effort to access this File. - * We can try using the URL path. - */ - return new File(device.getPath()); + throw new IOException( + "Failed to open " + deviceName, e.getCause()); } } @@ -528,19 +511,19 @@ int read = 0; try { while (read < len) { - int count = devRandom.read(result, read, len - read); + int count = seedStream.read(result, read, len - read); // /dev/random blocks - should never have EOF - if (count < 0) - throw new InternalError("URLSeedGenerator " + deviceName + - " reached end of file"); + if (count < 0) { + throw new InternalError( + "URLSeedGenerator " + deviceName + + " reached end of file"); + } read += count; } } catch (IOException ioe) { throw new InternalError("URLSeedGenerator " + deviceName + - " generated exception: " + - ioe.getMessage(), ioe); + " generated exception: " + ioe.getMessage(), ioe); } } - } }
--- a/src/share/classes/sun/security/provider/SunEntries.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/provider/SunEntries.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package sun.security.provider; +import java.io.*; +import java.net.*; import java.util.Map; import java.security.*; @@ -92,26 +94,41 @@ // if user selected /dev/urandom, we put it before SHA1PRNG, // otherwise after it boolean nativeAvailable = NativePRNG.isAvailable(); - boolean useUrandom = seedSource.equals(URL_DEV_URANDOM); - if (nativeAvailable && useUrandom) { + boolean useNativePRNG = seedSource.equals(URL_DEV_URANDOM) || + seedSource.equals(URL_DEV_RANDOM); + + if (nativeAvailable && useNativePRNG) { map.put("SecureRandom.NativePRNG", "sun.security.provider.NativePRNG"); } map.put("SecureRandom.SHA1PRNG", "sun.security.provider.SecureRandom"); - if (nativeAvailable && !useUrandom) { + if (nativeAvailable && !useNativePRNG) { map.put("SecureRandom.NativePRNG", "sun.security.provider.NativePRNG"); } + if (NativePRNG.Blocking.isAvailable()) { + map.put("SecureRandom.NativePRNGBlocking", + "sun.security.provider.NativePRNG$Blocking"); + } + + if (NativePRNG.NonBlocking.isAvailable()) { + map.put("SecureRandom.NativePRNGNonBlocking", + "sun.security.provider.NativePRNG$NonBlocking"); + } + /* * Signature engines */ - map.put("Signature.SHA1withDSA", "sun.security.provider.DSA$SHA1withDSA"); + map.put("Signature.SHA1withDSA", + "sun.security.provider.DSA$SHA1withDSA"); map.put("Signature.NONEwithDSA", "sun.security.provider.DSA$RawDSA"); map.put("Alg.Alias.Signature.RawDSA", "NONEwithDSA"); - map.put("Signature.SHA224withDSA", "sun.security.provider.DSA$SHA224withDSA"); - map.put("Signature.SHA256withDSA", "sun.security.provider.DSA$SHA256withDSA"); + map.put("Signature.SHA224withDSA", + "sun.security.provider.DSA$SHA224withDSA"); + map.put("Signature.SHA256withDSA", + "sun.security.provider.DSA$SHA256withDSA"); String dsaKeyClasses = "java.security.interfaces.DSAPublicKey" + "|java.security.interfaces.DSAPrivateKey"; @@ -128,13 +145,15 @@ map.put("Alg.Alias.Signature.SHAwithDSA", "SHA1withDSA"); map.put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA"); map.put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", - "SHA1withDSA"); + "SHA1withDSA"); map.put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA"); map.put("Alg.Alias.Signature.1.3.14.3.2.13", "SHA1withDSA"); map.put("Alg.Alias.Signature.1.3.14.3.2.27", "SHA1withDSA"); - map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.1", "SHA224withDSA"); + map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.1", + "SHA224withDSA"); map.put("Alg.Alias.Signature.2.16.840.1.101.3.4.3.1", "SHA224withDSA"); - map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.2", "SHA256withDSA"); + map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.2", + "SHA256withDSA"); map.put("Alg.Alias.Signature.2.16.840.1.101.3.4.3.2", "SHA256withDSA"); /* @@ -160,17 +179,21 @@ map.put("MessageDigest.SHA-224", "sun.security.provider.SHA2$SHA224"); map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.4", "SHA-224"); - map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.4", "SHA-224"); + map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.4", + "SHA-224"); map.put("MessageDigest.SHA-256", "sun.security.provider.SHA2$SHA256"); map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256"); - map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.1", "SHA-256"); + map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.1", + "SHA-256"); map.put("MessageDigest.SHA-384", "sun.security.provider.SHA5$SHA384"); map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.2", "SHA-384"); - map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.2", "SHA-384"); + map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.2", + "SHA-384"); map.put("MessageDigest.SHA-512", "sun.security.provider.SHA5$SHA512"); map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512"); - map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3", "SHA-512"); + map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3", + "SHA-512"); /* * Algorithm Parameter Generator engines @@ -296,6 +319,7 @@ seedSource = AccessController.doPrivileged( new PrivilegedAction<String>() { + @Override public String run() { String egdSource = System.getProperty(PROP_EGD, ""); if (egdSource.length() != 0) { @@ -314,4 +338,36 @@ return seedSource; } + /* + * Use a URI to access this File. Previous code used a URL + * which is less strict on syntax. If we encounter a + * URISyntaxException we make best efforts for backwards + * compatibility. e.g. space character in deviceName string. + * + * Method called within PrivilegedExceptionAction block. + * + * Moved from SeedGenerator to avoid initialization problems with + * signed providers. + */ + static File getDeviceFile(URL device) throws IOException { + try { + URI deviceURI = device.toURI(); + if(deviceURI.isOpaque()) { + // File constructor does not accept opaque URI + URI localDir = new File( + System.getProperty("user.dir")).toURI(); + String uriPath = localDir.toString() + + deviceURI.toString().substring(5); + return new File(URI.create(uriPath)); + } else { + return new File(deviceURI); + } + } catch (URISyntaxException use) { + /* + * Make best effort to access this File. + * We can try using the URL path. + */ + return new File(device.getPath()); + } + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/security/ssl/Authenticator.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.util.Arrays; + +/** + * This class represents an SSL/TLS message authentication token, + * which encapsulates a sequence number and ensures that attempts to + * delete or reorder messages can be detected. + * + * Each SSL/TLS connection state contains a sequence number, which + * is maintained separately for read and write states. The sequence + * number MUST be set to zero whenever a connection state is made the + * active state. Sequence numbers are of type uint64 and may not + * exceed 2^64-1. Sequence numbers do not wrap. If a SSL/TLS + * implementation would need to wrap a sequence number, it must + * renegotiate instead. A sequence number is incremented after each + * record: specifically, the first record transmitted under a + * particular connection state MUST use sequence number 0. + */ +class Authenticator { + + // byte array containing the additional authentication information for + // each record + private final byte[] block; + + // the block size of SSL v3.0: + // sequence number + record type + + record length + private static final int BLOCK_SIZE_SSL = 8 + 1 + 2; + + // the block size of TLS v1.0 and later: + // sequence number + record type + protocol version + record length + private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2; + + /** + * Default construct, no message authentication token is initialized. + * + * Note that this construct can only be called for null MAC + */ + Authenticator() { + block = new byte[0]; + } + + /** + * Constructs the message authentication token for the specified + * SSL/TLS protocol. + */ + Authenticator(ProtocolVersion protocolVersion) { + if (protocolVersion.v >= ProtocolVersion.TLS10.v) { + block = new byte[BLOCK_SIZE_TLS]; + block[9] = protocolVersion.major; + block[10] = protocolVersion.minor; + } else { + block = new byte[BLOCK_SIZE_SSL]; + } + } + + /** + * Checks whether the sequence number is close to wrap. + * + * Sequence numbers are of type uint64 and may not exceed 2^64-1. + * Sequence numbers do not wrap. When the sequence number is near + * to wrap, we need to close the connection immediately. + * + * @return true if the sequence number is close to wrap + */ + final boolean seqNumOverflow() { + /* + * Conservatively, we don't allow more records to be generated + * when there are only 2^8 sequence numbers left. + */ + return (block.length != 0 && + block[0] == (byte)0xFF && block[1] == (byte)0xFF && + block[2] == (byte)0xFF && block[3] == (byte)0xFF && + block[4] == (byte)0xFF && block[5] == (byte)0xFF && + block[6] == (byte)0xFF); + } + + /** + * Checks whether the sequence number close to renew. + * + * Sequence numbers are of type uint64 and may not exceed 2^64-1. + * Sequence numbers do not wrap. If a TLS + * implementation would need to wrap a sequence number, it must + * renegotiate instead. + * + * @return true if the sequence number is huge enough to renew + */ + final boolean seqNumIsHuge() { + /* + * Conservatively, we should ask for renegotiation when there are + * only 2^48 sequence numbers left. + */ + return (block.length != 0 && + block[0] == (byte)0xFF && block[1] == (byte)0xFF); + } + + /** + * Gets the current sequence number. + * + * @return the byte array of the current sequence number + */ + final byte[] sequenceNumber() { + return Arrays.copyOf(block, 8); + } + + /** + * Acquires the current message authentication information with the + * specified record type and fragment length, and then increases the + * sequence number. + * + * @param type the record type + * @param length the fragment of the record + * @return the byte array of the current message authentication information + */ + final byte[] acquireAuthenticationBytes(byte type, int length) { + byte[] copy = block.clone(); + + if (block.length != 0) { + copy[8] = type; + copy[copy.length - 2] = (byte)(length >> 8); + copy[copy.length - 1] = (byte)(length); + + /* + * Increase the sequence number in the block array + * it is a 64-bit number stored in big-endian format + */ + int k = 7; + while ((k >= 0) && (++block[k] == 0)) { + k--; + } + } + + return copy; + } + +}
--- a/src/share/classes/sun/security/ssl/CipherBox.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/CipherBox.java Wed Apr 17 02:53:02 2013 -0700 @@ -29,15 +29,18 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Hashtable; +import java.util.Arrays; import java.security.*; import javax.crypto.*; import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.GCMParameterSpec; import java.nio.*; import sun.security.ssl.CipherSuite.*; import static sun.security.ssl.CipherSuite.*; +import static sun.security.ssl.CipherSuite.CipherType.*; import sun.misc.HexDumpEncoder; @@ -102,19 +105,40 @@ private final Cipher cipher; /** - * Cipher blocksize, 0 for stream ciphers - */ - private int blockSize; - - /** * secure random */ private SecureRandom random; /** - * Is the cipher of CBC mode? + * fixed IV, the implicit nonce of AEAD cipher suite, only apply to + * AEAD cipher suites + */ + private final byte[] fixedIv; + + /** + * the key, reserved only for AEAD cipher initialization + */ + private final Key key; + + /** + * the operation mode, reserved for AEAD cipher initialization */ - private final boolean isCBCMode; + private final int mode; + + /** + * the authentication tag size, only apply to AEAD cipher suites + */ + private final int tagSize; + + /** + * the record IV length, only apply to AEAD cipher suites + */ + private final int recordIvSize; + + /** + * cipher type + */ + private final CipherType cipherType; /** * Fixed masks of various block size, as the initial decryption IVs @@ -132,7 +156,13 @@ private CipherBox() { this.protocolVersion = ProtocolVersion.DEFAULT; this.cipher = null; - this.isCBCMode = false; + this.cipherType = STREAM_CIPHER; + this.fixedIv = new byte[0]; + this.key = null; + this.mode = Cipher.ENCRYPT_MODE; // choose at random + this.random = null; + this.tagSize = 0; + this.recordIvSize = 0; } /** @@ -147,13 +177,13 @@ try { this.protocolVersion = protocolVersion; this.cipher = JsseJce.getCipher(bulkCipher.transformation); - int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; + this.mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; if (random == null) { random = JsseJce.getSecureRandom(); } this.random = random; - this.isCBCMode = bulkCipher.isCBCMode; + this.cipherType = bulkCipher.cipherType; /* * RFC 4346 recommends two algorithms used to generated the @@ -171,14 +201,40 @@ iv = getFixedMask(bulkCipher.ivSize); } - cipher.init(mode, key, iv, random); + if (cipherType == AEAD_CIPHER) { + // AEAD must completely initialize the cipher for each packet, + // and so we save initialization parameters for packet + // processing time. + + // Set the tag size for AEAD cipher + tagSize = bulkCipher.tagSize; + + // Reserve the key for AEAD cipher initialization + this.key = key; + + fixedIv = iv.getIV(); + if (fixedIv == null || + fixedIv.length != bulkCipher.fixedIvSize) { + throw new RuntimeException("Improper fixed IV for AEAD"); + } - // Do not call getBlockSize until after init() - // otherwise we would disrupt JCE delayed provider selection - blockSize = cipher.getBlockSize(); - // some providers implement getBlockSize() incorrectly - if (blockSize == 1) { - blockSize = 0; + // Set the record IV length for AEAD cipher + recordIvSize = bulkCipher.ivSize - bulkCipher.fixedIvSize; + + // DON'T initialize the cipher for AEAD! + } else { + // CBC only requires one initialization during its lifetime + // (future packets/IVs set the proper CBC state), so we can + // initialize now. + + // Zeroize the variables that only apply to AEAD cipher + this.tagSize = 0; + this.fixedIv = new byte[0]; + this.recordIvSize = 0; + this.key = null; + + // Initialize the cipher + cipher.init(mode, key, iv, random); } } catch (NoSuchAlgorithmException e) { throw e; @@ -235,26 +291,11 @@ } try { - if (blockSize != 0) { - // TLSv1.1 needs a IV block - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - // generate a random number - byte[] prefix = new byte[blockSize]; - random.nextBytes(prefix); - - // move forward the plaintext - System.arraycopy(buf, offset, - buf, offset + prefix.length, len); - - // prefix the plaintext - System.arraycopy(prefix, 0, - buf, offset, prefix.length); - - len += prefix.length; - } - + int blockSize = cipher.getBlockSize(); + if (cipherType == BLOCK_CIPHER) { len = addPadding(buf, offset, len, blockSize); } + if (debug != null && Debug.isOn("plaintext")) { try { HexDumpEncoder hd = new HexDumpEncoder(); @@ -267,14 +308,28 @@ System.out); } catch (IOException e) { } } - int newLen = cipher.update(buf, offset, len, buf, offset); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); + + + if (cipherType == AEAD_CIPHER) { + try { + return cipher.doFinal(buf, offset, len, buf, offset); + } catch (IllegalBlockSizeException | BadPaddingException ibe) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode in JCE provider " + + cipher.getProvider().getName(), ibe); + } + } else { + int newLen = cipher.update(buf, offset, len, buf, offset); + if (newLen != len) { + // catch BouncyCastle buffering error + throw new RuntimeException("Cipher buffering error " + + "in JCE provider " + cipher.getProvider().getName()); + } + return newLen; } - return newLen; } catch (ShortBufferException e) { + // unlikely to happen, we should have enough buffer space here throw new ArrayIndexOutOfBoundsException(e.toString()); } } @@ -288,7 +343,7 @@ * set to last position padded/encrypted. The limit may have changed * because of the added padding bytes. */ - int encrypt(ByteBuffer bb) { + int encrypt(ByteBuffer bb, int outLimit) { int len = bb.remaining(); @@ -297,66 +352,71 @@ return len; } - try { - int pos = bb.position(); + int pos = bb.position(); - if (blockSize != 0) { - // TLSv1.1 needs a IV block - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - // generate a random number - byte[] prefix = new byte[blockSize]; - random.nextBytes(prefix); + int blockSize = cipher.getBlockSize(); + if (cipherType == BLOCK_CIPHER) { + // addPadding adjusts pos/limit + len = addPadding(bb, blockSize); + bb.position(pos); + } - // move forward the plaintext - byte[] buf = null; - int limit = bb.limit(); - if (bb.hasArray()) { - int arrayOffset = bb.arrayOffset(); - buf = bb.array(); - System.arraycopy(buf, arrayOffset + pos, - buf, arrayOffset + pos + prefix.length, - limit - pos); - bb.limit(limit + prefix.length); - } else { - buf = new byte[limit - pos]; - bb.get(buf, 0, limit - pos); - bb.position(pos + prefix.length); - bb.limit(limit + prefix.length); - bb.put(buf); - } - bb.position(pos); + if (debug != null && Debug.isOn("plaintext")) { + try { + HexDumpEncoder hd = new HexDumpEncoder(); + + System.out.println( + "Padded plaintext before ENCRYPTION: len = " + + len); + hd.encodeBuffer(bb.duplicate(), System.out); + + } catch (IOException e) { } + } - // prefix the plaintext - bb.put(prefix); - bb.position(pos); + /* + * Encrypt "in-place". This does not add its own padding. + */ + ByteBuffer dup = bb.duplicate(); + if (cipherType == AEAD_CIPHER) { + try { + int outputSize = cipher.getOutputSize(dup.remaining()); + if (outputSize > bb.remaining()) { + // need to expand the limit of the output buffer for + // the authentication tag. + // + // DON'T worry about the buffer's capacity, we have + // reserved space for the authentication tag. + if (outLimit < pos + outputSize) { + // unlikely to happen + throw new ShortBufferException( + "need more space in output buffer"); + } + bb.limit(pos + outputSize); } - - // addPadding adjusts pos/limit - len = addPadding(bb, blockSize); - bb.position(pos); + int newLen = cipher.doFinal(dup, bb); + if (newLen != outputSize) { + throw new RuntimeException( + "Cipher buffering error in JCE provider " + + cipher.getProvider().getName()); + } + return newLen; + } catch (IllegalBlockSizeException | + BadPaddingException | ShortBufferException ibse) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode in JCE provider " + + cipher.getProvider().getName(), ibse); } - if (debug != null && Debug.isOn("plaintext")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - - System.out.println( - "Padded plaintext before ENCRYPTION: len = " - + len); - hd.encodeBuffer(bb, System.out); - - } catch (IOException e) { } - /* - * reset back to beginning - */ - bb.position(pos); + } else { + int newLen; + try { + newLen = cipher.update(dup, bb); + } catch (ShortBufferException sbe) { + // unlikely to happen + throw new RuntimeException("Cipher buffering error " + + "in JCE provider " + cipher.getProvider().getName()); } - /* - * Encrypt "in-place". This does not add its own padding. - */ - ByteBuffer dup = bb.duplicate(); - int newLen = cipher.update(dup, bb); - if (bb.position() != dup.position()) { throw new RuntimeException("bytebuffer padding error"); } @@ -367,10 +427,6 @@ "in JCE provider " + cipher.getProvider().getName()); } return newLen; - } catch (ShortBufferException e) { - RuntimeException exc = new RuntimeException(e.toString()); - exc.initCause(e); - throw exc; } } @@ -399,11 +455,23 @@ } try { - int newLen = cipher.update(buf, offset, len, buf, offset); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); + int newLen; + if (cipherType == AEAD_CIPHER) { + try { + newLen = cipher.doFinal(buf, offset, len, buf, offset); + } catch (IllegalBlockSizeException ibse) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode in JCE provider " + + cipher.getProvider().getName(), ibse); + } + } else { + newLen = cipher.update(buf, offset, len, buf, offset); + if (newLen != len) { + // catch BouncyCastle buffering error + throw new RuntimeException("Cipher buffering error " + + "in JCE provider " + cipher.getProvider().getName()); + } } if (debug != null && Debug.isOn("plaintext")) { try { @@ -418,7 +486,8 @@ } catch (IOException e) { } } - if (blockSize != 0) { + if (cipherType == BLOCK_CIPHER) { + int blockSize = cipher.getBlockSize(); newLen = removePadding( buf, offset, newLen, tagLen, blockSize, protocolVersion); @@ -426,16 +495,11 @@ if (newLen < blockSize) { throw new BadPaddingException("invalid explicit IV"); } - - // discards the first cipher block, the IV component. - System.arraycopy(buf, offset + blockSize, - buf, offset, newLen - blockSize); - - newLen -= blockSize; } } return newLen; } catch (ShortBufferException e) { + // unlikely to happen, we should have enough buffer space here throw new ArrayIndexOutOfBoundsException(e.toString()); } } @@ -465,13 +529,28 @@ */ int pos = bb.position(); ByteBuffer dup = bb.duplicate(); - int newLen = cipher.update(dup, bb); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); + int newLen; + if (cipherType == AEAD_CIPHER) { + try { + newLen = cipher.doFinal(dup, bb); + } catch (IllegalBlockSizeException ibse) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode \"" + ibse.getMessage() + + " \"in JCE provider " + cipher.getProvider().getName()); + } + } else { + newLen = cipher.update(dup, bb); + if (newLen != len) { + // catch BouncyCastle buffering error + throw new RuntimeException("Cipher buffering error " + + "in JCE provider " + cipher.getProvider().getName()); + } } + // reset the limit to the end of the decryted data + bb.limit(pos + newLen); + if (debug != null && Debug.isOn("plaintext")) { try { HexDumpEncoder hd = new HexDumpEncoder(); @@ -488,44 +567,25 @@ /* * Remove the block padding. */ - if (blockSize != 0) { + if (cipherType == BLOCK_CIPHER) { + int blockSize = cipher.getBlockSize(); bb.position(pos); - newLen = removePadding( - bb, tagLen, blockSize, protocolVersion); + newLen = removePadding(bb, tagLen, blockSize, protocolVersion); + // check the explicit IV of TLS v1.1 or later if (protocolVersion.v >= ProtocolVersion.TLS11.v) { if (newLen < blockSize) { throw new BadPaddingException("invalid explicit IV"); } - // discards the first cipher block, the IV component. - byte[] buf = null; - int limit = bb.limit(); - if (bb.hasArray()) { - int arrayOffset = bb.arrayOffset(); - buf = bb.array(); - System.arraycopy(buf, arrayOffset + pos + blockSize, - buf, arrayOffset + pos, limit - pos - blockSize); - bb.limit(limit - blockSize); - } else { - buf = new byte[limit - pos - blockSize]; - bb.position(pos + blockSize); - bb.get(buf); - bb.position(pos); - bb.put(buf); - bb.limit(limit - blockSize); - } - // reset the position to the end of the decrypted data - limit = bb.limit(); - bb.position(limit); + bb.position(bb.limit()); } } return newLen; } catch (ShortBufferException e) { - RuntimeException exc = new RuntimeException(e.toString()); - exc.initCause(e); - throw exc; + // unlikely to happen, we should have enough buffer space here + throw new ArrayIndexOutOfBoundsException(e.toString()); } } @@ -766,8 +826,8 @@ // ignore return value. cipher.doFinal(); } - } catch (GeneralSecurityException e) { - // swallow for now. + } catch (Exception e) { + // swallow all types of exceptions. } } @@ -777,10 +837,19 @@ * @return true if the cipher use CBC mode, false otherwise. */ boolean isCBCMode() { - return isCBCMode; + return cipherType == BLOCK_CIPHER; } - /** + /* + * Does the cipher use AEAD mode? + * + * @return true if the cipher use AEAD mode, false otherwise. + */ + boolean isAEADMode() { + return cipherType == AEAD_CIPHER; + } + + /* * Is the cipher null? * * @return true if the cipher is null, false otherwise. @@ -789,6 +858,226 @@ return cipher == null; } + /* + * Gets the explicit nonce/IV size of the cipher. + * + * The returned value is the SecurityParameters.record_iv_length in + * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the + * size of explicit nonce for AEAD mode. + * + * @return the explicit nonce size of the cipher. + */ + int getExplicitNonceSize() { + switch (cipherType) { + case BLOCK_CIPHER: + // For block ciphers, the explicit IV length is of length + // SecurityParameters.record_iv_length, which is equal to + // the SecurityParameters.block_size. + if (protocolVersion.v >= ProtocolVersion.TLS11.v) { + return cipher.getBlockSize(); + } + break; + case AEAD_CIPHER: + return recordIvSize; + // It is also the length of sequence number, which is + // used as the nonce_explicit for AEAD cipher suites. + } + + return 0; + } + + /* + * Applies the explicit nonce/IV to this cipher. This method is used to + * decrypt an SSL/TLS input record. + * + * The returned value is the SecurityParameters.record_iv_length in + * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the + * size of explicit nonce for AEAD mode. + * + * @param authenticator the authenticator to get the additional + * authentication data + * @param contentType the content type of the input record + * @param bb the byte buffer to get the explicit nonce from + * + * @return the explicit nonce size of the cipher. + */ + int applyExplicitNonce(Authenticator authenticator, byte contentType, + ByteBuffer bb) throws BadPaddingException { + switch (cipherType) { + case BLOCK_CIPHER: + // sanity check length of the ciphertext + int tagLen = (authenticator instanceof MAC) ? + ((MAC)authenticator).MAClen() : 0; + if (tagLen != 0) { + if (!sanityCheck(tagLen, bb.remaining())) { + throw new BadPaddingException( + "ciphertext sanity check failed"); + } + } + + // For block ciphers, the explicit IV length is of length + // SecurityParameters.record_iv_length, which is equal to + // the SecurityParameters.block_size. + if (protocolVersion.v >= ProtocolVersion.TLS11.v) { + return cipher.getBlockSize(); + } + break; + case AEAD_CIPHER: + if (bb.remaining() < (recordIvSize + tagSize)) { + throw new BadPaddingException( + "invalid AEAD cipher fragment"); + } + + // initialize the AEAD cipher for the unique IV + byte[] iv = Arrays.copyOf(fixedIv, + fixedIv.length + recordIvSize); + bb.get(iv, fixedIv.length, recordIvSize); + bb.position(bb.position() - recordIvSize); + GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); + try { + cipher.init(mode, key, spec, random); + } catch (InvalidKeyException | + InvalidAlgorithmParameterException ikae) { + // unlikely to happen + throw new RuntimeException( + "invalid key or spec in GCM mode", ikae); + } + + // update the additional authentication data + byte[] aad = authenticator.acquireAuthenticationBytes( + contentType, bb.remaining() - recordIvSize - tagSize); + cipher.updateAAD(aad); + + return recordIvSize; + // It is also the length of sequence number, which is + // used as the nonce_explicit for AEAD cipher suites. + } + + return 0; + } + + /* + * Applies the explicit nonce/IV to this cipher. This method is used to + * decrypt an SSL/TLS input record. + * + * The returned value is the SecurityParameters.record_iv_length in + * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the + * size of explicit nonce for AEAD mode. + * + * @param authenticator the authenticator to get the additional + * authentication data + * @param contentType the content type of the input record + * @param buf the byte array to get the explicit nonce from + * @param offset the offset of the byte buffer + * @param cipheredLength the ciphered fragment length of the output + * record, it is the TLSCiphertext.length in RFC 4346/5246. + * + * @return the explicit nonce size of the cipher. + */ + int applyExplicitNonce(Authenticator authenticator, + byte contentType, byte[] buf, int offset, + int cipheredLength) throws BadPaddingException { + + ByteBuffer bb = ByteBuffer.wrap(buf, offset, cipheredLength); + + return applyExplicitNonce(authenticator, contentType, bb); + } + + /* + * Creates the explicit nonce/IV to this cipher. This method is used to + * encrypt an SSL/TLS output record. + * + * The size of the returned array is the SecurityParameters.record_iv_length + * in RFC 4346/5246. It is the size of explicit IV for CBC mode, and the + * size of explicit nonce for AEAD mode. + * + * @param authenticator the authenticator to get the additional + * authentication data + * @param contentType the content type of the input record + * @param fragmentLength the fragment length of the output record, it is + * the TLSCompressed.length in RFC 4346/5246. + * + * @return the explicit nonce of the cipher. + */ + byte[] createExplicitNonce(Authenticator authenticator, + byte contentType, int fragmentLength) { + + byte[] nonce = new byte[0]; + switch (cipherType) { + case BLOCK_CIPHER: + if (protocolVersion.v >= ProtocolVersion.TLS11.v) { + // For block ciphers, the explicit IV length is of length + // SecurityParameters.record_iv_length, which is equal to + // the SecurityParameters.block_size. + // + // Generate a random number as the explicit IV parameter. + nonce = new byte[cipher.getBlockSize()]; + random.nextBytes(nonce); + } + break; + case AEAD_CIPHER: + // To be unique and aware of overflow-wrap, sequence number + // is used as the nonce_explicit of AEAD cipher suites. + nonce = authenticator.sequenceNumber(); + + // initialize the AEAD cipher for the unique IV + byte[] iv = Arrays.copyOf(fixedIv, + fixedIv.length + nonce.length); + System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length); + GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); + try { + cipher.init(mode, key, spec, random); + } catch (InvalidKeyException | + InvalidAlgorithmParameterException ikae) { + // unlikely to happen + throw new RuntimeException( + "invalid key or spec in GCM mode", ikae); + } + + // update the additional authentication data + byte[] aad = authenticator.acquireAuthenticationBytes( + contentType, fragmentLength); + cipher.updateAAD(aad); + break; + } + + return nonce; + } + + /* + * Is this cipher available? + * + * This method can only be called by CipherSuite.BulkCipher.isAvailable() + * to test the availability of a cipher suites. Please DON'T use it in + * other places, otherwise, the behavior may be unexpected because we may + * initialize AEAD cipher improperly in the method. + */ + Boolean isAvailable() { + // We won't know whether a cipher for a particular key size is + // available until the cipher is successfully initialized. + // + // We do not initialize AEAD cipher in the constructor. Need to + // initialize the cipher to ensure that the AEAD mode for a + // particular key size is supported. + if (cipherType == AEAD_CIPHER) { + try { + Authenticator authenticator = + new Authenticator(protocolVersion); + byte[] nonce = authenticator.sequenceNumber(); + byte[] iv = Arrays.copyOf(fixedIv, + fixedIv.length + nonce.length); + System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length); + GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); + + cipher.init(mode, key, spec, random); + } catch (Exception e) { + return Boolean.FALSE; + } + } // Otherwise, we have initialized the cipher in the constructor. + + return Boolean.TRUE; + } + /** * Sanity check the length of a fragment before decryption. * @@ -802,11 +1091,12 @@ * * @return true if the length of a fragment matches above requirements */ - boolean sanityCheck(int tagLen, int fragmentLen) { - if (!isCBCMode) { + private boolean sanityCheck(int tagLen, int fragmentLen) { + if (!isCBCMode()) { return fragmentLen >= tagLen; } + int blockSize = cipher.getBlockSize(); if ((fragmentLen % blockSize) == 0) { int minimal = tagLen + 1; minimal = (minimal >= blockSize) ? minimal : blockSize;
--- a/src/share/classes/sun/security/ssl/CipherSuite.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/CipherSuite.java Wed Apr 17 02:53:02 2013 -0700 @@ -33,12 +33,14 @@ import java.security.SecureRandom; import java.security.KeyManagementException; +import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import static sun.security.ssl.CipherSuite.KeyExchange.*; import static sun.security.ssl.CipherSuite.PRF.*; +import static sun.security.ssl.CipherSuite.CipherType.*; import static sun.security.ssl.JsseJce.*; /** @@ -135,7 +137,9 @@ this.keyExchange = keyExchange; this.cipher = cipher; this.exportable = cipher.exportable; - if (name.endsWith("_MD5")) { + if (cipher.cipherType == CipherType.AEAD_CIPHER) { + macAlg = M_NULL; + } else if (name.endsWith("_MD5")) { macAlg = M_MD5; } else if (name.endsWith("_SHA")) { macAlg = M_SHA; @@ -385,6 +389,12 @@ } } + static enum CipherType { + STREAM_CIPHER, // null or stream cipher + BLOCK_CIPHER, // block cipher in CBC mode + AEAD_CIPHER // AEAD cipher + } + /** * An SSL/TLS bulk cipher algorithm. One instance per combination of * cipher and key length. @@ -417,14 +427,26 @@ // for non-exportable ciphers, this is the same as keySize final int expandedKeySize; - // size of the IV (also block size) + // size of the IV final int ivSize; + // size of fixed IV + // + // record_iv_length = ivSize - fixedIvSize + final int fixedIvSize; + // exportable under 512/40 bit rules final boolean exportable; // Is the cipher algorithm of Cipher Block Chaining (CBC) mode? - final boolean isCBCMode; + final CipherType cipherType; + + // size of the authentication tag, only applicable to cipher suites in + // Galois Counter Mode (GCM) + // + // As far as we know, all supported GCM cipher suites use 128-bits + // authentication tags. + final int tagSize = 16; // The secure random used to detect the cipher availability. private final static SecureRandom secureRandom; @@ -437,32 +459,34 @@ } } - BulkCipher(String transformation, int keySize, - int expandedKeySize, int ivSize, boolean allowed) { + BulkCipher(String transformation, CipherType cipherType, int keySize, + int expandedKeySize, int ivSize, + int fixedIvSize, boolean allowed) { + this.transformation = transformation; String[] splits = transformation.split("/"); this.algorithm = splits[0]; - this.isCBCMode = - splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]); + this.cipherType = cipherType; this.description = this.algorithm + "/" + (keySize << 3); this.keySize = keySize; this.ivSize = ivSize; + this.fixedIvSize = fixedIvSize; this.allowed = allowed; this.expandedKeySize = expandedKeySize; this.exportable = true; } - BulkCipher(String transformation, int keySize, - int ivSize, boolean allowed) { + BulkCipher(String transformation, CipherType cipherType, int keySize, + int ivSize, int fixedIvSize, boolean allowed) { this.transformation = transformation; String[] splits = transformation.split("/"); this.algorithm = splits[0]; - this.isCBCMode = - splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]); + this.cipherType = cipherType; this.description = this.algorithm + "/" + (keySize << 3); this.keySize = keySize; this.ivSize = ivSize; + this.fixedIvSize = fixedIvSize; this.allowed = allowed; this.expandedKeySize = keySize; @@ -486,16 +510,20 @@ * Test if this bulk cipher is available. For use by CipherSuite. * * Currently all supported ciphers except AES are always available - * via the JSSE internal implementations. We also assume AES/128 - * is always available since it is shipped with the SunJCE provider. - * However, AES/256 is unavailable when the default JCE policy - * jurisdiction files are installed because of key length restrictions. + * via the JSSE internal implementations. We also assume AES/128 of + * CBC mode is always available since it is shipped with the SunJCE + * provider. However, AES/256 is unavailable when the default JCE + * policy jurisdiction files are installed because of key length + * restrictions, and AEAD is unavailable when the underlying providers + * do not support AEAD/GCM mode. */ boolean isAvailable() { if (allowed == false) { return false; } - if (this == B_AES_256) { + + if ((this == B_AES_256) || + (this.cipherType == CipherType.AEAD_CIPHER)) { return isAvailable(this); } @@ -513,19 +541,50 @@ private static synchronized boolean isAvailable(BulkCipher cipher) { Boolean b = availableCache.get(cipher); if (b == null) { - try { - SecretKey key = new SecretKeySpec - (new byte[cipher.expandedKeySize], cipher.algorithm); - IvParameterSpec iv = - new IvParameterSpec(new byte[cipher.ivSize]); - cipher.newCipher(ProtocolVersion.DEFAULT, + int keySizeInBits = cipher.keySize * 8; + if (keySizeInBits > 128) { // need the JCE unlimited + // strength jurisdiction policy + try { + if (Cipher.getMaxAllowedKeyLength( + cipher.transformation) < keySizeInBits) { + b = Boolean.FALSE; + } + } catch (Exception e) { + b = Boolean.FALSE; + } + } + + if (b == null) { + b = Boolean.FALSE; // may be reset to TRUE if + // the cipher is available + CipherBox temporary = null; + try { + SecretKey key = new SecretKeySpec( + new byte[cipher.expandedKeySize], + cipher.algorithm); + IvParameterSpec iv; + if (cipher.cipherType == CipherType.AEAD_CIPHER) { + iv = new IvParameterSpec( + new byte[cipher.fixedIvSize]); + } else { + iv = new IvParameterSpec(new byte[cipher.ivSize]); + } + temporary = cipher.newCipher( + ProtocolVersion.DEFAULT, key, iv, secureRandom, true); - b = Boolean.TRUE; - } catch (NoSuchAlgorithmException e) { - b = Boolean.FALSE; + b = temporary.isAvailable(); + } catch (NoSuchAlgorithmException e) { + // not available + } finally { + if (temporary != null) { + temporary.dispose(); + } + } } + availableCache.put(cipher, b); } + return b.booleanValue(); } @@ -582,27 +641,31 @@ // export strength ciphers final static BulkCipher B_NULL = - new BulkCipher("NULL", 0, 0, 0, true); + new BulkCipher("NULL", STREAM_CIPHER, 0, 0, 0, 0, true); final static BulkCipher B_RC4_40 = - new BulkCipher(CIPHER_RC4, 5, 16, 0, true); + new BulkCipher(CIPHER_RC4, STREAM_CIPHER, 5, 16, 0, 0, true); final static BulkCipher B_RC2_40 = - new BulkCipher("RC2", 5, 16, 8, false); + new BulkCipher("RC2", BLOCK_CIPHER, 5, 16, 8, 0, false); final static BulkCipher B_DES_40 = - new BulkCipher(CIPHER_DES, 5, 8, 8, true); + new BulkCipher(CIPHER_DES, BLOCK_CIPHER, 5, 8, 8, 0, true); // domestic strength ciphers final static BulkCipher B_RC4_128 = - new BulkCipher(CIPHER_RC4, 16, 0, true); + new BulkCipher(CIPHER_RC4, STREAM_CIPHER, 16, 0, 0, true); final static BulkCipher B_DES = - new BulkCipher(CIPHER_DES, 8, 8, true); + new BulkCipher(CIPHER_DES, BLOCK_CIPHER, 8, 8, 0, true); final static BulkCipher B_3DES = - new BulkCipher(CIPHER_3DES, 24, 8, true); + new BulkCipher(CIPHER_3DES, BLOCK_CIPHER, 24, 8, 0, true); final static BulkCipher B_IDEA = - new BulkCipher("IDEA", 16, 8, false); + new BulkCipher("IDEA", BLOCK_CIPHER, 16, 8, 0, false); final static BulkCipher B_AES_128 = - new BulkCipher(CIPHER_AES, 16, 16, true); + new BulkCipher(CIPHER_AES, BLOCK_CIPHER, 16, 16, 0, true); final static BulkCipher B_AES_256 = - new BulkCipher(CIPHER_AES, 32, 16, true); + new BulkCipher(CIPHER_AES, BLOCK_CIPHER, 32, 16, 0, true); + final static BulkCipher B_AES_128_GCM = + new BulkCipher(CIPHER_AES_GCM, AEAD_CIPHER, 16, 12, 4, true); + final static BulkCipher B_AES_256_GCM = + new BulkCipher(CIPHER_AES_GCM, AEAD_CIPHER, 32, 12, 4, true); // MACs final static MacAlg M_NULL = new MacAlg("NULL", 0, 0, 0); @@ -902,11 +965,13 @@ * Definition of the CipherSuites that are enabled by default. * They are listed in preference order, most preferred first, using * the following criteria: - * 1. Prefer the stronger buld cipher, in the order of AES_256, - * AES_128, RC-4, 3DES-EDE. - * 2. Prefer the stronger MAC algorithm, in the order of SHA384, + * 1. Prefer Suite B compliant cipher suites, see RFC6460 (To be + * changed later, see below). + * 2. Prefer the stronger bulk cipher, in the order of AES_256(GCM), + * AES_128(GCM), AES_256, AES_128, RC-4, 3DES-EDE. + * 3. Prefer the stronger MAC algorithm, in the order of SHA384, * SHA256, SHA, MD5. - * 3. Prefer the better performance of key exchange and digital + * 4. Prefer the better performance of key exchange and digital * signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA, * RSA, ECDH-ECDSA, ECDH-RSA, DHE-RSA, DHE-DSS. */ @@ -919,6 +984,16 @@ // ID Key Exchange Cipher A obs suprt PRF // ====== ============ ========= = === ===== ======== + + + // Placeholder for cipher suites in GCM mode. + // + // For better compatibility and interoperability, we decrease the + // priority of cipher suites in GCM mode for a while as GCM + // technologies mature in the industry. Eventually we'll move + // the GCM suites here. + + // AES_256(CBC) add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 0xc024, --p, K_ECDHE_ECDSA, B_AES_256, T, max, tls12, P_SHA384); add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", @@ -949,6 +1024,7 @@ add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 0x0038, --p, K_DHE_DSS, B_AES_256, T); + // AES_128(CBC) add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 0xc023, --p, K_ECDHE_ECDSA, B_AES_128, T, max, tls12, P_SHA256); add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", @@ -979,6 +1055,7 @@ add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 0x0032, --p, K_DHE_DSS, B_AES_128, T); + // RC-4 add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 0xC007, --p, K_ECDHE_ECDSA, B_RC4_128, N); add("TLS_ECDHE_RSA_WITH_RC4_128_SHA", @@ -990,6 +1067,51 @@ add("TLS_ECDH_RSA_WITH_RC4_128_SHA", 0xC00C, --p, K_ECDH_RSA, B_RC4_128, N); + // Cipher suites in GCM mode, see RFC 5288/5289. + // + // We may increase the priority of cipher suites in GCM mode when + // GCM technologies become mature in the industry. + + // Suite B compliant cipher suites, see RFC 6460. + // + // Note that, at present this provider is not Suite B compliant. The + // preference order of the GCM cipher suites does not follow the spec + // of RFC 6460. + add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + 0xc02c, --p, K_ECDHE_ECDSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + 0xc02b, --p, K_ECDHE_ECDSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + + // AES_256(GCM) + add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + 0xc030, --p, K_ECDHE_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_RSA_WITH_AES_256_GCM_SHA384", + 0x009d, --p, K_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", + 0xc02e, --p, K_ECDH_ECDSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", + 0xc032, --p, K_ECDH_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + 0x009f, --p, K_DHE_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", + 0x00a3, --p, K_DHE_DSS, B_AES_256_GCM, T, max, tls12, P_SHA384); + + // AES_128(GCM) + add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + 0xc02f, --p, K_ECDHE_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + add("TLS_RSA_WITH_AES_128_GCM_SHA256", + 0x009c, --p, K_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + 0xc02d, --p, K_ECDH_ECDSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", + 0xc031, --p, K_ECDH_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", + 0x009e, --p, K_DHE_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", + 0x00a2, --p, K_DHE_DSS, B_AES_128_GCM, T, max, tls12, P_SHA256); + // End of cipher suites in GCM mode. + + // 3DES_EDE add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xC008, --p, K_ECDHE_ECDSA, B_3DES, T); add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", @@ -1033,17 +1155,22 @@ */ p = DEFAULT_SUITES_PRIORITY; + add("TLS_DH_anon_WITH_AES_256_GCM_SHA384", + 0x00a7, --p, K_DH_ANON, B_AES_256_GCM, N, max, tls12, P_SHA384); + add("TLS_DH_anon_WITH_AES_128_GCM_SHA256", + 0x00a6, --p, K_DH_ANON, B_AES_128_GCM, N, max, tls12, P_SHA256); + add("TLS_DH_anon_WITH_AES_256_CBC_SHA256", 0x006d, --p, K_DH_ANON, B_AES_256, N, max, tls12, P_SHA256); add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", - 0xC019, --p, K_ECDH_ANON, B_AES_256, T); + 0xC019, --p, K_ECDH_ANON, B_AES_256, N); add("TLS_DH_anon_WITH_AES_256_CBC_SHA", 0x003a, --p, K_DH_ANON, B_AES_256, N); add("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x006c, --p, K_DH_ANON, B_AES_128, N, max, tls12, P_SHA256); add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", - 0xC018, --p, K_ECDH_ANON, B_AES_128, T); + 0xC018, --p, K_ECDH_ANON, B_AES_128, N); add("TLS_DH_anon_WITH_AES_128_CBC_SHA", 0x0034, --p, K_DH_ANON, B_AES_128, N); @@ -1053,7 +1180,7 @@ 0x0018, --p, K_DH_ANON, B_RC4_128, N); add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", - 0xC017, --p, K_ECDH_ANON, B_3DES, T); + 0xC017, --p, K_ECDH_ANON, B_3DES, N); add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", 0x001b, --p, K_DH_ANON, B_3DES, N); @@ -1208,18 +1335,10 @@ add("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069); // Unsupported cipher suites from RFC 5288 - add("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x009c); - add("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x009d); - add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x009e); - add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x009f); add("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0); add("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1); - add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x00a2); - add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x00a3); add("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4); add("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5); - add("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x00a6); - add("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x00a7); // Unsupported cipher suites from RFC 5487 add("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8); @@ -1278,16 +1397,6 @@ add("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021); add("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022); - // Unsupported cipher suites from RFC 5289 - add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02b); - add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02c); - add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02d); - add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02e); - add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xc02f); - add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xc030); - add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xc031); - add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xc032); - // Unsupported cipher suites from RFC 5489 add("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033); add("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034);
--- a/src/share/classes/sun/security/ssl/EngineInputRecord.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/EngineInputRecord.java Wed Apr 17 02:53:02 2013 -0700 @@ -186,29 +186,35 @@ * If external data(app), return a new ByteBuffer with data to * process. */ - ByteBuffer decrypt(MAC signer, + ByteBuffer decrypt(Authenticator authenticator, CipherBox box, ByteBuffer bb) throws BadPaddingException { if (internalData) { - decrypt(signer, box); // MAC is checked during decryption + decrypt(authenticator, box); // MAC is checked during decryption return tmpBB; } BadPaddingException reservedBPE = null; - int tagLen = signer.MAClen(); + int tagLen = + (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0; int cipheredLength = bb.remaining(); if (!box.isNullCipher()) { - // sanity check length of the ciphertext - if (!box.sanityCheck(tagLen, cipheredLength)) { - throw new BadPaddingException( - "ciphertext sanity check failed"); - } + try { + // apply explicit nonce for AEAD/CBC cipher suites if needed + int nonceSize = + box.applyExplicitNonce(authenticator, contentType(), bb); - try { + // decrypt the content + if (box.isAEADMode()) { + // DON'T encrypt the nonce_explicit for AEAD mode + bb.position(bb.position() + nonceSize); + } // The explicit IV for CBC mode can be decrypted. + // Note that the CipherBox.decrypt() does not change // the capacity of the buffer. box.decrypt(bb, tagLen); + bb.position(nonceSize); // We don't actually remove the nonce. } catch (BadPaddingException bpe) { // RFC 2246 states that decryption_failed should be used // for this purpose. However, that allows certain attacks, @@ -219,12 +225,13 @@ // // Failover to message authentication code checking. reservedBPE = bpe; - } finally { - bb.rewind(); } } - if (tagLen != 0) { + // Requires message authentication code for null, stream and block + // cipher suites. + if ((authenticator instanceof MAC) && (tagLen != 0)) { + MAC signer = (MAC)authenticator; int macOffset = bb.limit() - tagLen; // Note that although it is not necessary, we run the same MAC @@ -297,6 +304,7 @@ private static boolean checkMacTags(byte contentType, ByteBuffer bb, MAC signer, boolean isSimulated) { + int position = bb.position(); int tagLen = signer.MAClen(); int lim = bb.limit(); int macData = lim - tagLen; @@ -314,7 +322,8 @@ int[] results = compareMacTags(bb, hash); return (results[0] != 0); } finally { - bb.rewind(); + // reset to the data + bb.position(position); bb.limit(macData); } } @@ -416,8 +425,8 @@ if (debug != null && Debug.isOn("packet")) { try { HexDumpEncoder hd = new HexDumpEncoder(); - srcBB.limit(srcPos + len); ByteBuffer bb = srcBB.duplicate(); // Use copy of BB + bb.limit(srcPos + len); System.out.println("[Raw read (bb)]: length = " + len); hd.encodeBuffer(bb, System.out);
--- a/src/share/classes/sun/security/ssl/EngineOutputRecord.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/EngineOutputRecord.java Wed Apr 17 02:53:02 2013 -0700 @@ -29,7 +29,6 @@ import java.io.*; import java.nio.*; - /** * A OutputRecord class extension which uses external ByteBuffers * or the internal ByteArrayOutputStream for data manipulations. @@ -101,51 +100,6 @@ return finishedMsg; } - - /** - * Calculate the MAC value, storing the result either in - * the internal buffer, or at the end of the destination - * ByteBuffer. - * <P> - * We assume that the higher levels have assured us enough - * room, otherwise we'll indirectly throw a - * BufferOverFlowException runtime exception. - * - * position should equal limit, and points to the next - * free spot. - */ - private void addMAC(MAC signer, ByteBuffer bb) - throws IOException { - - if (signer.MAClen() != 0) { - byte[] hash = signer.compute(contentType(), bb, false); - - /* - * position was advanced to limit in compute above. - * - * Mark next area as writable (above layers should have - * established that we have plenty of room), then write - * out the hash. - */ - bb.limit(bb.limit() + hash.length); - bb.put(hash); - } - } - - /* - * Encrypt a ByteBuffer. - * - * We assume that the higher levels have assured us enough - * room for the encryption (plus padding), otherwise we'll - * indirectly throw a BufferOverFlowException runtime exception. - * - * position and limit will be the same, and points to the - * next free spot. - */ - void encrypt(CipherBox box, ByteBuffer bb) { - box.encrypt(bb); - } - /* * Override the actual write below. We do things this way to be * consistent with InputRecord. InputRecord may try to write out @@ -160,7 +114,8 @@ * Copy data out of buffer, it's ready to go. */ ByteBuffer netBB = (ByteBuffer) - ByteBuffer.allocate(len).put(buf, 0, len).flip(); + ByteBuffer.allocate(len).put(buf, off, len).flip(); + writer.putOutboundData(netBB); } @@ -168,17 +123,19 @@ * Main method for writing non-application data. * We MAC/encrypt, then send down for processing. */ - void write(MAC writeMAC, CipherBox writeCipher) throws IOException { + void write(Authenticator authenticator, CipherBox writeCipher) + throws IOException { + /* * Sanity check. */ switch (contentType()) { - case ct_change_cipher_spec: - case ct_alert: - case ct_handshake: - break; - default: - throw new RuntimeException("unexpected byte buffers"); + case ct_change_cipher_spec: + case ct_alert: + case ct_handshake: + break; + default: + throw new RuntimeException("unexpected byte buffers"); } /* @@ -193,10 +150,10 @@ */ if (!isEmpty()) { // compress(); // eventually - addMAC(writeMAC); - encrypt(writeCipher); - write((OutputStream)null, false, // send down for processing - (ByteArrayOutputStream)null); + encrypt(authenticator, writeCipher); + + // send down for processing + write((OutputStream)null, false, (ByteArrayOutputStream)null); } return; } @@ -204,8 +161,8 @@ /** * Main wrap/write driver. */ - void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher) - throws IOException { + void write(EngineArgs ea, Authenticator authenticator, + CipherBox writeCipher) throws IOException { /* * sanity check to make sure someone didn't inadvertantly * send us an impossible combination we don't know how @@ -217,7 +174,7 @@ * Have we set the MAC's yet? If not, we're not ready * to process application data yet. */ - if (writeMAC == MAC.NULL) { + if (authenticator == MAC.NULL) { return; } @@ -255,7 +212,7 @@ */ int length; if (engine.needToSplitPayload(writeCipher, protocolVersion)) { - write(ea, writeMAC, writeCipher, 0x01); + write(ea, authenticator, writeCipher, 0x01); ea.resetLim(); // reset application data buffer limit length = Math.min(ea.getAppRemaining(), maxDataSizeMinusOneByteRecord); @@ -265,14 +222,14 @@ // Don't bother to really write empty records. if (length > 0) { - write(ea, writeMAC, writeCipher, length); + write(ea, authenticator, writeCipher, length); } return; } - void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher, - int length) throws IOException { + void write(EngineArgs ea, Authenticator authenticator, + CipherBox writeCipher, int length) throws IOException { /* * Copy out existing buffer values. */ @@ -286,39 +243,76 @@ * Don't need to worry about SSLv2 rewrites, if we're here, * that's long since done. */ - int dstData = dstPos + headerSize; + int dstData = dstPos + headerSize + writeCipher.getExplicitNonceSize(); dstBB.position(dstData); + /* + * transfer application data into the network data buffer + */ ea.gather(length); + dstBB.limit(dstBB.position()); + dstBB.position(dstData); /* * "flip" but skip over header again, add MAC & encrypt - * addMAC will expand the limit to reflect the new - * data. */ - dstBB.limit(dstBB.position()); - dstBB.position(dstData); - addMAC(writeMAC, dstBB); + if (authenticator instanceof MAC) { + MAC signer = (MAC)authenticator; + if (signer.MAClen() != 0) { + byte[] hash = signer.compute(contentType(), dstBB, false); + + /* + * position was advanced to limit in compute above. + * + * Mark next area as writable (above layers should have + * established that we have plenty of room), then write + * out the hash. + */ + dstBB.limit(dstBB.limit() + hash.length); + dstBB.put(hash); + + // reset the position and limit + dstBB.limit(dstBB.position()); + dstBB.position(dstData); + } + } - /* - * Encrypt may pad, so again the limit may have changed. - */ - dstBB.limit(dstBB.position()); - dstBB.position(dstData); - encrypt(writeCipher, dstBB); + if (!writeCipher.isNullCipher()) { + /* + * Requires explicit IV/nonce for CBC/AEAD cipher suites for TLS 1.1 + * or later. + */ + if (protocolVersion.v >= ProtocolVersion.TLS11.v && + (writeCipher.isCBCMode() || writeCipher.isAEADMode())) { + byte[] nonce = writeCipher.createExplicitNonce( + authenticator, contentType(), dstBB.remaining()); + dstBB.position(dstPos + headerSize); + dstBB.put(nonce); + if (!writeCipher.isAEADMode()) { + // The explicit IV in TLS 1.1 and later can be encrypted. + dstBB.position(dstPos + headerSize); + } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode + } - if (debug != null - && (Debug.isOn("record") || Debug.isOn("handshake"))) { - if ((debug != null && Debug.isOn("record")) - || contentType() == ct_change_cipher_spec) + /* + * Encrypt may pad, so again the limit may have changed. + */ + writeCipher.encrypt(dstBB, dstLim); + + if ((debug != null) && (Debug.isOn("record") || + (Debug.isOn("handshake") && + (contentType() == ct_change_cipher_spec)))) { System.out.println(Thread.currentThread().getName() // v3.0/v3.1 ... + ", WRITE: " + protocolVersion + " " + InputRecord.contentName(contentType()) + ", length = " + length); + } + } else { + dstBB.position(dstBB.limit()); } - int packetLength = dstBB.limit() - dstData; + int packetLength = dstBB.limit() - dstPos - headerSize; /* * Finish out the record header. @@ -333,7 +327,5 @@ * Position was already set by encrypt() above. */ dstBB.limit(dstLim); - - return; } }
--- a/src/share/classes/sun/security/ssl/EngineWriter.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/EngineWriter.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,7 +99,8 @@ * other writeRecord. */ synchronized void writeRecord(EngineOutputRecord outputRecord, - MAC writeMAC, CipherBox writeCipher) throws IOException { + Authenticator authenticator, + CipherBox writeCipher) throws IOException { /* * Only output if we're still open. @@ -108,7 +109,7 @@ throw new IOException("writer side was already closed."); } - outputRecord.write(writeMAC, writeCipher); + outputRecord.write(authenticator, writeCipher); /* * Did our handshakers notify that we just sent the @@ -151,7 +152,8 @@ * Return any determined status. */ synchronized HandshakeStatus writeRecord( - EngineOutputRecord outputRecord, EngineArgs ea, MAC writeMAC, + EngineOutputRecord outputRecord, EngineArgs ea, + Authenticator authenticator, CipherBox writeCipher) throws IOException { /* @@ -181,7 +183,7 @@ throw new IOException("The write side was already closed"); } - outputRecord.write(ea, writeMAC, writeCipher); + outputRecord.write(ea, authenticator, writeCipher); if (debug != null && Debug.isOn("packet")) { dumpPacket(ea, false);
--- a/src/share/classes/sun/security/ssl/Handshaker.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/Handshaker.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,7 @@ import sun.security.ssl.CipherSuite.*; import static sun.security.ssl.CipherSuite.PRF.*; +import static sun.security.ssl.CipherSuite.CipherType.*; /** * Handshaker ... processes handshake records from an SSL V3.0 @@ -714,33 +715,47 @@ /** * Create a new read MAC and return it to caller. */ - MAC newReadMAC() throws NoSuchAlgorithmException, InvalidKeyException { - MacAlg macAlg = cipherSuite.macAlg; - MAC mac; - if (isClient) { - mac = macAlg.newMac(protocolVersion, svrMacSecret); - svrMacSecret = null; + Authenticator newReadAuthenticator() + throws NoSuchAlgorithmException, InvalidKeyException { + + Authenticator authenticator = null; + if (cipherSuite.cipher.cipherType == AEAD_CIPHER) { + authenticator = new Authenticator(protocolVersion); } else { - mac = macAlg.newMac(protocolVersion, clntMacSecret); - clntMacSecret = null; + MacAlg macAlg = cipherSuite.macAlg; + if (isClient) { + authenticator = macAlg.newMac(protocolVersion, svrMacSecret); + svrMacSecret = null; + } else { + authenticator = macAlg.newMac(protocolVersion, clntMacSecret); + clntMacSecret = null; + } } - return mac; + + return authenticator; } /** * Create a new write MAC and return it to caller. */ - MAC newWriteMAC() throws NoSuchAlgorithmException, InvalidKeyException { - MacAlg macAlg = cipherSuite.macAlg; - MAC mac; - if (isClient) { - mac = macAlg.newMac(protocolVersion, clntMacSecret); - clntMacSecret = null; + Authenticator newWriteAuthenticator() + throws NoSuchAlgorithmException, InvalidKeyException { + + Authenticator authenticator = null; + if (cipherSuite.cipher.cipherType == AEAD_CIPHER) { + authenticator = new Authenticator(protocolVersion); } else { - mac = macAlg.newMac(protocolVersion, svrMacSecret); - svrMacSecret = null; + MacAlg macAlg = cipherSuite.macAlg; + if (isClient) { + authenticator = macAlg.newMac(protocolVersion, clntMacSecret); + clntMacSecret = null; + } else { + authenticator = macAlg.newMac(protocolVersion, svrMacSecret); + svrMacSecret = null; + } } - return mac; + + return authenticator; } /* @@ -1189,11 +1204,23 @@ int prfHashLength = prf.getPRFHashLength(); int prfBlockSize = prf.getPRFBlockSize(); + // TLS v1.1 or later uses an explicit IV in CBC cipher suites to + // protect against the CBC attacks. AEAD/GCM cipher suites in TLS + // v1.2 or later use a fixed IV as the implicit part of the partially + // implicit nonce technique described in RFC 5116. + int ivSize = cipher.ivSize; + if (cipher.cipherType == AEAD_CIPHER) { + ivSize = cipher.fixedIvSize; + } else if (protocolVersion.v >= ProtocolVersion.TLS11.v && + cipher.cipherType == BLOCK_CIPHER) { + ivSize = 0; + } + TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec( masterKey, protocolVersion.major, protocolVersion.minor, clnt_random.random_bytes, svr_random.random_bytes, cipher.algorithm, cipher.keySize, expandedKeySize, - cipher.ivSize, hashSize, + ivSize, hashSize, prfHashAlg, prfHashLength, prfBlockSize); try { @@ -1201,14 +1228,15 @@ kg.init(spec); TlsKeyMaterialSpec keySpec = (TlsKeyMaterialSpec)kg.generateKey(); + // Return null if cipher keys are not supposed to be generated. clntWriteKey = keySpec.getClientCipherKey(); svrWriteKey = keySpec.getServerCipherKey(); // Return null if IVs are not supposed to be generated. - // e.g. TLS 1.1+. clntWriteIV = keySpec.getClientIv(); svrWriteIV = keySpec.getServerIv(); + // Return null if MAC keys are not supposed to be generated. clntMacSecret = keySpec.getClientMacKey(); svrMacSecret = keySpec.getServerMacKey(); } catch (GeneralSecurityException e) { @@ -1233,10 +1261,14 @@ printHex(dump, masterKey.getEncoded()); // Outputs: - System.out.println("Client MAC write Secret:"); - printHex(dump, clntMacSecret.getEncoded()); - System.out.println("Server MAC write Secret:"); - printHex(dump, svrMacSecret.getEncoded()); + if (clntMacSecret != null) { + System.out.println("Client MAC write Secret:"); + printHex(dump, clntMacSecret.getEncoded()); + System.out.println("Server MAC write Secret:"); + printHex(dump, svrMacSecret.getEncoded()); + } else { + System.out.println("... no MAC keys used for this cipher"); + } if (clntWriteKey != null) { System.out.println("Client write key:");
--- a/src/share/classes/sun/security/ssl/InputRecord.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/InputRecord.java Wed Apr 17 02:53:02 2013 -0700 @@ -77,6 +77,17 @@ /* * Construct the record to hold the maximum sized input record. * Data will be filled in separately. + * + * The structure of the byte buffer looks like: + * + * |--------+---------+---------------------------------| + * | header | IV | content, MAC/TAG, padding, etc. | + * | headerPlusIVSize | + * + * header: the header of an SSL records + * IV: the optional IV/nonce field, it is only required for block + * (TLS 1.1 or later) and AEAD cipher suites. + * */ InputRecord() { super(new byte[maxRecordSize]); @@ -133,24 +144,34 @@ return handshakeHash; } - void decrypt(MAC signer, CipherBox box) throws BadPaddingException { - + void decrypt(Authenticator authenticator, + CipherBox box) throws BadPaddingException { BadPaddingException reservedBPE = null; - int tagLen = signer.MAClen(); + int tagLen = + (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0; int cipheredLength = count - headerSize; if (!box.isNullCipher()) { - // sanity check length of the ciphertext - if (!box.sanityCheck(tagLen, cipheredLength)) { - throw new BadPaddingException( - "ciphertext sanity check failed"); - } + try { + // apply explicit nonce for AEAD/CBC cipher suites if needed + int nonceSize = box.applyExplicitNonce(authenticator, + contentType(), buf, headerSize, cipheredLength); + pos = headerSize + nonceSize; + lastHashed = pos; // don't digest the explicit nonce - try { + // decrypt the content + int offset = headerSize; + if (box.isAEADMode()) { + // DON'T encrypt the nonce_explicit for AEAD mode + offset += nonceSize; + } // The explicit IV for CBC mode can be decrypted. + // Note that the CipherBox.decrypt() does not change // the capacity of the buffer. - count = headerSize + - box.decrypt(buf, headerSize, cipheredLength, tagLen); + count = offset + + box.decrypt(buf, offset, count - offset, tagLen); + + // Note that we don't remove the nonce from the buffer. } catch (BadPaddingException bpe) { // RFC 2246 states that decryption_failed should be used // for this purpose. However, that allows certain attacks, @@ -164,9 +185,12 @@ } } - if (tagLen != 0) { + // Requires message authentication code for null, stream and block + // cipher suites. + if (authenticator instanceof MAC && tagLen != 0) { + MAC signer = (MAC)authenticator; int macOffset = count - tagLen; - int contentLen = macOffset - headerSize; + int contentLen = macOffset - pos; // Note that although it is not necessary, we run the same MAC // computation and comparison on the payload for both stream @@ -190,7 +214,7 @@ // Run MAC computation and comparison on the payload. if (checkMacTags(contentType(), - buf, headerSize, contentLen, signer, false)) { + buf, pos, contentLen, signer, false)) { if (reservedBPE == null) { reservedBPE = new BadPaddingException("bad record MAC"); }
--- a/src/share/classes/sun/security/ssl/JsseJce.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/JsseJce.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,6 +155,11 @@ */ final static String CIPHER_AES = "AES/CBC/NoPadding"; /** + * JCE transformation string for AES in GCM mode + * without padding. + */ + final static String CIPHER_AES_GCM = "AES/GCM/NoPadding"; + /** * JCA identifier string for DSA, i.e. a DSA with SHA-1. */ final static String SIGNATURE_DSA = "DSA";
--- a/src/share/classes/sun/security/ssl/MAC.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/MAC.java Wed Apr 17 02:53:02 2013 -0700 @@ -39,19 +39,15 @@ /** * This class computes the "Message Authentication Code" (MAC) for each - * SSL message. This is essentially a shared-secret signature, used to - * provide integrity protection for SSL messages. The MAC is actually - * one of several keyed hashes, as associated with the cipher suite and - * protocol version. (SSL v3.0 uses one construct, TLS uses another.) - * <P> - * NOTE: MAC computation is the only place in the SSL protocol that the - * sequence number is used. It's also reset to zero with each change of - * a cipher spec, so this is the only place this state is needed. + * SSL stream and block cipher message. This is essentially a shared-secret + * signature, used to provide integrity protection for SSL messages. The + * MAC is actually one of several keyed hashes, as associated with the cipher + * suite and protocol version. (SSL v3.0 uses one construct, TLS uses another.) * * @author David Brownell * @author Andreas Sterbenz */ -final class MAC { +final class MAC extends Authenticator { final static MAC NULL = new MAC(); @@ -61,33 +57,12 @@ // internal identifier for the MAC algorithm private final MacAlg macAlg; - // stuff defined by the kind of MAC algorithm - private final int macSize; - // JCE Mac object private final Mac mac; - // byte array containing the additional information we MAC in each record - // (see below) - private final byte[] block; - - // sequence number + record type + + record length - private static final int BLOCK_SIZE_SSL = 8 + 1 + 2; - - // sequence number + record type + protocol version + record length - private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2; - - // offset of record type in block - private static final int BLOCK_OFFSET_TYPE = 8; - - // offset of protocol version number in block (TLS only) - private static final int BLOCK_OFFSET_VERSION = 8 + 1; - private MAC() { - macSize = 0; macAlg = M_NULL; mac = null; - block = null; } /** @@ -95,8 +70,8 @@ */ MAC(MacAlg macAlg, ProtocolVersion protocolVersion, SecretKey key) throws NoSuchAlgorithmException, InvalidKeyException { + super(protocolVersion); this.macAlg = macAlg; - this.macSize = macAlg.size; String algorithm; boolean tls = (protocolVersion.v >= ProtocolVersion.TLS10.v); @@ -115,21 +90,13 @@ mac = JsseJce.getMac(algorithm); mac.init(key); - - if (tls) { - block = new byte[BLOCK_SIZE_TLS]; - block[BLOCK_OFFSET_VERSION] = protocolVersion.major; - block[BLOCK_OFFSET_VERSION+1] = protocolVersion.minor; - } else { - block = new byte[BLOCK_SIZE_SSL]; - } } /** * Returns the length of the MAC. */ int MAClen() { - return macSize; + return macAlg.size; } /** @@ -157,7 +124,17 @@ */ final byte[] compute(byte type, byte buf[], int offset, int len, boolean isSimulated) { - return compute(type, null, buf, offset, len, isSimulated); + if (macAlg.size == 0) { + return nullMAC; + } + + if (!isSimulated) { + byte[] additional = acquireAuthenticationBytes(type, len); + mac.update(additional); + } + mac.update(buf, offset, len); + + return mac.doFinal(); } /** @@ -173,83 +150,19 @@ * @param isSimulated if true, simulate the the MAC computation */ final byte[] compute(byte type, ByteBuffer bb, boolean isSimulated) { - return compute(type, bb, null, 0, bb.remaining(), isSimulated); - } - - /** - * Check whether the sequence number is close to wrap - * - * Sequence numbers are of type uint64 and may not exceed 2^64-1. - * Sequence numbers do not wrap. When the sequence number is near - * to wrap, we need to close the connection immediately. - */ - final boolean seqNumOverflow() { - /* - * Conservatively, we don't allow more records to be generated - * when there are only 2^8 sequence numbers left. - */ - return (block != null && mac != null && - block[0] == (byte)0xFF && block[1] == (byte)0xFF && - block[2] == (byte)0xFF && block[3] == (byte)0xFF && - block[4] == (byte)0xFF && block[5] == (byte)0xFF && - block[6] == (byte)0xFF); - } - - /* - * Check whether to renew the sequence number - * - * Sequence numbers are of type uint64 and may not exceed 2^64-1. - * Sequence numbers do not wrap. If a TLS - * implementation would need to wrap a sequence number, it must - * renegotiate instead. - */ - final boolean seqNumIsHuge() { - /* - * Conservatively, we should ask for renegotiation when there are - * only 2^48 sequence numbers left. - */ - return (block != null && mac != null && - block[0] == (byte)0xFF && block[1] == (byte)0xFF); - } - - // increment the sequence number in the block array - // it is a 64-bit number stored in big-endian format - private void incrementSequenceNumber() { - int k = 7; - while ((k >= 0) && (++block[k] == 0)) { - k--; - } - } - - /* - * Compute based on either buffer type, either bb.position/limit - * or buf/offset/len. - */ - private byte[] compute(byte type, ByteBuffer bb, byte[] buf, - int offset, int len, boolean isSimulated) { - - if (macSize == 0) { + if (macAlg.size == 0) { return nullMAC; } - // MUST NOT increase the sequence number for a simulated computation. if (!isSimulated) { - block[BLOCK_OFFSET_TYPE] = type; - block[block.length - 2] = (byte)(len >> 8); - block[block.length - 1] = (byte)(len ); - - mac.update(block); - incrementSequenceNumber(); + byte[] additional = + acquireAuthenticationBytes(type, bb.remaining()); + mac.update(additional); } - - // content - if (bb != null) { - mac.update(bb); - } else { - mac.update(buf, offset, len); - } + mac.update(bb); return mac.doFinal(); } } +
--- a/src/share/classes/sun/security/ssl/OutputRecord.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/OutputRecord.java Wed Apr 17 02:53:02 2013 -0700 @@ -54,6 +54,7 @@ private int lastHashed; private boolean firstMessage; final private byte contentType; + private int headerOffset; // current protocol version, sent as record version ProtocolVersion protocolVersion; @@ -70,6 +71,23 @@ * Default constructor makes a record supporting the maximum * SSL record size. It allocates the header bytes directly. * + * The structure of the byte buffer looks like: + * + * |---------+--------+-------+---------------------------------| + * | unused | header | IV | content, MAC/TAG, padding, etc. | + * | headerPlusMaxIVSize | + * + * unused: unused part of the buffer of size + * + * headerPlusMaxIVSize - header size - IV size + * + * When this object is created, we don't know the protocol + * version number, IV length, etc., so reserve space in front + * to avoid extra data movement (copies). + * header: the header of an SSL record + * IV: the optional IV/nonce field, it is only required for block + * (TLS 1.1 or later) and AEAD cipher suites. + * * @param type the content type for the record */ OutputRecord(byte type, int size) { @@ -77,9 +95,10 @@ this.protocolVersion = ProtocolVersion.DEFAULT; this.helloVersion = ProtocolVersion.DEFAULT_HELLO; firstMessage = true; - count = headerSize; + count = headerPlusMaxIVSize; contentType = type; lastHashed = count; + headerOffset = headerPlusMaxIVSize - headerSize; } OutputRecord(byte type) { @@ -119,8 +138,9 @@ @Override public synchronized void reset() { super.reset(); - count = headerSize; + count = headerPlusMaxIVSize; lastHashed = count; + headerOffset = headerPlusMaxIVSize - headerSize; } /* @@ -173,58 +193,84 @@ * of sending empty records over the network. */ boolean isEmpty() { - return count == headerSize; + return count == headerPlusMaxIVSize; } /* - * Return true if the record is of a given alert. + * Return true if the record is of an alert of the given description. + * + * Per SSL/TLS specifications, alert messages convey the severity of the + * message (warning or fatal) and a description of the alert. An alert + * is defined with a two bytes struct, {byte level, byte description}, + * following after the header bytes. */ boolean isAlert(byte description) { - // An alert is defined with a two bytes struct, - // {byte level, byte description}, following after the header bytes. - if (count > (headerSize + 1) && contentType == ct_alert) { - return buf[headerSize + 1] == description; + if ((count > (headerPlusMaxIVSize + 1)) && (contentType == ct_alert)) { + return buf[headerPlusMaxIVSize + 1] == description; } return false; } /* - * Compute the MAC and append it to this record. In case we - * are automatically flushing a handshake stream, make sure we - * have hashed the message first. + * Encrypt ... length may grow due to block cipher padding, or + * message authentication code or tag. */ - void addMAC(MAC signer) throws IOException { + void encrypt(Authenticator authenticator, CipherBox box) + throws IOException { + + // In case we are automatically flushing a handshake stream, make + // sure we have hashed the message first. // // when we support compression, hashing can't go here // since it'll need to be done on the uncompressed data, // and the MAC applies to the compressed data. - // if (contentType == ct_handshake) { doHashes(); } - if (signer.MAClen() != 0) { - byte[] hash = signer.compute(contentType, buf, - headerSize, count - headerSize, false); - write(hash); + + // Requires message authentication code for stream and block + // cipher suites. + if (authenticator instanceof MAC) { + MAC signer = (MAC)authenticator; + if (signer.MAClen() != 0) { + byte[] hash = signer.compute(contentType, buf, + headerPlusMaxIVSize, count - headerPlusMaxIVSize, false); + write(hash); + } + } + + if (!box.isNullCipher()) { + // Requires explicit IV/nonce for CBC/AEAD cipher suites for + // TLS 1.1 or later. + if ((protocolVersion.v >= ProtocolVersion.TLS11.v) && + (box.isCBCMode() || box.isAEADMode())) { + byte[] nonce = box.createExplicitNonce(authenticator, + contentType, count - headerPlusMaxIVSize); + int offset = headerPlusMaxIVSize - nonce.length; + System.arraycopy(nonce, 0, buf, offset, nonce.length); + headerOffset = offset - headerSize; + } else { + headerOffset = headerPlusMaxIVSize - headerSize; + } + + // encrypt the content + int offset = headerPlusMaxIVSize; + if (!box.isAEADMode()) { + // The explicit IV can be encrypted. + offset = headerOffset + headerSize; + } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode + + count = offset + box.encrypt(buf, offset, count - offset); } } /* - * Encrypt ... length may grow due to block cipher padding - */ - void encrypt(CipherBox box) { - int len = count - headerSize; - count = headerSize + box.encrypt(buf, headerSize, len); - } - - - /* * Tell how full the buffer is ... for filling it with application or * handshake data. */ final int availableDataBytes() { - int dataSize = count - headerSize; + int dataSize = count - headerPlusMaxIVSize; return maxDataSize - dataSize; } @@ -270,11 +316,11 @@ * Don't emit content-free records. (Even change cipher spec * messages have a byte of data!) */ - if (count == headerSize) { + if (count == headerPlusMaxIVSize) { return; } - int length = count - headerSize; + int length = count - headerOffset - headerSize; // "should" really never write more than about 14 Kb... if (length < 0) { throw new SSLException("output record size too small: " @@ -299,7 +345,9 @@ */ if (firstMessage && useV2Hello()) { byte[] v3Msg = new byte[length - 4]; - System.arraycopy(buf, headerSize + 4, v3Msg, 0, v3Msg.length); + System.arraycopy(buf, headerPlusMaxIVSize + 4, + v3Msg, 0, v3Msg.length); + headerOffset = 0; // reset the header offset V3toV2ClientHello(v3Msg); handshakeHash.reset(); lastHashed = 2; @@ -314,11 +362,11 @@ /* * Fill out the header, write it and the message. */ - buf[0] = contentType; - buf[1] = protocolVersion.major; - buf[2] = protocolVersion.minor; - buf[3] = (byte)(length >> 8); - buf[4] = (byte)(length); + buf[headerOffset + 0] = contentType; + buf[headerOffset + 1] = protocolVersion.major; + buf[headerOffset + 2] = protocolVersion.minor; + buf[headerOffset + 3] = (byte)(length >> 8); + buf[headerOffset + 4] = (byte)(length); } firstMessage = false; @@ -338,7 +386,8 @@ * when holdRecord is true, the implementation in this class * will be used. */ - writeBuffer(heldRecordBuffer, buf, 0, count, debugOffset); + writeBuffer(heldRecordBuffer, + buf, headerOffset, count - headerOffset, debugOffset); } else { // It's time to send, do we have buffered data? // May or may not have a heldRecordBuffer. @@ -346,15 +395,18 @@ int heldLen = heldRecordBuffer.size(); // Ensure the capacity of this buffer. - ensureCapacity(count + heldLen); + int newCount = count + heldLen - headerOffset; + ensureCapacity(newCount); // Slide everything in the buffer to the right. - System.arraycopy(buf, 0, buf, heldLen, count); + System.arraycopy(buf, headerOffset, + buf, heldLen, count - headerOffset); // Prepend the held record to the buffer. System.arraycopy( heldRecordBuffer.toByteArray(), 0, buf, 0, heldLen); - count += heldLen; + count = newCount; + headerOffset = 0; // Clear the held buffer. heldRecordBuffer.reset(); @@ -362,7 +414,8 @@ // The held buffer has been dumped, set the debug dump offset. debugOffset = heldLen; } - writeBuffer(s, buf, 0, count, debugOffset); + writeBuffer(s, buf, headerOffset, + count - headerOffset, debugOffset); } reset(); @@ -382,12 +435,11 @@ if (debug != null && Debug.isOn("packet")) { try { HexDumpEncoder hd = new HexDumpEncoder(); - ByteBuffer bb = ByteBuffer.wrap( - buf, off + debugOffset, len - debugOffset); System.out.println("[Raw write]: length = " + - bb.remaining()); - hd.encodeBuffer(bb, System.out); + (len - debugOffset)); + hd.encodeBuffer(new ByteArrayInputStream(buf, + off + debugOffset, len - debugOffset), System.out); } catch (IOException e) { } } } @@ -400,8 +452,13 @@ return firstMessage && (helloVersion == ProtocolVersion.SSL20Hello) && (contentType == ct_handshake) - && (buf[5] == HandshakeMessage.ht_client_hello) - && (buf[headerSize + 4+2+32] == 0); // V3 session ID is empty + && (buf[headerOffset + 5] == HandshakeMessage.ht_client_hello) + // 5: recode header size + && (buf[headerPlusMaxIVSize + 4 + 2 + 32] == 0); + // V3 session ID is empty + // 4: handshake header size + // 2: client_version in ClientHello + // 32: random in ClientHello } /*
--- a/src/share/classes/sun/security/ssl/Record.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/Record.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,20 +52,29 @@ static final int trailerSize = 20; // SHA1 hash size static final int maxDataSize = 16384; // 2^14 bytes of data static final int maxPadding = 256; // block cipher padding - static final int maxIVLength = 256; // block length + static final int maxIVLength = 256; // IV length + + /* + * The size of the header plus the max IV length + */ + static final int headerPlusMaxIVSize = + headerSize // header + + maxIVLength; // iv /* * SSL has a maximum record size. It's header, (compressed) data, - * padding, and a trailer for the MAC. + * padding, and a trailer for the message authentication information (MAC + * for block and stream ciphers, and message authentication tag for AEAD + * ciphers). + * * Some compression algorithms have rare cases where they expand the data. * As we don't support compression at this time, leave that out. */ static final int maxRecordSize = - headerSize // header - + maxIVLength // iv - + maxDataSize // data - + maxPadding // padding - + trailerSize; // MAC + headerPlusMaxIVSize // header + iv + + maxDataSize // data + + maxPadding // padding + + trailerSize; // MAC or AEAD tag static final boolean enableCBCProtection = Debug.getBooleanProperty("jsse.enableCBCProtection", true); @@ -77,8 +86,7 @@ static final int maxDataSizeMinusOneByteRecord = maxDataSize // max data size - ( // max one byte record size - headerSize // header - + maxIVLength // iv + headerPlusMaxIVSize // header + iv + 1 // one byte data + maxPadding // padding + trailerSize // MAC @@ -104,11 +112,10 @@ * Allocate a smaller array. */ static final int maxAlertRecordSize = - headerSize // header - + maxIVLength // iv - + 2 // alert - + maxPadding // padding - + trailerSize; // MAC + headerPlusMaxIVSize // header + iv + + 2 // alert + + maxPadding // padding + + trailerSize; // MAC /* * The overflow values of integers of 8, 16 and 24 bits.
--- a/src/share/classes/sun/security/ssl/SSLEngineImpl.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/SSLEngineImpl.java Wed Apr 17 02:53:02 2013 -0700 @@ -280,7 +280,7 @@ /* * Crypto state that's reinitialized when the session changes. */ - private MAC readMAC, writeMAC; + private Authenticator readAuthenticator, writeAuthenticator; private CipherBox readCipher, writeCipher; // NOTE: compression state would be saved here @@ -377,9 +377,9 @@ * Note: compression support would go here too */ readCipher = CipherBox.NULL; - readMAC = MAC.NULL; + readAuthenticator = MAC.NULL; writeCipher = CipherBox.NULL; - writeMAC = MAC.NULL; + writeAuthenticator = MAC.NULL; // default security parameters for secure renegotiation secureRenegotiation = false; @@ -586,7 +586,7 @@ try { readCipher = handshaker.newReadCipher(); - readMAC = handshaker.newReadMAC(); + readAuthenticator = handshaker.newReadAuthenticator(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e); @@ -622,7 +622,7 @@ try { writeCipher = handshaker.newWriteCipher(); - writeMAC = handshaker.newWriteMAC(); + writeAuthenticator = handshaker.newWriteAuthenticator(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e); @@ -958,7 +958,8 @@ * throw a fatal alert if the integrity check fails. */ try { - decryptedBB = inputRecord.decrypt(readMAC, readCipher, readBB); + decryptedBB = inputRecord.decrypt( + readAuthenticator, readCipher, readBB); } catch (BadPaddingException e) { byte alertType = (inputRecord.contentType() == Record.ct_handshake) ? @@ -967,7 +968,6 @@ fatal(alertType, e.getMessage(), e); } - // if (!inputRecord.decompress(c)) // fatal(Alerts.alert_decompression_failure, // "decompression failure"); @@ -1117,7 +1117,7 @@ hsStatus = getHSStatus(hsStatus); if (connectionState < cs_ERROR && !isInboundDone() && (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) { - if (checkSequenceNumber(readMAC, + if (checkSequenceNumber(readAuthenticator, inputRecord.contentType())) { hsStatus = getHSStatus(null); } @@ -1270,7 +1270,7 @@ // eventually compress as well. HandshakeStatus hsStatus = - writer.writeRecord(eor, ea, writeMAC, writeCipher); + writer.writeRecord(eor, ea, writeAuthenticator, writeCipher); /* * We only need to check the sequence number state for @@ -1287,7 +1287,7 @@ hsStatus = getHSStatus(hsStatus); if (connectionState < cs_ERROR && !isOutboundDone() && (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) { - if (checkSequenceNumber(writeMAC, eor.contentType())) { + if (checkSequenceNumber(writeAuthenticator, eor.contentType())) { hsStatus = getHSStatus(null); } } @@ -1326,7 +1326,7 @@ */ void writeRecord(EngineOutputRecord eor) throws IOException { // eventually compress as well. - writer.writeRecord(eor, writeMAC, writeCipher); + writer.writeRecord(eor, writeAuthenticator, writeCipher); /* * Check the sequence number state @@ -1340,7 +1340,7 @@ * of the last record cannot be wrapped. */ if ((connectionState < cs_ERROR) && !isOutboundDone()) { - checkSequenceNumber(writeMAC, eor.contentType()); + checkSequenceNumber(writeAuthenticator, eor.contentType()); } } @@ -1358,14 +1358,14 @@ * * Return true if the handshake status may be changed. */ - private boolean checkSequenceNumber(MAC mac, byte type) + private boolean checkSequenceNumber(Authenticator authenticator, byte type) throws IOException { /* * Don't bother to check the sequence number for error or * closed connections, or NULL MAC */ - if (connectionState >= cs_ERROR || mac == MAC.NULL) { + if (connectionState >= cs_ERROR || authenticator == MAC.NULL) { return false; } @@ -1373,7 +1373,7 @@ * Conservatively, close the connection immediately when the * sequence number is close to overflow */ - if (mac.seqNumOverflow()) { + if (authenticator.seqNumOverflow()) { /* * TLS protocols do not define a error alert for sequence * number overflow. We use handshake_failure error alert @@ -1396,7 +1396,7 @@ * Don't bother to kickstart the renegotiation when the local is * asking for it. */ - if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) { + if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) { if (debug != null && Debug.isOn("ssl")) { System.out.println(Thread.currentThread().getName() + ", request renegotiation " +
--- a/src/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Apr 17 02:53:02 2013 -0700 @@ -292,7 +292,7 @@ /* * Crypto state that's reinitialized when the session changes. */ - private MAC readMAC, writeMAC; + private Authenticator readAuthenticator, writeAuthenticator; private CipherBox readCipher, writeCipher; // NOTE: compression state would be saved here @@ -586,9 +586,9 @@ * Note: compression support would go here too */ readCipher = CipherBox.NULL; - readMAC = MAC.NULL; + readAuthenticator = MAC.NULL; writeCipher = CipherBox.NULL; - writeMAC = MAC.NULL; + writeAuthenticator = MAC.NULL; // initial security parameters for secure renegotiation secureRenegotiation = false; @@ -829,8 +829,7 @@ boolean holdRecord) throws IOException { // r.compress(c); - r.addMAC(writeMAC); - r.encrypt(writeCipher); + r.encrypt(writeAuthenticator, writeCipher); if (holdRecord) { // If we were requested to delay the record due to possibility @@ -861,7 +860,7 @@ * of the last record cannot be wrapped. */ if (connectionState < cs_ERROR) { - checkSequenceNumber(writeMAC, r.contentType()); + checkSequenceNumber(writeAuthenticator, r.contentType()); } // turn off the flag of the first application record @@ -986,7 +985,7 @@ * throw a fatal alert if the integrity check fails. */ try { - r.decrypt(readMAC, readCipher); + r.decrypt(readAuthenticator, readCipher); } catch (BadPaddingException e) { byte alertType = (r.contentType() == Record.ct_handshake) ? Alerts.alert_handshake_failure @@ -1143,7 +1142,7 @@ * of the last record cannot be wrapped. */ if (connectionState < cs_ERROR) { - checkSequenceNumber(readMAC, r.contentType()); + checkSequenceNumber(readAuthenticator, r.contentType()); } return; @@ -1166,14 +1165,14 @@ * implementation would need to wrap a sequence number, it must * renegotiate instead." */ - private void checkSequenceNumber(MAC mac, byte type) + private void checkSequenceNumber(Authenticator authenticator, byte type) throws IOException { /* * Don't bother to check the sequence number for error or * closed connections, or NULL MAC. */ - if (connectionState >= cs_ERROR || mac == MAC.NULL) { + if (connectionState >= cs_ERROR || authenticator == MAC.NULL) { return; } @@ -1181,7 +1180,7 @@ * Conservatively, close the connection immediately when the * sequence number is close to overflow */ - if (mac.seqNumOverflow()) { + if (authenticator.seqNumOverflow()) { /* * TLS protocols do not define a error alert for sequence * number overflow. We use handshake_failure error alert @@ -1203,7 +1202,7 @@ * Don't bother to kickstart the renegotiation when the local is * asking for it. */ - if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) { + if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) { if (debug != null && Debug.isOn("ssl")) { System.out.println(Thread.currentThread().getName() + ", request renegotiation " + @@ -2065,7 +2064,7 @@ try { readCipher = handshaker.newReadCipher(); - readMAC = handshaker.newReadMAC(); + readAuthenticator = handshaker.newReadAuthenticator(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e); @@ -2096,7 +2095,7 @@ try { writeCipher = handshaker.newWriteCipher(); - writeMAC = handshaker.newWriteMAC(); + writeAuthenticator = handshaker.newWriteAuthenticator(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e);
--- a/src/share/lib/security/java.security-linux Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/lib/security/java.security-linux Wed Apr 17 02:53:02 2013 -0700 @@ -76,26 +76,57 @@ security.provider.9=sun.security.smartcardio.SunPCSC # -# Select the source of seed data for SecureRandom. By default an -# attempt is made to use the entropy gathering device specified by -# the securerandom.source property. If an exception occurs when -# accessing the URL then the traditional system/thread activity -# algorithm is used. +# Sun Provider SecureRandom seed source. +# +# Select the primary source of seed data for the "SHA1PRNG" and +# "NativePRNG" SecureRandom implementations in the "Sun" provider. +# (Other SecureRandom implementations might also use this property.) +# +# On Unix-like systems (for example, Solaris/Linux/MacOS), the +# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from +# special device files such as file:/dev/random. # -# On Solaris and Linux systems, if file:/dev/urandom is specified and it -# exists, a special SecureRandom implementation is activated by default. -# This "NativePRNG" reads random bytes directly from /dev/urandom. +# On Windows systems, specifying the URLs "file:/dev/random" or +# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding +# mechanism for SHA1PRNG. +# +# By default, an attempt is made to use the entropy gathering device +# specified by the "securerandom.source" Security property. If an +# exception occurs while accessing the specified URL: +# +# SHA1PRNG: +# the traditional system/thread activity algorithm will be used. +# +# NativePRNG: +# a default value of /dev/random will be used. If neither +# are available, the implementation will be disabled. +# "file" is the only currently supported protocol type. # -# On Windows systems, the URLs file:/dev/random and file:/dev/urandom -# enables use of the Microsoft CryptoAPI seed functionality. +# The entropy gathering device can also be specified with the System +# property "java.security.egd". For example: +# +# % java -Djava.security.egd=file:/dev/random MainClass # -securerandom.source=file:/dev/urandom +# Specifying this System property will override the +# "securerandom.source" Security property. +# +# In addition, if "file:/dev/random" or "file:/dev/urandom" is +# specified, the "NativePRNG" implementation will be more preferred than +# SHA1PRNG in the Sun provider. # -# The entropy gathering device is described as a URL and can also -# be specified with the system property "java.security.egd". For example, -# -Djava.security.egd=file:/dev/urandom -# Specifying this system property will override the securerandom.source -# setting. +securerandom.source=file:/dev/random + +# +# A list of known strong SecureRandom implementations. +# +# To help guide applications in selecting a suitable strong +# java.security.SecureRandom implementation, Java distributions should +# indicate a list of known strong implementations using the property. +# +# This is a comma-separated list of algorithm and/or algorithm:provider +# entries. +# +securerandom.strongAlgorithms=NativePRNGBlocking:SUN # # Class to instantiate as the javax.security.auth.login.Configuration
--- a/src/share/lib/security/java.security-macosx Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/lib/security/java.security-macosx Wed Apr 17 02:53:02 2013 -0700 @@ -77,26 +77,57 @@ security.provider.10=apple.security.AppleProvider # -# Select the source of seed data for SecureRandom. By default an -# attempt is made to use the entropy gathering device specified by -# the securerandom.source property. If an exception occurs when -# accessing the URL then the traditional system/thread activity -# algorithm is used. +# Sun Provider SecureRandom seed source. +# +# Select the primary source of seed data for the "SHA1PRNG" and +# "NativePRNG" SecureRandom implementations in the "Sun" provider. +# (Other SecureRandom implementations might also use this property.) +# +# On Unix-like systems (for example, Solaris/Linux/MacOS), the +# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from +# special device files such as file:/dev/random. # -# On Solaris and Linux systems, if file:/dev/urandom is specified and it -# exists, a special SecureRandom implementation is activated by default. -# This "NativePRNG" reads random bytes directly from /dev/urandom. +# On Windows systems, specifying the URLs "file:/dev/random" or +# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding +# mechanism for SHA1PRNG. +# +# By default, an attempt is made to use the entropy gathering device +# specified by the "securerandom.source" Security property. If an +# exception occurs while accessing the specified URL: +# +# SHA1PRNG: +# the traditional system/thread activity algorithm will be used. +# +# NativePRNG: +# a default value of /dev/random will be used. If neither +# are available, the implementation will be disabled. +# "file" is the only currently supported protocol type. # -# On Windows systems, the URLs file:/dev/random and file:/dev/urandom -# enables use of the Microsoft CryptoAPI seed functionality. +# The entropy gathering device can also be specified with the System +# property "java.security.egd". For example: +# +# % java -Djava.security.egd=file:/dev/random MainClass # -securerandom.source=file:/dev/urandom +# Specifying this System property will override the +# "securerandom.source" Security property. +# +# In addition, if "file:/dev/random" or "file:/dev/urandom" is +# specified, the "NativePRNG" implementation will be more preferred than +# SHA1PRNG in the Sun provider. # -# The entropy gathering device is described as a URL and can also -# be specified with the system property "java.security.egd". For example, -# -Djava.security.egd=file:/dev/urandom -# Specifying this system property will override the securerandom.source -# setting. +securerandom.source=file:/dev/random + +# +# A list of known strong SecureRandom implementations. +# +# To help guide applications in selecting a suitable strong +# java.security.SecureRandom implementation, Java distributions should +# indicate a list of known strong implementations using the property. +# +# This is a comma-separated list of algorithm and/or algorithm:provider +# entries. +# +securerandom.strongAlgorithms=NativePRNGBlocking:SUN # # Class to instantiate as the javax.security.auth.login.Configuration
--- a/src/share/lib/security/java.security-solaris Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/lib/security/java.security-solaris Wed Apr 17 02:53:02 2013 -0700 @@ -78,26 +78,57 @@ security.provider.11=sun.security.smartcardio.SunPCSC # -# Select the source of seed data for SecureRandom. By default an -# attempt is made to use the entropy gathering device specified by -# the securerandom.source property. If an exception occurs when -# accessing the URL then the traditional system/thread activity -# algorithm is used. +# Sun Provider SecureRandom seed source. +# +# Select the primary source of seed data for the "SHA1PRNG" and +# "NativePRNG" SecureRandom implementations in the "Sun" provider. +# (Other SecureRandom implementations might also use this property.) +# +# On Unix-like systems (for example, Solaris/Linux/MacOS), the +# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from +# special device files such as file:/dev/random. # -# On Solaris and Linux systems, if file:/dev/urandom is specified and it -# exists, a special SecureRandom implementation is activated by default. -# This "NativePRNG" reads random bytes directly from /dev/urandom. +# On Windows systems, specifying the URLs "file:/dev/random" or +# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding +# mechanism for SHA1PRNG. +# +# By default, an attempt is made to use the entropy gathering device +# specified by the "securerandom.source" Security property. If an +# exception occurs while accessing the specified URL: +# +# SHA1PRNG: +# the traditional system/thread activity algorithm will be used. +# +# NativePRNG: +# a default value of /dev/random will be used. If neither +# are available, the implementation will be disabled. +# "file" is the only currently supported protocol type. # -# On Windows systems, the URLs file:/dev/random and file:/dev/urandom -# enables use of the Microsoft CryptoAPI seed functionality. +# The entropy gathering device can also be specified with the System +# property "java.security.egd". For example: +# +# % java -Djava.security.egd=file:/dev/random MainClass # -securerandom.source=file:/dev/urandom +# Specifying this System property will override the +# "securerandom.source" Security property. +# +# In addition, if "file:/dev/random" or "file:/dev/urandom" is +# specified, the "NativePRNG" implementation will be more preferred than +# SHA1PRNG in the Sun provider. # -# The entropy gathering device is described as a URL and can also -# be specified with the system property "java.security.egd". For example, -# -Djava.security.egd=file:/dev/urandom -# Specifying this system property will override the securerandom.source -# setting. +securerandom.source=file:/dev/random + +# +# A list of known strong SecureRandom implementations. +# +# To help guide applications in selecting a suitable strong +# java.security.SecureRandom implementation, Java distributions should +# indicate a list of known strong implementations using the property. +# +# This is a comma-separated list of algorithm and/or algorithm:provider +# entries. +# +securerandom.strongAlgorithms=NativePRNGBlocking:SUN # # Class to instantiate as the javax.security.auth.login.Configuration @@ -453,4 +484,4 @@ # # Example: # jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048 -i +
--- a/src/share/lib/security/java.security-windows Wed Apr 17 01:04:45 2013 -0700 +++ b/src/share/lib/security/java.security-windows Wed Apr 17 02:53:02 2013 -0700 @@ -77,26 +77,57 @@ security.provider.10=sun.security.mscapi.SunMSCAPI # -# Select the source of seed data for SecureRandom. By default an -# attempt is made to use the entropy gathering device specified by -# the securerandom.source property. If an exception occurs when -# accessing the URL then the traditional system/thread activity -# algorithm is used. +# Sun Provider SecureRandom seed source. +# +# Select the primary source of seed data for the "SHA1PRNG" and +# "NativePRNG" SecureRandom implementations in the "Sun" provider. +# (Other SecureRandom implementations might also use this property.) +# +# On Unix-like systems (for example, Solaris/Linux/MacOS), the +# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from +# special device files such as file:/dev/random. # -# On Solaris and Linux systems, if file:/dev/urandom is specified and it -# exists, a special SecureRandom implementation is activated by default. -# This "NativePRNG" reads random bytes directly from /dev/urandom. +# On Windows systems, specifying the URLs "file:/dev/random" or +# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding +# mechanism for SHA1PRNG. +# +# By default, an attempt is made to use the entropy gathering device +# specified by the "securerandom.source" Security property. If an +# exception occurs while accessing the specified URL: +# +# SHA1PRNG: +# the traditional system/thread activity algorithm will be used. +# +# NativePRNG: +# a default value of /dev/random will be used. If neither +# are available, the implementation will be disabled. +# "file" is the only currently supported protocol type. # -# On Windows systems, the URLs file:/dev/random and file:/dev/urandom -# enables use of the Microsoft CryptoAPI seed functionality. +# The entropy gathering device can also be specified with the System +# property "java.security.egd". For example: +# +# % java -Djava.security.egd=file:/dev/random MainClass # -securerandom.source=file:/dev/urandom +# Specifying this System property will override the +# "securerandom.source" Security property. +# +# In addition, if "file:/dev/random" or "file:/dev/urandom" is +# specified, the "NativePRNG" implementation will be more preferred than +# SHA1PRNG in the Sun provider. # -# The entropy gathering device is described as a URL and can also -# be specified with the system property "java.security.egd". For example, -# -Djava.security.egd=file:/dev/urandom -# Specifying this system property will override the securerandom.source -# setting. +securerandom.source=file:/dev/random + +# +# A list of known strong SecureRandom implementations. +# +# To help guide applications in selecting a suitable strong +# java.security.SecureRandom implementation, Java distributions should +# indicate a list of known strong implementations using the property. +# +# This is a comma-separated list of algorithm and/or algorithm:provider +# entries. +# +securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI # # Class to instantiate as the javax.security.auth.login.Configuration
--- a/src/solaris/classes/sun/security/provider/NativePRNG.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/solaris/classes/sun/security/provider/NativePRNG.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,34 +26,47 @@ package sun.security.provider; import java.io.*; - +import java.net.*; import java.security.*; -import java.security.SecureRandom; +import sun.security.util.Debug; /** - * Native PRNG implementation for Solaris/Linux. It interacts with - * /dev/random and /dev/urandom, so it is only available if those - * files are present. Otherwise, SHA1PRNG is used instead of this class. - * - * getSeed() and setSeed() directly read/write /dev/random. However, - * /dev/random is only writable by root in many configurations. Because - * we cannot just ignore bytes specified via setSeed(), we keep a - * SHA1PRNG around in parallel. - * - * nextBytes() reads the bytes directly from /dev/urandom (and then - * mixes them with bytes from the SHA1PRNG for the reasons explained - * above). Reading bytes from /dev/urandom means that constantly get - * new entropy the operating system has collected. This is a notable - * advantage over the SHA1PRNG model, which acquires entropy only - * initially during startup although the VM may be running for months. - * - * Also note that we do not need any initial pure random seed from - * /dev/random. This is an advantage because on some versions of Linux - * it can be exhausted very quickly and could thus impact startup time. - * + * Native PRNG implementation for Solaris/Linux/MacOS. + * <p> + * It obtains seed and random numbers by reading system files such as + * the special device files /dev/random and /dev/urandom. This + * implementation respects the {@code securerandom.source} Security + * property and {@code java.security.egd} System property for obtaining + * seed material. If the file specified by the properties does not + * exist, /dev/random is the default seed source. /dev/urandom is + * the default source of random numbers. + * <p> + * On some Unix platforms, /dev/random may block until enough entropy is + * available, but that may negatively impact the perceived startup + * time. By selecting these sources, this implementation tries to + * strike a balance between performance and security. + * <p> + * generateSeed() and setSeed() attempt to directly read/write to the seed + * source. However, this file may only be writable by root in many + * configurations. Because we cannot just ignore bytes specified via + * setSeed(), we keep a SHA1PRNG around in parallel. + * <p> + * nextBytes() reads the bytes directly from the source of random + * numbers (and then mixes them with bytes from the SHA1PRNG for the + * reasons explained above). Reading bytes from the random generator means + * that we are generally getting entropy from the operating system. This + * is a notable advantage over the SHA1PRNG model, which acquires + * entropy only initially during startup although the VM may be running + * for months. + * <p> + * Also note for nextBytes() that we do not need any initial pure random + * seed from /dev/random. This is an advantage because on some versions + * of Linux entropy can be exhausted very quickly and could thus impact + * startup time. + * <p> * Finally, note that we use a singleton for the actual work (RandomIO) * to avoid having to open and close /dev/[u]random constantly. However, - * there may me many NativePRNG instances created by the JCA framework. + * there may be many NativePRNG instances created by the JCA framework. * * @since 1.5 * @author Andreas Sterbenz @@ -62,32 +75,121 @@ private static final long serialVersionUID = -6599091113397072932L; + private static final Debug debug = Debug.getInstance("provider"); + // name of the pure random file (also used for setSeed()) private static final String NAME_RANDOM = "/dev/random"; // name of the pseudo random file private static final String NAME_URANDOM = "/dev/urandom"; + // which kind of RandomIO object are we creating? + private enum Variant { + MIXED, BLOCKING, NONBLOCKING + } + // singleton instance or null if not available - private static final RandomIO INSTANCE = initIO(); + private static final RandomIO INSTANCE = initIO(Variant.MIXED); - private static RandomIO initIO() { - return AccessController.doPrivileged( - new PrivilegedAction<RandomIO>() { - public RandomIO run() { - File randomFile = new File(NAME_RANDOM); - if (randomFile.exists() == false) { + /** + * Get the System egd source (if defined). We only allow "file:" + * URLs for now. If there is a egd value, parse it. + * + * @return the URL or null if not available. + */ + private static URL getEgdUrl() { + // This will return "" if nothing was set. + String egdSource = SunEntries.getSeedSource(); + URL egdUrl; + + if (egdSource.length() != 0) { + if (debug != null) { + debug.println("NativePRNG egdUrl: " + egdSource); + } + try { + egdUrl = new URL(egdSource); + if (!egdUrl.getProtocol().equalsIgnoreCase("file")) { return null; } - File urandomFile = new File(NAME_URANDOM); - if (urandomFile.exists() == false) { - return null; + } catch (MalformedURLException e) { + return null; + } + } else { + egdUrl = null; + } + + return egdUrl; + } + + /** + * Create a RandomIO object for all I/O of this Variant type. + */ + private static RandomIO initIO(final Variant v) { + return AccessController.doPrivileged( + new PrivilegedAction<RandomIO>() { + @Override + public RandomIO run() { + + File seedFile; + File nextFile; + + switch(v) { + case MIXED: + URL egdUrl; + File egdFile = null; + + if ((egdUrl = getEgdUrl()) != null) { + try { + egdFile = SunEntries.getDeviceFile(egdUrl); + } catch (IOException e) { + // Swallow, seedFile is still null + } + } + + // Try egd first. + if ((egdFile != null) && egdFile.canRead()) { + seedFile = egdFile; + } else { + // fall back to /dev/random. + seedFile = new File(NAME_RANDOM); + } + nextFile = new File(NAME_URANDOM); + break; + + case BLOCKING: + seedFile = new File(NAME_RANDOM); + nextFile = new File(NAME_RANDOM); + break; + + case NONBLOCKING: + seedFile = new File(NAME_URANDOM); + nextFile = new File(NAME_URANDOM); + break; + + default: + // Shouldn't happen! + return null; + } + + if (debug != null) { + debug.println("NativePRNG." + v + + " seedFile: " + seedFile + + " nextFile: " + nextFile); + } + + if (!seedFile.canRead() || !nextFile.canRead()) { + if (debug != null) { + debug.println("NativePRNG." + v + + " Couldn't read Files."); + } + return null; + } + + try { + return new RandomIO(seedFile, nextFile); + } catch (Exception e) { + return null; + } } - try { - return new RandomIO(randomFile, urandomFile); - } catch (Exception e) { - return null; - } - } }); } @@ -105,67 +207,173 @@ } // set the seed + @Override protected void engineSetSeed(byte[] seed) { INSTANCE.implSetSeed(seed); } // get pseudo random bytes + @Override protected void engineNextBytes(byte[] bytes) { INSTANCE.implNextBytes(bytes); } // get true random bytes + @Override protected byte[] engineGenerateSeed(int numBytes) { return INSTANCE.implGenerateSeed(numBytes); } /** + * A NativePRNG-like class that uses /dev/random for both + * seed and random material. + * + * Note that it does not respect the egd properties, since we have + * no way of knowing what those qualities are. + * + * This is very similar to the outer NativePRNG class, minimizing any + * breakage to the serialization of the existing implementation. + * + * @since 1.8 + */ + public static final class Blocking extends SecureRandomSpi { + private static final long serialVersionUID = -6396183145759983347L; + + private static final RandomIO INSTANCE = initIO(Variant.BLOCKING); + + // return whether this is available + static boolean isAvailable() { + return INSTANCE != null; + } + + // constructor, called by the JCA framework + public Blocking() { + super(); + if (INSTANCE == null) { + throw new AssertionError("NativePRNG$Blocking not available"); + } + } + + // set the seed + @Override + protected void engineSetSeed(byte[] seed) { + INSTANCE.implSetSeed(seed); + } + + // get pseudo random bytes + @Override + protected void engineNextBytes(byte[] bytes) { + INSTANCE.implNextBytes(bytes); + } + + // get true random bytes + @Override + protected byte[] engineGenerateSeed(int numBytes) { + return INSTANCE.implGenerateSeed(numBytes); + } + } + + /** + * A NativePRNG-like class that uses /dev/urandom for both + * seed and random material. + * + * Note that it does not respect the egd properties, since we have + * no way of knowing what those qualities are. + * + * This is very similar to the outer NativePRNG class, minimizing any + * breakage to the serialization of the existing implementation. + * + * @since 1.8 + */ + public static final class NonBlocking extends SecureRandomSpi { + private static final long serialVersionUID = -1102062982994105487L; + + private static final RandomIO INSTANCE = initIO(Variant.NONBLOCKING); + + // return whether this is available + static boolean isAvailable() { + return INSTANCE != null; + } + + // constructor, called by the JCA framework + public NonBlocking() { + super(); + if (INSTANCE == null) { + throw new AssertionError( + "NativePRNG$NonBlocking not available"); + } + } + + // set the seed + @Override + protected void engineSetSeed(byte[] seed) { + INSTANCE.implSetSeed(seed); + } + + // get pseudo random bytes + @Override + protected void engineNextBytes(byte[] bytes) { + INSTANCE.implNextBytes(bytes); + } + + // get true random bytes + @Override + protected byte[] engineGenerateSeed(int numBytes) { + return INSTANCE.implGenerateSeed(numBytes); + } + } + + /** * Nested class doing the actual work. Singleton, see INSTANCE above. */ private static class RandomIO { - // we buffer data we read from /dev/urandom for efficiency, + // we buffer data we read from the "next" file for efficiency, // but we limit the lifetime to avoid using stale bits // lifetime in ms, currently 100 ms (0.1 s) private final static long MAX_BUFFER_TIME = 100; - // size of the /dev/urandom buffer + // size of the "next" buffer private final static int BUFFER_SIZE = 32; - // In/OutputStream for /dev/random and /dev/urandom - private final InputStream randomIn, urandomIn; - private OutputStream randomOut; + // Holder for the seedFile. Used if we ever add seed material. + File seedFile; - // flag indicating if we have tried to open randomOut yet - private boolean randomOutInitialized; + // In/OutputStream for "seed" and "next" + private final InputStream seedIn, nextIn; + private OutputStream seedOut; + + // flag indicating if we have tried to open seedOut yet + private boolean seedOutInitialized; // SHA1PRNG instance for mixing // initialized lazily on demand to avoid problems during startup private volatile sun.security.provider.SecureRandom mixRandom; - // buffer for /dev/urandom bits - private final byte[] urandomBuffer; + // buffer for next bits + private final byte[] nextBuffer; - // number of bytes left in urandomBuffer + // number of bytes left in nextBuffer private int buffered; - // time we read the data into the urandomBuffer + // time we read the data into the nextBuffer private long lastRead; // mutex lock for nextBytes() private final Object LOCK_GET_BYTES = new Object(); - // mutex lock for getSeed() + // mutex lock for generateSeed() private final Object LOCK_GET_SEED = new Object(); // mutex lock for setSeed() private final Object LOCK_SET_SEED = new Object(); // constructor, called only once from initIO() - private RandomIO(File randomFile, File urandomFile) throws IOException { - randomIn = new FileInputStream(randomFile); - urandomIn = new FileInputStream(urandomFile); - urandomBuffer = new byte[BUFFER_SIZE]; + private RandomIO(File seedFile, File nextFile) throws IOException { + this.seedFile = seedFile; + seedIn = new FileInputStream(seedFile); + nextIn = new FileInputStream(nextFile); + nextBuffer = new byte[BUFFER_SIZE]; } // get the SHA1PRNG for mixing @@ -179,7 +387,7 @@ r = new sun.security.provider.SecureRandom(); try { byte[] b = new byte[20]; - readFully(urandomIn, b); + readFully(nextIn, b); r.engineSetSeed(b); } catch (IOException e) { throw new ProviderException("init failed", e); @@ -192,7 +400,7 @@ } // read data.length bytes from in - // /dev/[u]random are not normal files, so we need to loop the read. + // These are not normal files, so we need to loop the read. // just keep trying as long as we are making progress private static void readFully(InputStream in, byte[] data) throws IOException { @@ -201,22 +409,22 @@ while (len > 0) { int k = in.read(data, ofs, len); if (k <= 0) { - throw new EOFException("/dev/[u]random closed?"); + throw new EOFException("File(s) closed?"); } ofs += k; len -= k; } if (len > 0) { - throw new IOException("Could not read from /dev/[u]random"); + throw new IOException("Could not read from file(s)"); } } - // get true random bytes, just read from /dev/random + // get true random bytes, just read from "seed" private byte[] implGenerateSeed(int numBytes) { synchronized (LOCK_GET_SEED) { try { byte[] b = new byte[numBytes]; - readFully(randomIn, b); + readFully(seedIn, b); return b; } catch (IOException e) { throw new ProviderException("generateSeed() failed", e); @@ -225,26 +433,27 @@ } // supply random bytes to the OS - // write to /dev/random if possible + // write to "seed" if possible // always add the seed to our mixing random private void implSetSeed(byte[] seed) { synchronized (LOCK_SET_SEED) { - if (randomOutInitialized == false) { - randomOutInitialized = true; - randomOut = AccessController.doPrivileged( + if (seedOutInitialized == false) { + seedOutInitialized = true; + seedOut = AccessController.doPrivileged( new PrivilegedAction<OutputStream>() { + @Override public OutputStream run() { try { - return new FileOutputStream(NAME_RANDOM, true); + return new FileOutputStream(seedFile, true); } catch (Exception e) { return null; } } }); } - if (randomOut != null) { + if (seedOut != null) { try { - randomOut.write(seed); + seedOut.write(seed); } catch (IOException e) { throw new ProviderException("setSeed() failed", e); } @@ -261,12 +470,12 @@ return; } lastRead = time; - readFully(urandomIn, urandomBuffer); - buffered = urandomBuffer.length; + readFully(nextIn, nextBuffer); + buffered = nextBuffer.length; } // get pseudo random bytes - // read from /dev/urandom and XOR with bytes generated by the + // read from "next" and XOR with bytes generated by the // mixing SHA1PRNG private void implNextBytes(byte[] data) { synchronized (LOCK_GET_BYTES) { @@ -276,9 +485,9 @@ int ofs = 0; while (len > 0) { ensureBufferValid(); - int bufferOfs = urandomBuffer.length - buffered; + int bufferOfs = nextBuffer.length - buffered; while ((len > 0) && (buffered > 0)) { - data[ofs++] ^= urandomBuffer[bufferOfs++]; + data[ofs++] ^= nextBuffer[bufferOfs++]; len--; buffered--; } @@ -288,7 +497,5 @@ } } } - } - }
--- a/src/solaris/classes/sun/security/provider/NativeSeedGenerator.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/solaris/classes/sun/security/provider/NativeSeedGenerator.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,8 @@ */ class NativeSeedGenerator extends SeedGenerator.URLSeedGenerator { - NativeSeedGenerator() throws IOException { - super(); + NativeSeedGenerator(String seedFile) throws IOException { + super(seedFile); } }
--- a/src/windows/classes/sun/security/mscapi/PRNG.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/windows/classes/sun/security/mscapi/PRNG.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,6 +58,7 @@ * * @param seed the seed. */ + @Override protected void engineSetSeed(byte[] seed) { if (seed != null) { generateSeed(-1, seed); @@ -69,6 +70,7 @@ * * @param bytes the array to be filled in with random bytes. */ + @Override protected void engineNextBytes(byte[] bytes) { if (bytes != null) { if (generateSeed(0, bytes) == null) { @@ -85,6 +87,7 @@ * * @return the seed bytes. */ + @Override protected byte[] engineGenerateSeed(int numBytes) { byte[] seed = generateSeed(numBytes, null);
--- a/src/windows/classes/sun/security/provider/NativePRNG.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/windows/classes/sun/security/provider/NativePRNG.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,4 +39,15 @@ return false; } + public static final class NonBlocking { + static boolean isAvailable() { + return false; + } + } + + public static final class Blocking { + static boolean isAvailable() { + return false; + } + } }
--- a/src/windows/classes/sun/security/provider/NativeSeedGenerator.java Wed Apr 17 01:04:45 2013 -0700 +++ b/src/windows/classes/sun/security/provider/NativeSeedGenerator.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,8 @@ * @exception IOException if CryptoAPI seeds are not available * on this platform. */ - NativeSeedGenerator() throws IOException { + NativeSeedGenerator(String seedFile) throws IOException { + // seedFile is ignored. super(); // try generating two random bytes to see if CAPI is available if (!nativeGenerateSeed(new byte[2])) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8001596 + * @summary Incorrect condition check in PBKDF2KeyImpl.java + */ + +import java.security.*; +import java.security.spec.*; +import javax.crypto.*; +import javax.crypto.spec.*; +import java.lang.reflect.*; + +public class NegativeLength { + + public static void main(String[] args) throws Exception { + SecretKeyFactory skf = SecretKeyFactory.getInstance( + "PBKDF2WithHmacSHA1", "SunJCE"); + + // Create a valid PBEKeySpec + PBEKeySpec pbeks = new PBEKeySpec( + new char['p'], new byte[1], 1024, 8); + + // Use reflection to set it negative. + Class c = pbeks.getClass(); + Field f = c.getDeclaredField("keyLength"); + f.setAccessible(true); + f.setInt(pbeks, -8); + + System.out.println("pbeks.getKeyLength(): " + pbeks.getKeyLength()); + + try { + + // A negative length is clearly wrong, we should get a + // InvalidKeySpecException. Anything else is wrong. + skf.generateSecret(pbeks); + throw new Exception("We shouldn't get here."); + } catch (InvalidKeySpecException ike) { + // swallow, this is the exception we want. + System.out.println("Test Passed."); + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/com/sun/crypto/provider/Cipher/UTIL/SunJCEGetInstance.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7171982 + * @summary Test that SunJCE.getInstance() is retrieving a provider when + * SunJCE has been removed from the provider list. + * @run main/othervm SunJCEGetInstance + */ + +import java.security.Security; +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; + + +public class SunJCEGetInstance { + public static void main(String[] args) throws Exception { + Cipher jce; + + try{ + // Remove SunJCE from Provider list + Security.removeProvider("SunJCE"); + + // Create our own instance of SunJCE provider. Purposefully not + // using SunJCE.getInstance() so we can have our own instance + // for the test. + jce = Cipher.getInstance("AES/CBC/PKCS5Padding", + new com.sun.crypto.provider.SunJCE()); + + jce.init(Cipher.ENCRYPT_MODE, + new SecretKeySpec("1234567890abcedf".getBytes(), "AES")); + jce.doFinal("PlainText".getBytes()); + } catch (Exception e) { + System.err.println("Setup failure: "); + throw e; + } + + // Get parameters which will call SunJCE.getInstance(). Failure + // would occur on this line. + try { + jce.getParameters().getEncoded(); + + } catch (Exception e) { + System.err.println("Test Failure"); + throw e; + } + System.out.println("Passed"); + } +}
--- a/test/sun/security/ec/TestEC.java Wed Apr 17 01:04:45 2013 -0700 +++ b/test/sun/security/ec/TestEC.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,11 @@ * questions. */ +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + /** * @test * @bug 6840752 @@ -30,7 +35,7 @@ * @library ../pkcs11/sslecc * @library ../../../java/security/testlibrary * @compile -XDignore.symbol.file TestEC.java - * @run main TestEC + * @run main/othervm TestEC */ import java.security.NoSuchProviderException;
--- a/test/sun/security/pkcs11/fips/CipherTest.java Wed Apr 17 01:04:45 2013 -0700 +++ b/test/sun/security/pkcs11/fips/CipherTest.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -147,6 +147,25 @@ CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF), CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF), + CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + + CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + + CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + // cipher suites obsoleted since TLS 1.2 CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303),
--- a/test/sun/security/pkcs11/sslecc/CipherTest.java Wed Apr 17 01:04:45 2013 -0700 +++ b/test/sun/security/pkcs11/sslecc/CipherTest.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -147,6 +147,25 @@ CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF), CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF), + CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + + CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + + CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + // cipher suites obsoleted since TLS 1.2 CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303),
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/provider/SecureRandom/StrongSecureRandom.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 6425477 + * @summary Better support for generation of high entropy random numbers + * @run main/othervm StrongSecureRandom + */ +import java.security.*; +import java.util.*; + +/** + * This test assumes that the standard Sun providers are installed. + */ +public class StrongSecureRandom { + + private static String os = System.getProperty("os.name", "unknown"); + + private static void testDefaultEgd() throws Exception { + // No SecurityManager installed. + String s = Security.getProperty("securerandom.source"); + + System.out.println("Testing: default EGD: " + s); + if (!s.equals("file:/dev/random")) { + throw new Exception("Default is not 'file:/dev/random'"); + } + } + + private static void testSHA1PRNGImpl() throws Exception { + SecureRandom sr; + byte[] ba; + + String urandom = "file:/dev/urandom"; + + System.out.println("Testing new SeedGenerator and EGD"); + + Security.setProperty("securerandom.source", urandom); + if (!Security.getProperty("securerandom.source").equals(urandom)) { + throw new Exception("Couldn't set securerandom.source"); + } + + /* + * Take out a large number of bytes in hopes of blocking. + * Don't expect this to happen, unless something is broken on Linux + */ + sr = SecureRandom.getInstance("SHA1PRNG"); + if (!sr.getAlgorithm().equals("SHA1PRNG")) { + throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm()); + } + + ba = sr.generateSeed(4096); + sr.nextBytes(ba); + sr.setSeed(ba); + } + + private static void testNativePRNGImpls() throws Exception { + SecureRandom sr; + byte[] ba; + + System.out.println("Testing new NativePRNGImpls"); + + if (os.startsWith("Windows")) { + System.out.println("Skip windows testing."); + return; + } + + System.out.println(" Testing regular"); + sr = SecureRandom.getInstance("NativePRNG"); + if (!sr.getAlgorithm().equals("NativePRNG")) { + throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm()); + } + ba = sr.generateSeed(1); + sr.nextBytes(ba); + sr.setSeed(ba); + + System.out.println(" Testing NonBlocking"); + sr = SecureRandom.getInstance("NativePRNGNonBlocking"); + if (!sr.getAlgorithm().equals("NativePRNGNonBlocking")) { + throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm()); + } + ba = sr.generateSeed(1); + sr.nextBytes(ba); + sr.setSeed(ba); + + if (os.equals("Linux")) { + System.out.println("Skip Linux blocking test."); + return; + } + + System.out.println(" Testing Blocking"); + sr = SecureRandom.getInstance("NativePRNGBlocking"); + if (!sr.getAlgorithm().equals("NativePRNGBlocking")) { + throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm()); + } + ba = sr.generateSeed(1); + sr.nextBytes(ba); + sr.setSeed(ba); + } + + private static void testStrongInstance(boolean expected) throws Exception { + + boolean result = (SecureRandom.getStrongSecureRandom() != null); + + if (expected != result) { + throw new Exception("Received: " + result); + } + } + + /* + * This test assumes that the standard providers are installed. + */ + private static void testProperty(String property, boolean expected) + throws Exception { + + System.out.println("Testing: '" + property + "' " + expected); + + Security.setProperty("securerandom.strongAlgorithms", property); + testStrongInstance(expected); + } + + private static void testProperties() throws Exception { + // Sets securerandom.strongAlgorithms, and then tests various combos. + testProperty("", false); + + testProperty("SHA1PRNG", true); + testProperty(" SHA1PRNG", true); + testProperty("SHA1PRNG ", true); + testProperty(" SHA1PRNG ", true); + + // Impls are case-insenstive, providers are sensitive. + testProperty("SHA1PRNG:SUN", true); + testProperty("Sha1PRNG:SUN", true); + testProperty("SHA1PRNG:Sun", false); + + testProperty(" SHA1PRNG:SUN", true); + testProperty("SHA1PRNG:SUN ", true); + testProperty(" SHA1PRNG:SUN ", true); + + testProperty(" SHA1PRNG:SUn", false); + testProperty("SHA1PRNG:SUn ", false); + testProperty(" SHA1PRNG:SUn ", false); + + testProperty(",,,SHA1PRNG", true); + testProperty(",,, SHA1PRNG", true); + testProperty(" , , ,SHA1PRNG ", true); + + testProperty(",,,, SHA1PRNG ,,,", true); + testProperty(",,,, SHA1PRNG:SUN ,,,", true); + testProperty(",,,, SHA1PRNG:SUn ,,,", false); + + testProperty(",,,SHA1PRNG:Sun,, SHA1PRNG:SUN", true); + testProperty(",,,Sha1PRNG:Sun, SHA1PRNG:SUN", true); + testProperty(" SHA1PRNG:Sun, Sha1PRNG:Sun,,,,Sha1PRNG:SUN", true); + + testProperty(",,,SHA1PRNG:Sun,, SHA1PRNG:SUn", false); + testProperty(",,,Sha1PRNG:Sun, SHA1PRNG:SUn", false); + testProperty(" SHA1PRNG:Sun, Sha1PRNG:Sun,,,,Sha1PRNG:SUn", false); + + testProperty( + " @#%,%$#:!%^, NativePRNG:Sun, Sha1PRNG:Sun,,Sha1PRNG:SUN", + true); + testProperty(" @#%,%$#!%^, NativePRNG:Sun, Sha1PRNG:Sun,,Sha1PRNG:SUn", + false); + } + + /* + * Linux tends to block, so ignore anything that reads /dev/random. + */ + private static void handleLinuxRead(SecureRandom sr) throws Exception { + if (os.equals("Linux")) { + if (!sr.getAlgorithm().equalsIgnoreCase("NativePRNGBlocking")) { + sr.nextBytes(new byte[34]); + } + } else { + sr.nextBytes(new byte[34]); + sr.generateSeed(34); + sr.setSeed(new byte[34]); + } + } + + /* + * This is duplicating stuff above, but just iterate over all impls + * just in case we missed something. + */ + private static void testAllImpls() throws Exception { + System.out.print("Testing: AllImpls: "); + + Iterator<String> i = Security.getAlgorithms("SecureRandom").iterator(); + + while (i.hasNext()) { + String s = i.next(); + System.out.print("/" + s); + SecureRandom sr = SecureRandom.getInstance(s); + + handleLinuxRead(sr); + handleLinuxRead(sr); + } + System.out.println("/"); + } + + public static void main(String args[]) throws Exception { + testDefaultEgd(); + testSHA1PRNGImpl(); + testNativePRNGImpls(); + testAllImpls(); + + // test default. + testStrongInstance(true); + testProperties(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/provider/SecureRandom/StrongSeedReader.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,81 @@ + /* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 6425477 + * @summary Better support for generation of high entropy random numbers + * @run main/othervm StrongSeedReader + */ + +import java.io.*; +import java.net.*; +import java.security.SecureRandom; + +/** + * A simple test which takes into account knowledge about the underlying + * implementation. This may change if the implementations change. + * + * Create a new EGD file with known bytes, then set the EGD System property. The + * data read should be the same as what was written. + */ +public class StrongSeedReader { + + public static void main(String[] args) throws Exception { + // Skip Windows, the SHA1PRNG uses CryptGenRandom. + if (System.getProperty("os.name", "unknown").startsWith("Windows")) { + return; + } + + File file = null; + try { + file = new File(System.getProperty("java.io.tmpdir") + + "StrongSeedReader.tmpdata"); + + // write a bunch of 0's to the file. + FileOutputStream fos = new FileOutputStream(file); + fos.write(new byte[2048]); + + System.setProperty("java.security.egd", file.toURI().toString()); + testSeed("NativePRNG"); + testSeed("SHA1PRNG"); + } finally { + if (file != null) { + file.delete(); + } + } + } + + private static void testSeed(String alg) throws Exception { + System.out.println("Testing: " + alg); + SecureRandom sr = SecureRandom.getInstance(alg); + byte[] ba = sr.generateSeed(20); + + // We should get back a bunch of zeros from the file. + for (byte b : ba) { + if (b != 0) { + throw new Exception("Byte != 0"); + } + } + } +}
--- a/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java Wed Apr 17 01:04:45 2013 -0700 +++ b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,14 +21,16 @@ * questions. */ +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + /* * @test * @bug 7031830 * @summary bad_record_mac failure on TLSv1.2 enabled connection with SSLEngine * @run main/othervm SSLEngineBadBufferArrayAccess - * - * SunJSSE does not support dynamic system properties, no way to re-use - * system properties in samevm/agentvm mode. */ /**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java Wed Apr 17 02:53:02 2013 -0700 @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + +/* + * @test + * @bug 7030966 + * @summary Support AEAD CipherSuites + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_RSA_WITH_AES_128_GCM_SHA256 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_DH_anon_WITH_AES_128_GCM_SHA256 + */ + +/* + * Need additional key materials to run the following cases. + * + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * + * Need unlimited JCE Unlimited Strength Jurisdiction Policy to run the + * following cases. + * + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_RSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_DH_anon_WITH_AES_256_GCM_SHA384 + */ + +import java.net.*; +import java.util.*; +import java.io.*; +import javax.net.ssl.*; +import java.security.Security; +import java.security.KeyStore; +import java.security.KeyFactory; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.spec.*; +import java.security.interfaces.*; +import sun.misc.BASE64Decoder; + + +public class ShortRSAKeyGCM { + + /* + * ============================================================= + * Set the various variables needed for the tests, then + * specify what tests to run on each side. + */ + + /* + * Should we run the client or server in a separate thread? + * Both sides can throw exceptions, but do you have a preference + * as to which side should be the main thread. + */ + static boolean separateServerThread = true; + + /* + * Where do we find the keystores? + */ + // Certificates and key used in the test. + static String trustedCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + + "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" + + "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" + + "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" + + "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" + + "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" + + "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + + "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" + + "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" + + "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" + + "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" + + "-----END CERTIFICATE-----"; + + static String targetCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + + "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" + + "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" + + "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" + + "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" + + "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" + + "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" + + "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" + + "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" + + "-----END CERTIFICATE-----"; + + // Private key in the format of PKCS#8, key size is 512 bits. + static String targetPrivateKey = + "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" + + "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" + + "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" + + "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" + + "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" + + "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" + + "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" + + "3fnqsTgaUs4="; + + static char passphrase[] = "passphrase".toCharArray(); + + /* + * Is the server ready to serve? + */ + volatile static boolean serverReady = false; + + /* + * Turn on SSL debugging? + */ + static boolean debug = false; + + /* + * Define the server side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + void doServerSide() throws Exception { + SSLContext context = generateSSLContext(null, targetCertStr, + targetPrivateKey); + SSLServerSocketFactory sslssf = context.getServerSocketFactory(); + SSLServerSocket sslServerSocket = + (SSLServerSocket)sslssf.createServerSocket(serverPort); + serverPort = sslServerSocket.getLocalPort(); + + /* + * Signal Client, we're ready for his connect. + */ + serverReady = true; + + SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept(); + sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites()); + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + + sslIS.read(); + sslOS.write('A'); + sslOS.flush(); + + sslSocket.close(); + } + + /* + * Define the client side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + void doClientSide() throws Exception { + + /* + * Wait for server to get started. + */ + while (!serverReady) { + Thread.sleep(50); + } + + SSLContext context = generateSSLContext(trustedCertStr, null, null); + SSLSocketFactory sslsf = context.getSocketFactory(); + + SSLSocket sslSocket = + (SSLSocket)sslsf.createSocket("localhost", serverPort); + + // enable TLSv1.2 only + sslSocket.setEnabledProtocols(new String[] {"TLSv1.2"}); + + // enable a block cipher + sslSocket.setEnabledCipherSuites(new String[] {cipherSuite}); + + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + + sslOS.write('B'); + sslOS.flush(); + sslIS.read(); + + sslSocket.close(); + } + + /* + * ============================================================= + * The remainder is just support stuff + */ + private static String tmAlgorithm; // trust manager + private static String cipherSuite; // cipher suite + + private static void parseArguments(String[] args) { + tmAlgorithm = args[0]; + cipherSuite = args[1]; + } + + private static SSLContext generateSSLContext(String trustedCertStr, + String keyCertStr, String keySpecStr) throws Exception { + + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + // create a key store + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(null, null); + + // import the trused cert + Certificate trusedCert = null; + ByteArrayInputStream is = null; + if (trustedCertStr != null) { + is = new ByteArrayInputStream(trustedCertStr.getBytes()); + trusedCert = cf.generateCertificate(is); + is.close(); + + ks.setCertificateEntry("RSA Export Signer", trusedCert); + } + + if (keyCertStr != null) { + // generate the private key. + PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( + new BASE64Decoder().decodeBuffer(keySpecStr)); + KeyFactory kf = KeyFactory.getInstance("RSA"); + RSAPrivateKey priKey = + (RSAPrivateKey)kf.generatePrivate(priKeySpec); + + // generate certificate chain + is = new ByteArrayInputStream(keyCertStr.getBytes()); + Certificate keyCert = cf.generateCertificate(is); + is.close(); + + Certificate[] chain = null; + if (trusedCert != null) { + chain = new Certificate[2]; + chain[0] = keyCert; + chain[1] = trusedCert; + } else { + chain = new Certificate[1]; + chain[0] = keyCert; + } + + // import the key entry. + ks.setKeyEntry("Whatever", priKey, passphrase, chain); + } + + // create SSL context + TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); + tmf.init(ks); + + SSLContext ctx = SSLContext.getInstance("TLS"); + if (keyCertStr != null && !keyCertStr.isEmpty()) { + KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); + kmf.init(ks, passphrase); + + ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + ks = null; + } else { + ctx.init(null, tmf.getTrustManagers(), null); + } + + return ctx; + } + + + // use any free port by default + volatile int serverPort = 0; + + volatile Exception serverException = null; + volatile Exception clientException = null; + + public static void main(String[] args) throws Exception { + // reset the security property to make sure that the algorithms + // and keys used in this test are not disabled. + Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2"); + + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + + /* + * Get the customized arguments. + */ + parseArguments(args); + + /* + * Start the tests. + */ + new ShortRSAKeyGCM(); + } + + Thread clientThread = null; + Thread serverThread = null; + + /* + * Primary constructor, used to drive remainder of the test. + * + * Fork off the other side, then do your work. + */ + ShortRSAKeyGCM() throws Exception { + try { + if (separateServerThread) { + startServer(true); + startClient(false); + } else { + startClient(true); + startServer(false); + } + } catch (Exception e) { + // swallow for now. Show later + } + + /* + * Wait for other side to close down. + */ + if (separateServerThread) { + serverThread.join(); + } else { + clientThread.join(); + } + + /* + * When we get here, the test is pretty much over. + * Which side threw the error? + */ + Exception local; + Exception remote; + String whichRemote; + + if (separateServerThread) { + remote = serverException; + local = clientException; + whichRemote = "server"; + } else { + remote = clientException; + local = serverException; + whichRemote = "client"; + } + + /* + * If both failed, return the curthread's exception, but also + * print the remote side Exception + */ + if ((local != null) && (remote != null)) { + System.out.println(whichRemote + " also threw:"); + remote.printStackTrace(); + System.out.println(); + throw local; + } + + if (remote != null) { + throw remote; + } + + if (local != null) { + throw local; + } + } + + void startServer(boolean newThread) throws Exception { + if (newThread) { + serverThread = new Thread() { + public void run() { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Release the client, if not active already... + */ + System.err.println("Server died..." + e); + serverReady = true; + serverException = e; + } + } + }; + serverThread.start(); + } else { + try { + doServerSide(); + } catch (Exception e) { + serverException = e; + } finally { + serverReady = true; + } + } + } + + void startClient(boolean newThread) throws Exception { + if (newThread) { + clientThread = new Thread() { + public void run() { + try { + doClientSide(); + } catch (Exception e) { + /* + * Our client thread just died. + */ + System.err.println("Client died..." + e); + clientException = e; + } + } + }; + clientThread.start(); + } else { + try { + doClientSide(); + } catch (Exception e) { + clientException = e; + } + } + } +}
--- a/test/sun/security/ssl/sanity/ciphersuites/CipherSuitesInOrder.java Wed Apr 17 01:04:45 2013 -0700 +++ b/test/sun/security/ssl/sanity/ciphersuites/CipherSuitesInOrder.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,13 +21,15 @@ * questions. */ +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + /* * @test * @bug 7174244 * @summary NPE in Krb5ProxyImpl.getServerKeys() - * - * SunJSSE does not support dynamic system properties, no way to re-use - * system properties in samevm/agentvm mode. * @run main/othervm CipherSuitesInOrder */ @@ -72,6 +74,22 @@ "SSL_RSA_WITH_RC4_128_SHA", "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", "TLS_ECDH_RSA_WITH_RC4_128_SHA", + + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", + "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA", @@ -83,6 +101,9 @@ "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", + "TLS_DH_anon_WITH_AES_256_GCM_SHA384", + "TLS_DH_anon_WITH_AES_128_GCM_SHA256", + "TLS_DH_anon_WITH_AES_256_CBC_SHA256", "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", "TLS_DH_anon_WITH_AES_256_CBC_SHA",
--- a/test/sun/security/ssl/sanity/interop/CipherTest.java Wed Apr 17 01:04:45 2013 -0700 +++ b/test/sun/security/ssl/sanity/interop/CipherTest.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,6 +148,25 @@ CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF), CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF), + CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + + CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + + CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + // cipher suites obsoleted since TLS 1.2 CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303),
--- a/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java Wed Apr 17 01:04:45 2013 -0700 +++ b/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java Wed Apr 17 02:53:02 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,14 +21,15 @@ * questions. */ +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + /* * @test * @bug 7105780 * @summary Add SSLSocket client/SSLEngine server to templates directory. - * - * SunJSSE does not support dynamic system properties, no way to re-use - * system properties in samevm/agentvm mode. - * * @run main/othervm SSLSocketSSLEngineTemplate */