--- a/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/KeyStore.java Fri Apr 01 22:47:30 2016 +0200
+++ b/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/KeyStore.java Sun Apr 03 16:38:10 2016 +0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, 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
@@ -188,8 +188,10 @@
/*
* The keystore entries.
+ * Keys in the map are unique aliases (thus can differ from
+ * KeyEntry.getAlias())
*/
- private Collection<KeyEntry> entries = new ArrayList<KeyEntry>();
+ private Map<String,KeyEntry> entries = new HashMap<>();
/*
* The keystore name.
@@ -248,13 +250,10 @@
if (engineIsKeyEntry(alias) == false)
return null;
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias())) {
- return entry.getPrivateKey();
- }
- }
-
- return null;
+ KeyEntry entry = entries.get(alias);
+ return (entry == null)
+ ? null
+ : entry.getPrivateKey();
}
/**
@@ -274,15 +273,13 @@
return null;
}
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias())) {
- X509Certificate[] certChain = entry.getCertificateChain();
-
- return certChain.clone();
- }
- }
-
- return null;
+ KeyEntry entry = entries.get(alias);
+ X509Certificate[] certChain = (entry == null)
+ ? null
+ : entry.getCertificateChain();
+ return (certChain == null)
+ ? null
+ : certChain.clone();
}
/**
@@ -306,15 +303,13 @@
return null;
}
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias()))
- {
- X509Certificate[] certChain = entry.getCertificateChain();
- return certChain.length == 0 ? null : certChain[0];
- }
- }
-
- return null;
+ KeyEntry entry = entries.get(alias);
+ X509Certificate[] certChain = (entry == null)
+ ? null
+ : entry.getCertificateChain();
+ return (certChain == null || certChain.length == 0)
+ ? null
+ : certChain[0];
}
/**
@@ -378,16 +373,7 @@
if (key instanceof RSAPrivateCrtKey) {
- KeyEntry entry = null;
- boolean found = false;
-
- for (KeyEntry e : entries) {
- if (alias.equals(e.getAlias())) {
- found = true;
- entry = e;
- break;
- }
- }
+ KeyEntry entry = entries.get(alias);
X509Certificate[] xchain;
if (chain != null) {
@@ -401,11 +387,11 @@
xchain = null;
}
- if (! found) {
+ if (entry == null) {
entry =
//TODO new KeyEntry(alias, key, (X509Certificate[]) chain);
new KeyEntry(alias, null, xchain);
- entries.add(entry);
+ storeWithUniqueAlias(alias, entry);
}
entry.setAlias(alias);
@@ -484,23 +470,14 @@
// TODO - build CryptoAPI chain?
X509Certificate[] chain =
new X509Certificate[]{ (X509Certificate) cert };
- KeyEntry entry = null;
- boolean found = false;
+ KeyEntry entry = entries.get(alias);
- for (KeyEntry e : entries) {
- if (alias.equals(e.getAlias())) {
- found = true;
- entry = e;
- break;
- }
+ if (entry == null) {
+ entry =
+ new KeyEntry(alias, null, chain);
+ storeWithUniqueAlias(alias, entry);
}
- if (! found) {
- entry =
- new KeyEntry(alias, null, chain);
- entries.add(entry);
-
- }
if (entry.getPrivateKey() == null) { // trusted-cert entry
entry.setAlias(alias);
@@ -532,32 +509,26 @@
throw new KeyStoreException("alias must not be null");
}
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias())) {
+ KeyEntry entry = entries.remove(alias);
+ if (entry != null) {
+ // Get end-entity certificate and remove from system cert store
+ X509Certificate[] certChain = entry.getCertificateChain();
+ if (certChain != null) {
- // Get end-entity certificate and remove from system cert store
- X509Certificate[] certChain = entry.getCertificateChain();
- if (certChain != null) {
+ try {
- try {
-
- byte[] encoding = certChain[0].getEncoded();
- removeCertificate(getName(), alias, encoding,
+ byte[] encoding = certChain[0].getEncoded();
+ removeCertificate(getName(), entry.getAlias(), encoding,
encoding.length);
- } catch (CertificateException e) {
- throw new KeyStoreException("Cannot remove entry: " +
- e);
- }
+ } catch (CertificateException e) {
+ throw new KeyStoreException("Cannot remove entry: ", e);
}
- Key privateKey = entry.getPrivateKey();
- if (privateKey != null) {
- destroyKeyContainer(
- Key.getContainerName(privateKey.getHCryptProvider()));
- }
-
- entries.remove(entry);
- break;
+ }
+ Key privateKey = entry.getPrivateKey();
+ if (privateKey != null) {
+ destroyKeyContainer(
+ Key.getContainerName(privateKey.getHCryptProvider()));
}
}
}
@@ -568,8 +539,7 @@
* @return enumeration of the alias names
*/
public Enumeration<String> engineAliases() {
-
- final Iterator<KeyEntry> iter = entries.iterator();
+ final Iterator<String> iter = entries.keySet().iterator();
return new Enumeration<String>()
{
@@ -580,8 +550,7 @@
public String nextElement()
{
- KeyEntry entry = iter.next();
- return entry.getAlias();
+ return iter.next();
}
};
}
@@ -594,15 +563,7 @@
* @return true if the alias exists, false otherwise
*/
public boolean engineContainsAlias(String alias) {
- for (Enumeration<String> enumerator = engineAliases();
- enumerator.hasMoreElements();)
- {
- String a = enumerator.nextElement();
-
- if (a.equals(alias))
- return true;
- }
- return false;
+ return entries.containsKey(alias);
}
/**
@@ -627,13 +588,8 @@
return false;
}
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias())) {
- return entry.getPrivateKey() != null;
- }
- }
-
- return false;
+ KeyEntry entry = entries.get(alias);
+ return entry != null && entry.getPrivateKey() != null;
}
/**
@@ -643,15 +599,14 @@
* @return true if the entry identified by the given alias is a
* <i>trusted certificate entry</i>, false otherwise.
*/
- public boolean engineIsCertificateEntry(String alias)
- {
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias())) {
- return entry.getPrivateKey() == null;
- }
+ public boolean engineIsCertificateEntry(String alias) {
+
+ if (alias == null) {
+ return false;
}
- return false;
+ KeyEntry entry = entries.get(alias);
+ return entry != null && entry.getPrivateKey() == null;
}
/**
@@ -670,9 +625,10 @@
* @return the (alias) name of the first entry with matching certificate,
* or null if no such entry exists in this keystore.
*/
- public String engineGetCertificateAlias(Certificate cert)
- {
- for (KeyEntry entry : entries) {
+ public String engineGetCertificateAlias(Certificate cert) {
+
+ for (Map.Entry<String,KeyEntry> mapEntry : entries.entrySet()) {
+ KeyEntry entry = mapEntry.getValue();
if (entry.certChain != null && entry.certChain[0].equals(cert)) {
return entry.getAlias();
}
@@ -765,7 +721,7 @@
try {
// Load keys and/or certificate chains
- loadKeysOrCertificateChains(getName(), entries);
+ loadKeysOrCertificateChains(getName());
} catch (KeyStoreException e) {
throw new IOException(e);
@@ -773,12 +729,31 @@
}
/**
+ * Stores the given entry into the map, making sure
+ * the alias, used as the key is unique.
+ * If the same alias already exists, it tries to append
+ * a suffix (1), (2), etc to it until it finds a unique
+ * value.
+ */
+ private void storeWithUniqueAlias(String alias, KeyEntry entry) {
+ String uniqAlias = alias;
+ int uniqNum = 1;
+
+ while (true) {
+ if (entries.putIfAbsent(uniqAlias, entry) == null) {
+ break;
+ }
+ uniqAlias = alias + " (" + (uniqNum++) + ")";
+ }
+ }
+
+
+ /**
* Generates a certificate chain from the collection of
* certificates and stores the result into a key entry.
*/
private void generateCertificateChain(String alias,
- Collection<? extends Certificate> certCollection,
- Collection<KeyEntry> entries)
+ Collection<? extends Certificate> certCollection)
{
try
{
@@ -792,10 +767,8 @@
certChain[i] = (X509Certificate) iter.next();
}
- KeyEntry entry = new KeyEntry(alias, null, certChain);
-
- // Add cert chain
- entries.add(entry);
+ storeWithUniqueAlias(alias,
+ new KeyEntry(alias, null, certChain));
}
catch (Throwable e)
{
@@ -810,8 +783,7 @@
*/
private void generateRSAKeyAndCertificateChain(String alias,
long hCryptProv, long hCryptKey, int keyLength,
- Collection<? extends Certificate> certCollection,
- Collection<KeyEntry> entries)
+ Collection<? extends Certificate> certCollection)
{
try
{
@@ -825,11 +797,9 @@
certChain[i] = (X509Certificate) iter.next();
}
- KeyEntry entry = new KeyEntry(alias, new RSAPrivateKey(hCryptProv,
- hCryptKey, keyLength), certChain);
-
- // Add cert chain
- entries.add(entry);
+ storeWithUniqueAlias(alias, new KeyEntry(alias,
+ new RSAPrivateKey(hCryptProv, hCryptKey, keyLength),
+ certChain));
}
catch (Throwable e)
{
@@ -886,8 +856,8 @@
* @param name Name of keystore.
* @param entries Collection of key/certificate.
*/
- private native void loadKeysOrCertificateChains(String name,
- Collection<KeyEntry> entries) throws KeyStoreException;
+ private native void loadKeysOrCertificateChains(String name)
+ throws KeyStoreException;
/**
* Stores a DER-encoded certificate into the certificate store
--- a/jdk/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp Fri Apr 01 22:47:30 2016 +0200
+++ b/jdk/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp Sun Apr 03 16:38:10 2016 +0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, 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
@@ -272,7 +272,7 @@
* Signature: (Ljava/lang/String;Ljava/util/Collection;)V
*/
JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_loadKeysOrCertificateChains
- (JNIEnv *env, jobject obj, jstring jCertStoreName, jobject jCollections)
+ (JNIEnv *env, jobject obj, jstring jCertStoreName)
{
/**
* Certificate in cert store has enhanced key usage extension
@@ -331,7 +331,7 @@
// Determine method ID to generate certificate chain
jmethodID mGenCertChain = env->GetMethodID(clazzOfThis,
"generateCertificateChain",
- "(Ljava/lang/String;Ljava/util/Collection;Ljava/util/Collection;)V");
+ "(Ljava/lang/String;Ljava/util/Collection;)V");
if (mGenCertChain == NULL) {
__leave;
}
@@ -339,7 +339,7 @@
// Determine method ID to generate RSA certificate chain
jmethodID mGenRSAKeyAndCertChain = env->GetMethodID(clazzOfThis,
"generateRSAKeyAndCertificateChain",
- "(Ljava/lang/String;JJILjava/util/Collection;Ljava/util/Collection;)V");
+ "(Ljava/lang/String;JJILjava/util/Collection;)V");
if (mGenRSAKeyAndCertChain == NULL) {
__leave;
}
@@ -366,38 +366,37 @@
} else {
// Private key is available
- BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey);
+ BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey);
- // Skip certificate if cannot find private key
- if (bGetUserKey == FALSE)
- {
- if (bCallerFreeProv)
- ::CryptReleaseContext(hCryptProv, NULL);
+ // Skip certificate if cannot find private key
+ if (bGetUserKey == FALSE)
+ {
+ if (bCallerFreeProv)
+ ::CryptReleaseContext(hCryptProv, NULL);
- continue;
- }
+ continue;
+ }
- // Set cipher mode to ECB
- DWORD dwCipherMode = CRYPT_MODE_ECB;
- ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL);
+ // Set cipher mode to ECB
+ DWORD dwCipherMode = CRYPT_MODE_ECB;
+ ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL);
- // If the private key is present in smart card, we may not be able to
- // determine the key length by using the private key handle. However,
- // since public/private key pairs must have the same length, we could
- // determine the key length of the private key by using the public key
- // in the certificate.
- dwPublicKeyLength = ::CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- &(pCertContext->pCertInfo->SubjectPublicKeyInfo));
+ // If the private key is present in smart card, we may not be able to
+ // determine the key length by using the private key handle. However,
+ // since public/private key pairs must have the same length, we could
+ // determine the key length of the private key by using the public key
+ // in the certificate.
+ dwPublicKeyLength = ::CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ &(pCertContext->pCertInfo->SubjectPublicKeyInfo));
-}
+ }
PCCERT_CHAIN_CONTEXT pCertChainContext = NULL;
// Build certificate chain by using system certificate store.
// Add cert chain into collection for any key usage.
//
- if (GetCertificateChain(OID_EKU_ANY, pCertContext,
- &pCertChainContext))
+ if (GetCertificateChain(OID_EKU_ANY, pCertContext, &pCertChainContext))
{
for (unsigned int i=0; i < pCertChainContext->cChain; i++)
@@ -456,26 +455,26 @@
// collection
env->CallVoidMethod(obj, mGenCertChain,
env->NewStringUTF(pszNameString),
- jArrayList, jCollections);
+ jArrayList);
}
else
{
- // Determine key type: RSA or DSA
- DWORD dwData = CALG_RSA_KEYX;
- DWORD dwSize = sizeof(DWORD);
- ::CryptGetKeyParam(hUserKey, KP_ALGID, (BYTE*)&dwData,
- &dwSize, NULL);
+ // Determine key type: RSA or DSA
+ DWORD dwData = CALG_RSA_KEYX;
+ DWORD dwSize = sizeof(DWORD);
+ ::CryptGetKeyParam(hUserKey, KP_ALGID, (BYTE*)&dwData,
+ &dwSize, NULL);
- if ((dwData & ALG_TYPE_RSA) == ALG_TYPE_RSA)
- {
- // Generate RSA certificate chain and store into cert
- // chain collection
- env->CallVoidMethod(obj, mGenRSAKeyAndCertChain,
- env->NewStringUTF(pszNameString),
- (jlong) hCryptProv, (jlong) hUserKey,
- dwPublicKeyLength, jArrayList, jCollections);
+ if ((dwData & ALG_TYPE_RSA) == ALG_TYPE_RSA)
+ {
+ // Generate RSA certificate chain and store into cert
+ // chain collection
+ env->CallVoidMethod(obj, mGenRSAKeyAndCertChain,
+ env->NewStringUTF(pszNameString),
+ (jlong) hCryptProv, (jlong) hUserKey,
+ dwPublicKeyLength, jArrayList);
+ }
}
-}
}
// Free cert chain
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/mscapi/nonUniqueAliases/NonUniqueAliases.sh Sun Apr 03 16:38:10 2016 +0300
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+#
+# 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
+# @ignore Uses certutil.exe that isn't guaranteed to be installed
+# @bug 6483657
+# @requires os.family == "windows"
+# @run shell NonUniqueAliases.sh
+# @summary Test "keytool -list" displays correcly same named certificates
+
+# set a few environment variables so that the shell-script can run stand-alone
+# in the source directory
+if [ "${TESTSRC}" = "" ] ; then
+ TESTSRC="."
+fi
+
+if [ "${TESTCLASSES}" = "" ] ; then
+ TESTCLASSES="."
+fi
+
+if [ "${TESTJAVA}" = "" ] ; then
+ echo "TESTJAVA not set. Test cannot execute."
+ echo "FAILED!!!"
+ exit 1
+fi
+
+OS=`uname -s`
+case "$OS" in
+ Windows* | CYGWIN* )
+
+ # 'uname -m' does not give us enough information -
+ # should rely on $PROCESSOR_IDENTIFIER (as is done in Defs-windows.gmk),
+ # but JTREG does not pass this env variable when executing a shell script.
+ #
+ # execute test program - rely on it to exit if platform unsupported
+
+ echo "removing the alias NonUniqueName if it already exists"
+ certutil -user -delstore MY NonUniqueName
+
+ echo "Importing 1st certificate into MY keystore using certutil tool"
+ certutil -user -addstore MY ${TESTSRC}/nonUniq1.pem
+
+ echo "Importing 2nd certificate into MY keystore using certutil tool"
+ certutil -user -addstore MY ${TESTSRC}/nonUniq2.pem
+
+ echo "Listing certificates with keytool"
+ ${TESTJAVA}/bin/keytool ${TESTTOOLVMOPTS} -list -storetype Windows-My
+
+ echo "Counting expected entries"
+ count0=`${TESTJAVA}/bin/keytool ${TESTTOOLVMOPTS} -list -storetype Windows-My | grep 'NonUniqueName,' | wc -l`
+
+ if [ ! $count0 = 1 ]; then
+ echo "error: unexpected number of entries ($count0) in the Windows-MY store"
+ certutil -user -delstore MY NonUniqueName
+ exit 115
+ fi
+
+ echo "Counting expected entries"
+ count1=`${TESTJAVA}/bin/keytool ${TESTTOOLVMOPTS} -list -storetype Windows-My | grep 'NonUniqueName (1),' | wc -l`
+
+ if [ ! $count1 = 1 ]; then
+ echo "error: unexpected number of entries ($count1) in the Windows-MY store"
+ certutil -user -delstore MY NonUniqueName
+ exit 116
+ fi
+
+ echo "Cleaning up"
+ certutil -user -delstore MY NonUniqueName
+
+ exit 0
+ ;;
+
+ * )
+ echo "This test is not intended for '$OS' - passing test"
+ exit 0
+ ;;
+esac
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/mscapi/nonUniqueAliases/nonUniq1.pem Sun Apr 03 16:38:10 2016 +0300
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAWegAwIBAgIJANy5XBGM4BSuMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV
+BAMMDU5vblVuaXF1ZU5hbWUwHhcNMTYwNDAxMTcyMjQ0WhcNMTYwNzEwMTcyMjQ0
+WjAYMRYwFAYDVQQDDA1Ob25VbmlxdWVOYW1lMIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDI0hlED2YFVgTaVLKWvsqB9JN9EJpUWECkB97fJwb1x99dHf0TO2p6
+HPPvkvjBiAMEZYbojCz+WpNhG1Ilu/UgKwPyHh1pL6kRcEhlS2G3i7p9SDLHWlk0
+xfdhSZERgd6ROpDnY7eaj1CTdVCSyEATs4FFyNtN9Q39jyeCU++ksQIDAQABo1Aw
+TjAdBgNVHQ4EFgQUpW/Wtw/OOTdnFTL7afIkNjuCVr8wHwYDVR0jBBgwFoAUpW/W
+tw/OOTdnFTL7afIkNjuCVr8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOB
+gQAWC+xX1cGNNp3F6dAb5tKKJGgQwsjfrjDP0/AirWc7Im1kTCpVPT61Ayt0bHgH
+n3hGivKmO7ChQAI3QsDMDKWE98tF6afPltBOoWh2a9tPd65JSD1HfkG+Wc1IZ5gL
+8rKp1tdKTEG2A+qXRN/e6DdtMsgDrK1iPfX+rer53TC+Yg==
+-----END CERTIFICATE-----
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/mscapi/nonUniqueAliases/nonUniq2.pem Sun Apr 03 16:38:10 2016 +0300
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAWegAwIBAgIJAPyQune5t/SZMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV
+BAMMDU5vblVuaXF1ZU5hbWUwHhcNMTYwNDAxMTcyMzI0WhcNMTYwNzEwMTcyMzI0
+WjAYMRYwFAYDVQQDDA1Ob25VbmlxdWVOYW1lMIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDeSu/pPzL9hA1kjA2Rs13LpN2lNrisbYg/Vj/swGDMJnVCzS3IFQQy
+71515mru+ngrHnfPSo4FKUhZPJzET2D7CruR65SzhQ96SHGoR8rhmL41KRBKELuR
+3MoarLFziFzeIil4NZg55xp6TE/WCXRfi7HNdIgoKQGLoIhehVGN8QIDAQABo1Aw
+TjAdBgNVHQ4EFgQUxFw79pLSf5Ul3zLqi/Mc6pSxEtswHwYDVR0jBBgwFoAUxFw7
+9pLSf5Ul3zLqi/Mc6pSxEtswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOB
+gQDPilBcFpFrjwqb+lJxDxXK992KjNUS8yFLo1DQ/LBTaoHvy/U5zxzRq+nvSaaf
+h+RIKqTwIbuBhSjrXVdJ/gzob/UlPC7IDo7FVbZwOHqTkqEum8jQEpX67hEevw9s
++reyqGhLsCtQK6uBTd2Nt9uOVCHrWNzWgQewkVYAUM5QpA==
+-----END CERTIFICATE-----