JDK-8062264 : KeychainStore requires non-null password to be supplied when retrieving a private key
  • Type: Bug
  • Component: security-libs
  • Sub-Component: java.security
  • Affected Version: 7u71,8
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: os_x
  • Submitted: 2014-10-28
  • Updated: 2015-09-29
  • Resolved: 2014-10-29
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u60Fixed 9 b38Fixed
Description
The following issue (and patches) was reported by Florian Bruckner (florian.bruckner@3kraft.com):


KeychainStore does not load private keys when not called with a passphrase. This is the case in various deployment scenarios (like javaws), as a consequence identity certificates stored in Apple Keychain are not available (i.e. being offered for selection like on Windows).

The reason for this is the implementation of KeychainStore, which uses this API to retrieve a PKCS#12 container from apple keychain:

https://developer.apple.com/library/mac/documentation/security/Reference/keychainservices/Reference/reference.html#jumpTo_63

The API documentation says the PKCS#12 keystore being generated with this call requires a password. This is either supplied by the caller or the user is prompted (if a flag is set, which is not the case).

KeychainStore then goes on to extract the private key from the returned PKCS#12 store and decrypts it with the password.

Therefore, the password passed into engineGetKey is actually used to encrypt and decrypt only in the scope of this method. Therefore, the approach is to create a dummy password for this use case.

Please consider these patches to fix this issue:

For jdk7u-dev:

diff -r 35aabd00a534 src/macosx/classes/apple/security/KeychainStore.java
--- a/src/macosx/classes/apple/security/KeychainStore.java    Tue Jul 15 02:26:55 2014 +0400
+++ b/src/macosx/classes/apple/security/KeychainStore.java    Tue Jul 15 10:52:44 2014 +0200
@@ -134,7 +134,7 @@
    * 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 not used to access the private key in KeyChain, it is used internally only.
    *
    * @return the requested key, or null if the given alias does not exist
    * or does not identify a <i>key entry</i>.
@@ -148,6 +148,16 @@
       throws NoSuchAlgorithmException, UnrecoverableKeyException
   {
       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 to 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. Therefore use a single character.
+            password = new char[]{'A'}
+        }

       Object entry = entries.get(alias.toLowerCase());



For jdk8u-dev:

diff -r baec3649f6c0 src/macosx/classes/apple/security/KeychainStore.java
--- a/src/macosx/classes/apple/security/KeychainStore.java    Tue Jul 15 02:00:52 2014 +0400
+++ b/src/macosx/classes/apple/security/KeychainStore.java    Tue Jul 15 10:54:45 2014 +0200
@@ -140,7 +140,7 @@
    * 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 not used to access the private key in KeyChain, it is used internally only.
    *
    * @return the requested key, or null if the given alias does not exist
    * or does not identify a <i>key entry</i>.
@@ -154,7 +154,16 @@
       throws NoSuchAlgorithmException, UnrecoverableKeyException
   {
       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 to 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. Therefore use a single character.
+            password = new char[]{'A'}
+        }
       Object entry = entries.get(alias.toLowerCase());

       if (entry == null || !(entry instanceof KeyEntry)) {

Comments
The affected testcases pass in nightly result http://aurora.ru.oracle.com/functional/faces/RunDetails.xhtml?names=669066.CORELIBS-JDK-NIGHTLY-JTREG-16
26-12-2014