diff --git a/src/macosx/classes/apple/security/KeychainStore.java b/src/macosx/classes/apple/security/KeychainStore.java index 2016c4811ab6caf97b0e39bded799ffb1e655894..c6c771a244c690d6701a174628562190929b616b 100644 --- a/src/macosx/classes/apple/security/KeychainStore.java +++ b/src/macosx/classes/apple/security/KeychainStore.java @@ -140,7 +140,8 @@ public final class KeychainStore extends KeyStoreSpi { * 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 key entry. @@ -155,6 +156,20 @@ public final class KeychainStore extends KeyStoreSpi { { 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)) { diff --git a/test/sun/security/tools/keytool/ExportPrivateKeyNoPwd.java b/test/sun/security/tools/keytool/ExportPrivateKeyNoPwd.java new file mode 100644 index 0000000000000000000000000000000000000000..799bf455b23d0a842cd9b92a442942b7ec6c04c2 --- /dev/null +++ b/test/sun/security/tools/keytool/ExportPrivateKeyNoPwd.java @@ -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"); + } + } +} + diff --git a/test/sun/security/tools/keytool/ListKeychainStore.sh b/test/sun/security/tools/keytool/ListKeychainStore.sh index b6e486c212e30d6487cf76e64ade498e2db068f9..17e1b5a92e29328db41e583db26ccbeee8646070 100644 --- a/test/sun/security/tools/keytool/ListKeychainStore.sh +++ b/test/sun/security/tools/keytool/ListKeychainStore.sh @@ -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 @@ if [ "${TESTJAVA}" = "" ] ; then TESTJAVA=`dirname $JAVAC_CMD`/.. fi +if [ "${TESTSRC}" = "" ] ; then + TESTSRC="." +fi if [ "${TESTCLASSES}" = "" ] ; then TESTCLASSES=`pwd` fi @@ -59,10 +62,6 @@ CLEANUP_LIST="rm -f $TEMPORARY_LIST" 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 @@ fi 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 @@ security list-keychains # 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"