8062264: KeychainStore requires non-null password to be supplied when retrieving a private key
Reviewed-by: mullan
Contributed-by: Florian Bruckner <florian.bruckner@3kraft.com>
--- a/jdk/src/jdk.deploy.osx/macosx/classes/apple/security/KeychainStore.java Tue Oct 28 11:45:31 2014 +0100
+++ b/jdk/src/jdk.deploy.osx/macosx/classes/apple/security/KeychainStore.java Wed Oct 29 11:53:37 2014 +0000
@@ -140,7 +140,8 @@
* password to recover it.
*
* @param alias the alias name
- * @param password the password for recovering the key
+ * @param password the password for recovering the key. This password is
+ * used internally as the key is exported in a PKCS12 format.
*
* @return the requested key, or null if the given alias does not exist
* or does not identify a <i>key entry</i>.
@@ -155,6 +156,20 @@
{
permissionCheck();
+ // An empty password is rejected by MacOS API, no private key data
+ // is exported. If no password is passed (as is the case when
+ // this implementation is used as browser keystore in various
+ // deployment scenarios like Webstart, JFX and applets), create
+ // a dummy password so MacOS API is happy.
+ if (password == null || password.length == 0) {
+ // Must not be a char array with only a 0, as this is an empty
+ // string.
+ if (random == null) {
+ random = new SecureRandom();
+ }
+ password = Long.toString(random.nextLong()).toCharArray();
+ }
+
Object entry = entries.get(alias.toLowerCase());
if (entry == null || !(entry instanceof KeyEntry)) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/tools/keytool/ExportPrivateKeyNoPwd.java Wed Oct 29 11:53:37 2014 +0000
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+import java.security.*;
+
+/*
+ * Export a private key from the named keychain entry without supplying a
+ * password. See JDK-8062264.
+ *
+ * NOTE: Keychain access controls must already have been lowered to permit
+ * the target entry to be accessed.
+ */
+public class ExportPrivateKeyNoPwd {
+
+ public static final void main(String[] args) throws Exception {
+
+ if (args.length != 1) {
+ throw new Exception(
+ "ExportPrivateKeyNoPwd: must supply name of a keystore entry");
+ }
+ String alias = args[0];
+
+ KeyStore ks = KeyStore.getInstance("KeychainStore");
+ System.out.println("ExportPrivateKeyNoPwd: loading keychains...");
+ ks.load(null, null);
+
+ System.out.println("ExportPrivateKeyNoPwd: exporting key...");
+ Key key = ks.getKey(alias, null);
+ if (key instanceof PrivateKey) {
+ System.out.println("ExportPrivateKeyNoPwd: exported " +
+ key.getAlgorithm() + " private key from '" + alias + "'");
+ } else {
+ throw new Exception("Error exporting private key from keychain");
+ }
+ }
+}
+
--- a/jdk/test/sun/security/tools/keytool/ListKeychainStore.sh Tue Oct 28 11:45:31 2014 +0100
+++ b/jdk/test/sun/security/tools/keytool/ListKeychainStore.sh Wed Oct 29 11:53:37 2014 +0000
@@ -22,7 +22,7 @@
#
# @test
-# @bug 7133495 8041740
+# @bug 7133495 8041740 8062264
# @summary [macosx] KeyChain KeyStore implementation retrieves only one private key entry
if [ "${TESTJAVA}" = "" ] ; then
@@ -30,6 +30,9 @@
TESTJAVA=`dirname $JAVAC_CMD`/..
fi
+if [ "${TESTSRC}" = "" ] ; then
+ TESTSRC="."
+fi
if [ "${TESTCLASSES}" = "" ] ; then
TESTCLASSES=`pwd`
fi
@@ -59,10 +62,6 @@
COUNT=`$KEYTOOL -list | grep PrivateKeyEntry | wc -l`
echo "Found $COUNT private key entries in the Keychain keystores"
-if [ $COUNT -gt 1 ]; then
- exit 0
-fi
-
# Create a temporary PKCS12 keystore containing 3 public/private keypairs
RESULT=`$CLEANUP_P12`
@@ -107,8 +106,9 @@
echo "Unlocked the temporary keychain"
# Import the keypairs from the PKCS12 keystore into the keychain
+# (The '-A' option is used to lower the temporary keychain's access controls)
-security import $TEMPORARY_P12 -k $TEMPORARY_KC -f pkcs12 -P $PWD
+security import $TEMPORARY_P12 -k $TEMPORARY_KC -f pkcs12 -P $PWD -A
if [ $? -ne 0 ]; then
echo "Error: cannot import keypairs from PKCS12 keystore into the keychain"
RESULT=`$CLEANUP_P12`
@@ -128,26 +128,39 @@
# Recount the number of private key entries in the Keychain keystores
-COUNT=`$KEYTOOL -list | grep PrivateKeyEntry | wc -l`
-echo "Found $COUNT private key entries in the Keychain keystore"
-if [ $COUNT -lt 3 ]; then
- echo "Error: expected >2 private key entries in the Keychain keystores"
+RECOUNT=`$KEYTOOL -list | grep PrivateKeyEntry | wc -l`
+echo "Found $RECOUNT private key entries in the Keychain keystore"
+if [ $RECOUNT -lt `expr $COUNT + 3` ]; then
+ echo "Error: expected >$COUNT private key entries in the Keychain keystores"
RESULT=`$CLEANUP_P12`
RESULT=`$CLEANUP_KC`
exit 5
fi
+# Export a private key from the keychain (without supplying a password)
+# Access controls have already been lowered (see 'security import ... -A' above)
+
+${TESTJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}/ExportPrivateKeyNoPwd.java || exit 6
+echo | ${TESTJAVA}/bin/java ${TESTVMOPTS} ExportPrivateKeyNoPwd x
+if [ $? -ne 0 ]; then
+ echo "Error exporting private key from the temporary keychain"
+ RESULT=`$CLEANUP_P12`
+ RESULT=`$CLEANUP_KC`
+ exit 6
+fi
+echo "Exported a private key from the temporary keychain"
+
RESULT=`$CLEANUP_P12`
if [ $? -ne 0 ]; then
echo "Error: cannot remove the temporary PKCS12 keystore"
- exit 6
+ exit 7
fi
echo "Removed the temporary PKCS12 keystore"
RESULT=`$CLEANUP_KC`
if [ $? -ne 0 ]; then
echo "Error: cannot remove the temporary keychain"
- exit 7
+ exit 8
fi
echo "Removed the temporary keychain"