# HG changeset patch # User igerasim # Date 1471293932 -10800 # Node ID c6df8bba0b71a1cc6806a10e01b3c10fa2e0f769 # Parent 2e83d21d78cd9c1d52e6cd2599e9c8aa36ea1f52 8163896: Finalizing one key of a KeyPair invalidates the other key Reviewed-by: coffeys, vinnie diff -r 2e83d21d78cd -r c6df8bba0b71 jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/Key.java --- a/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/Key.java Wed Jul 05 22:05:29 2017 +0200 +++ b/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/Key.java Mon Aug 15 23:45:32 2016 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ /** * The handle for an RSA or DSA key using the Microsoft Crypto API. * - * @see DSAPrivateKey * @see RSAPrivateKey * @see RSAPublicKey * @@ -41,9 +40,35 @@ { private static final long serialVersionUID = -1088859394025049194L; - // Native handle - protected long hCryptProv = 0; - protected long hCryptKey = 0; + static class NativeHandles { + long hCryptProv = 0; + long hCryptKey = 0; + + public NativeHandles(long hCryptProv, long hCryptKey) { + this.hCryptProv = hCryptProv; + this.hCryptKey = hCryptKey; + } + + /** + * Finalization method + */ + protected void finalize() throws Throwable + { + try { + synchronized(this) + { + cleanUp(hCryptProv, hCryptKey); + hCryptProv = 0; + hCryptKey = 0; + } + + } finally { + super.finalize(); + } + } + } + + protected NativeHandles handles; // Key length protected int keyLength = 0; @@ -51,29 +76,10 @@ /** * Construct a Key object. */ - protected Key(long hCryptProv, long hCryptKey, int keyLength) - { - this.hCryptProv = hCryptProv; - this.hCryptKey = hCryptKey; - this.keyLength = keyLength; - } - - /** - * Finalization method - */ - protected void finalize() throws Throwable + protected Key(NativeHandles handles, int keyLength) { - try { - synchronized(this) - { - cleanUp(hCryptProv, hCryptKey); - hCryptProv = 0; - hCryptKey = 0; - } - - } finally { - super.finalize(); - } + this.handles = handles; + this.keyLength = keyLength; } /** @@ -96,7 +102,7 @@ */ public long getHCryptKey() { - return hCryptKey; + return handles.hCryptKey; } /** @@ -104,12 +110,12 @@ */ public long getHCryptProvider() { - return hCryptProv; + return handles.hCryptProv; } /** * Returns the standard algorithm name for this key. For - * example, "DSA" would indicate that this key is a DSA key. + * example, "RSA" would indicate that this key is a RSA key. * See Appendix A in the * Java Cryptography Architecture API Specification & Reference diff -r 2e83d21d78cd -r c6df8bba0b71 jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/KeyStore.java --- a/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/KeyStore.java Wed Jul 05 22:05:29 2017 +0200 +++ b/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/KeyStore.java Mon Aug 15 23:45:32 2016 +0300 @@ -168,7 +168,7 @@ } certChain = chain; } - }; + } /* * An X.509 certificate factory. @@ -798,7 +798,8 @@ } storeWithUniqueAlias(alias, new KeyEntry(alias, - new RSAPrivateKey(hCryptProv, hCryptKey, keyLength), + new RSAPrivateKey(new Key.NativeHandles(hCryptProv, + hCryptKey), keyLength), certChain)); } catch (Throwable e) @@ -854,7 +855,6 @@ * Load keys and/or certificates from keystore into Collection. * * @param name Name of keystore. - * @param entries Collection of key/certificate. */ private native void loadKeysOrCertificateChains(String name) throws KeyStoreException; diff -r 2e83d21d78cd -r c6df8bba0b71 jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAKeyPair.java --- a/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAKeyPair.java Wed Jul 05 22:05:29 2017 +0200 +++ b/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAKeyPair.java Mon Aug 15 23:45:32 2016 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -41,8 +41,9 @@ */ RSAKeyPair(long hCryptProv, long hCryptKey, int keyLength) { - privateKey = new RSAPrivateKey(hCryptProv, hCryptKey, keyLength); - publicKey = new RSAPublicKey(hCryptProv, hCryptKey, keyLength); + Key.NativeHandles handles = new Key.NativeHandles(hCryptProv, hCryptKey); + privateKey = new RSAPrivateKey(handles, keyLength); + publicKey = new RSAPublicKey(handles, keyLength); } public RSAPrivateKey getPrivate() { diff -r 2e83d21d78cd -r c6df8bba0b71 jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAPrivateKey.java --- a/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAPrivateKey.java Wed Jul 05 22:05:29 2017 +0200 +++ b/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAPrivateKey.java Mon Aug 15 23:45:32 2016 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -42,7 +42,15 @@ */ RSAPrivateKey(long hCryptProv, long hCryptKey, int keyLength) { - super(hCryptProv, hCryptKey, keyLength); + super(new NativeHandles(hCryptProv, hCryptKey), keyLength); + } + + /** + * Construct an RSAPrivateKey object. + */ + RSAPrivateKey(NativeHandles handles, int keyLength) + { + super(handles, keyLength); } /** @@ -63,8 +71,8 @@ public String toString() { return "RSAPrivateKey [size=" + keyLength + " bits, type=" + - getKeyType(hCryptKey) + ", container=" + - getContainerName(hCryptProv) + "]"; + getKeyType(handles.hCryptKey) + ", container=" + + getContainerName(handles.hCryptProv) + "]"; } // This class is not serializable diff -r 2e83d21d78cd -r c6df8bba0b71 jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAPublicKey.java --- a/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAPublicKey.java Wed Jul 05 22:05:29 2017 +0200 +++ b/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSAPublicKey.java Mon Aug 15 23:45:32 2016 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -51,7 +51,15 @@ */ RSAPublicKey(long hCryptProv, long hCryptKey, int keyLength) { - super(hCryptProv, hCryptKey, keyLength); + super(new NativeHandles(hCryptProv, hCryptKey), keyLength); + } + + /** + * Construct an RSAPublicKey object. + */ + RSAPublicKey(NativeHandles handles, int keyLength) + { + super(handles, keyLength); } /** @@ -77,8 +85,8 @@ StringBuffer sb = new StringBuffer(); sb.append("RSAPublicKey [size=").append(keyLength) - .append(" bits, type=").append(getKeyType(hCryptKey)) - .append(", container=").append(getContainerName(hCryptProv)) + .append(" bits, type=").append(getKeyType(handles.hCryptKey)) + .append(", container=").append(getContainerName(handles.hCryptProv)) .append("]\n modulus: ").append(getModulus()) .append("\n public exponent: ").append(getPublicExponent()); @@ -93,7 +101,7 @@ if (exponent == null) { try { - publicKeyBlob = getPublicKeyBlob(hCryptKey); + publicKeyBlob = getPublicKeyBlob(handles.hCryptKey); exponent = new BigInteger(1, getExponent(publicKeyBlob)); } catch (KeyException e) { @@ -112,7 +120,7 @@ if (modulus == null) { try { - publicKeyBlob = getPublicKeyBlob(hCryptKey); + publicKeyBlob = getPublicKeyBlob(handles.hCryptKey); modulus = new BigInteger(1, getModulus(publicKeyBlob)); } catch (KeyException e) { diff -r 2e83d21d78cd -r c6df8bba0b71 jdk/test/java/security/KeyPairGenerator/FinalizeHalf.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/security/KeyPairGenerator/FinalizeHalf.java Mon Aug 15 23:45:32 2016 +0300 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016, 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 8163896 + * @summary Finalizing one key of a KeyPair invalidates the other key + */ + +import java.security.Key; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.ProviderException; +import java.security.Security; +import java.util.function.Consumer; +import java.util.ArrayList; +import java.util.List; + +public class FinalizeHalf { + + static int failures = 0; + + public static void main(String[] args) throws Throwable { + List> methods = new ArrayList<>(); + methods.add((Key k) -> k.getEncoded()); + methods.add((Key k) -> k.toString()); + + for (String algo : new String[] {"DiffieHellman", "DSA", "RSA"}) { + for (Provider provider : Security.getProviders()) { + for (boolean priv : new boolean[] {true, false}) { + for (Consumer method : methods) { + test(algo, provider, priv, method); + } + } + } + } + + if (failures > 0) { + throw new RuntimeException(failures + " test(s) failed."); + } + } + + static void test(String algo, Provider provider, boolean priv, + Consumer method) throws Exception { + KeyPairGenerator generator; + try { + generator = KeyPairGenerator.getInstance(algo, provider); + } catch (NoSuchAlgorithmException nsae) { + return; + } + + System.out.println("Checking " + provider.getName() + ", " + algo); + + KeyPair pair = generator.generateKeyPair(); + Key key = priv ? pair.getPrivate() : pair.getPublic(); + + pair = null; + for (int i = 0; i < 32; ++i) { + System.gc(); + } + + try { + method.accept(key); + } catch (ProviderException pe) { + failures++; + } + } +}