changeset 12607:007f014639d1

8086002: Move apple.security.AppleProvider to a proper module Summary: Move Apple provider to java.base module with "libosxsecurity" native library. Reviewed-by: mchung
author valeriep
date Tue, 18 Aug 2015 21:16:27 +0000
parents e5c1949e76bd
children 562b349a85da
files make/lib/Lib-java.base.gmk make/lib/Lib-jdk.deploy.osx.gmk make/lib/SecurityLibraries.gmk src/java.base/macosx/classes/apple/security/AppleProvider.java src/java.base/macosx/classes/apple/security/KeychainStore.java src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m src/java.base/share/classes/sun/security/jca/ProviderConfig.java src/jdk.deploy.osx/macosx/classes/apple/security/AppleProvider.java src/jdk.deploy.osx/macosx/classes/apple/security/KeychainStore.java src/jdk.deploy.osx/macosx/native/libosx/KeystoreImpl.m
diffstat 10 files changed, 1910 insertions(+), 1827 deletions(-) [+]
line wrap: on
line diff
--- a/make/lib/Lib-java.base.gmk	Tue Aug 18 12:49:00 2015 -0700
+++ b/make/lib/Lib-java.base.gmk	Tue Aug 18 21:16:27 2015 +0000
@@ -32,3 +32,4 @@
 include CoreLibraries.gmk
 include NetworkingLibraries.gmk
 include NioLibraries.gmk
+include SecurityLibraries.gmk
--- a/make/lib/Lib-jdk.deploy.osx.gmk	Tue Aug 18 12:49:00 2015 -0700
+++ b/make/lib/Lib-jdk.deploy.osx.gmk	Tue Aug 18 21:16:27 2015 +0000
@@ -80,7 +80,6 @@
           -framework ApplicationServices \
           -framework JavaNativeFoundation \
           -framework JavaRuntimeSupport \
-          -framework Security \
           -framework SystemConfiguration \
           $(LDFLAGS_JDKLIB_SUFFIX), \
       OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosx, \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/lib/SecurityLibraries.gmk	Tue Aug 18 21:16:27 2015 +0000
@@ -0,0 +1,63 @@
+#
+# Copyright (c) 2015, 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.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# 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.
+#
+
+include LibCommon.gmk
+
+ifeq ($(OPENJDK_TARGET_OS), macosx)
+
+  ################################################################################
+
+  LIBOSXSECURITY_DIRS := $(JDK_TOPDIR)/src/java.base/macosx/native/libosxsecurity
+  LIBOSXSECURITY_CFLAGS := -I$(LIBOSXSECURITY_DIRS) \
+      $(LIBJAVA_HEADER_FLAGS) \
+      -I$(SUPPORT_OUTPUTDIR)/headers/java.base \
+
+  $(eval $(call SetupNativeCompilation,BUILD_LIBOSXSECURITY, \
+      LIBRARY := osxsecurity, \
+      OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+      SRC := $(LIBOSXSECURITY_DIRS), \
+      OPTIMIZATION := LOW, \
+      CFLAGS := $(CFLAGS_JDKLIB) \
+          $(LIBOSXSECURITY_CFLAGS), \
+      DISABLED_WARNINGS_clang := deprecated-declarations, \
+      LDFLAGS := $(LDFLAGS_JDKLIB) \
+          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base \
+          $(call SET_SHARED_LIBRARY_ORIGIN), \
+      LDFLAGS_SUFFIX_macosx := \
+          -fobjc-link-runtime \
+          -framework JavaNativeFoundation \
+          -framework CoreServices \
+          -framework Security \
+          $(LDFLAGS_JDKLIB_SUFFIX), \
+      OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxsecurity, \
+      DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
+
+  $(BUILD_LIBOSXSECURITY): $(BUILD_LIBJAVA)
+
+  TARGETS += $(BUILD_LIBOSXSECURITY)
+
+  ################################################################################
+
+endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/macosx/classes/apple/security/AppleProvider.java	Tue Aug 18 21:16:27 2015 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011, 2015, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package apple.security;
+
+import java.security.*;
+
+/**
+ * The Apple Security Provider.
+ */
+
+/**
+ * Defines the Apple provider.
+ *
+ * This provider only exists to provide access to the Apple keychain-based KeyStore implementation
+ */
+@SuppressWarnings("serial") // JDK implementation class
+public final class AppleProvider extends Provider {
+
+    private static final String info = "Apple Provider";
+
+    private static final class ProviderService extends Provider.Service {
+        ProviderService(Provider p, String type, String algo, String cn) {
+            super(p, type, algo, cn, null, null);
+        }
+
+        @Override
+        public Object newInstance(Object ctrParamObj)
+            throws NoSuchAlgorithmException {
+            String type = getType();
+            if (ctrParamObj != null) {
+                throw new InvalidParameterException
+                    ("constructorParameter not used with " + type + " engines");
+            }
+
+            String algo = getAlgorithm();
+            try {
+                if (type.equals("KeyStore")) {
+                    if (algo.equals("KeychainStore")) {
+                        return new KeychainStore();
+                    }
+                }
+            } catch (Exception ex) {
+                throw new NoSuchAlgorithmException("Error constructing " +
+                    type + " for " + algo + " using Apple", ex);
+            }
+            throw new ProviderException("No impl for " + algo +
+                " " + type);
+        }
+    }
+
+
+    public AppleProvider() {
+        /* We are the Apple provider */
+        super("Apple", 1.9d, info);
+
+        final Provider p = this;
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                putService(new ProviderService(p, "KeyStore",
+                           "KeychainStore", "apple.security.KeychainStore"));
+                return null;
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/macosx/classes/apple/security/KeychainStore.java	Tue Aug 18 21:16:27 2015 +0000
@@ -0,0 +1,1149 @@
+/*
+ * Copyright (c) 2011, 2015, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package apple.security;
+
+import java.io.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.cert.Certificate;
+import java.security.spec.*;
+import java.util.*;
+
+import javax.crypto.*;
+import javax.crypto.spec.*;
+import javax.security.auth.x500.*;
+
+import sun.security.pkcs.*;
+import sun.security.pkcs.EncryptedPrivateKeyInfo;
+import sun.security.util.*;
+import sun.security.x509.*;
+
+/**
+ * This class provides the keystore implementation referred to as "KeychainStore".
+ * It uses the current user's keychain as its backing storage, and does NOT support
+ * a file-based implementation.
+ */
+
+public final class KeychainStore extends KeyStoreSpi {
+
+    // Private keys and their supporting certificate chains
+    // If a key came from the keychain it has a SecKeyRef and one or more
+    // SecCertificateRef.  When we delete the key we have to delete all of the corresponding
+    // native objects.
+    class KeyEntry {
+        Date date; // the creation date of this entry
+        byte[] protectedPrivKey;
+        char[] password;
+        long keyRef;  // SecKeyRef for this key
+        Certificate chain[];
+        long chainRefs[];  // SecCertificateRefs for this key's chain.
+    };
+
+    // Trusted certificates
+    class TrustedCertEntry {
+        Date date; // the creation date of this entry
+
+        Certificate cert;
+        long certRef;  // SecCertificateRef for this key
+    };
+
+    /**
+     * Entries that have been deleted.  When something calls engineStore we'll
+     * remove them from the keychain.
+     */
+    private Hashtable<String, Object> deletedEntries = new Hashtable<>();
+
+    /**
+     * Entries that have been added.  When something calls engineStore we'll
+     * add them to the keychain.
+     */
+    private Hashtable<String, Object> addedEntries = new Hashtable<>();
+
+    /**
+     * Private keys and certificates are stored in a hashtable.
+     * Hash entries are keyed by alias names.
+     */
+    private Hashtable<String, Object> entries = new Hashtable<>();
+
+    /**
+     * Algorithm identifiers and corresponding OIDs for the contents of the PKCS12 bag we get from the Keychain.
+     */
+    private static final int keyBag[]  = {1, 2, 840, 113549, 1, 12, 10, 1, 2};
+    private static final int pbeWithSHAAnd3KeyTripleDESCBC[] =     {1, 2, 840, 113549, 1, 12, 1, 3};
+    private static ObjectIdentifier PKCS8ShroudedKeyBag_OID;
+    private static ObjectIdentifier pbeWithSHAAnd3KeyTripleDESCBC_OID;
+
+    /**
+     * Constnats used in PBE decryption.
+     */
+    private static final int iterationCount = 1024;
+    private static final int SALT_LEN = 20;
+
+    static {
+        AccessController.doPrivileged(
+            new PrivilegedAction<Void>() {
+                public Void run() {
+                    System.loadLibrary("osxsecurity");
+                    return null;
+                }
+            });
+        try {
+            PKCS8ShroudedKeyBag_OID = new ObjectIdentifier(keyBag);
+            pbeWithSHAAnd3KeyTripleDESCBC_OID = new ObjectIdentifier(pbeWithSHAAnd3KeyTripleDESCBC);
+        } catch (IOException ioe) {
+            // should not happen
+        }
+    }
+
+    private static void permissionCheck() {
+        SecurityManager sec = System.getSecurityManager();
+
+        if (sec != null) {
+            sec.checkPermission(new RuntimePermission("useKeychainStore"));
+        }
+    }
+
+
+    /**
+     * Verify the Apple provider in the constructor.
+     *
+     * @exception SecurityException if fails to verify
+     * its own integrity
+     */
+    public KeychainStore() { }
+
+    /**
+        * Returns the key associated with the given alias, using the given
+     * password to recover it.
+     *
+     * @param alias the alias name
+     * @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>.
+     *
+     * @exception NoSuchAlgorithmException if the algorithm for recovering the
+     * key cannot be found
+     * @exception UnrecoverableKeyException if the key cannot be recovered
+     * (e.g., the given password is wrong).
+     */
+    public Key engineGetKey(String alias, char[] password)
+        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 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)) {
+            return null;
+        }
+
+        // This call gives us a PKCS12 bag, with the key inside it.
+        byte[] exportedKeyInfo = _getEncodedKeyData(((KeyEntry)entry).keyRef, password);
+        if (exportedKeyInfo == null) {
+            return null;
+        }
+
+        PrivateKey returnValue = null;
+
+        try {
+            byte[] pkcs8KeyData = fetchPrivateKeyFromBag(exportedKeyInfo);
+            byte[] encryptedKey;
+            AlgorithmParameters algParams;
+            ObjectIdentifier algOid;
+            try {
+                // get the encrypted private key
+                EncryptedPrivateKeyInfo encrInfo = new EncryptedPrivateKeyInfo(pkcs8KeyData);
+                encryptedKey = encrInfo.getEncryptedData();
+
+                // parse Algorithm parameters
+                DerValue val = new DerValue(encrInfo.getAlgorithm().encode());
+                DerInputStream in = val.toDerInputStream();
+                algOid = in.getOID();
+                algParams = parseAlgParameters(in);
+
+            } catch (IOException ioe) {
+                UnrecoverableKeyException uke =
+                new UnrecoverableKeyException("Private key not stored as "
+                                              + "PKCS#8 EncryptedPrivateKeyInfo: " + ioe);
+                uke.initCause(ioe);
+                throw uke;
+            }
+
+            // Use JCE to decrypt the data using the supplied password.
+            SecretKey skey = getPBEKey(password);
+            Cipher cipher = Cipher.getInstance(algOid.toString());
+            cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
+            byte[] decryptedPrivateKey = cipher.doFinal(encryptedKey);
+            PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(decryptedPrivateKey);
+
+             // Parse the key algorithm and then use a JCA key factory to create the private key.
+            DerValue val = new DerValue(decryptedPrivateKey);
+            DerInputStream in = val.toDerInputStream();
+
+            // Ignore this -- version should be 0.
+            int i = in.getInteger();
+
+            // Get the Algorithm ID next
+            DerValue[] value = in.getSequence(2);
+            AlgorithmId algId = new AlgorithmId(value[0].getOID());
+            String algName = algId.getName();
+
+            // Get a key factory for this algorithm.  It's likely to be 'RSA'.
+            KeyFactory kfac = KeyFactory.getInstance(algName);
+            returnValue = kfac.generatePrivate(kspec);
+        } catch (Exception e) {
+            UnrecoverableKeyException uke =
+            new UnrecoverableKeyException("Get Key failed: " +
+                                          e.getMessage());
+            uke.initCause(e);
+            throw uke;
+        }
+
+        return returnValue;
+    }
+
+    private native byte[] _getEncodedKeyData(long secKeyRef, char[] password);
+
+    /**
+     * Returns the certificate chain associated with the given alias.
+     *
+     * @param alias the alias name
+     *
+     * @return the certificate chain (ordered with the user's certificate first
+                                      * and the root certificate authority last), or null if the given alias
+     * does not exist or does not contain a certificate chain (i.e., the given
+                                                               * alias identifies either a <i>trusted certificate entry</i> or a
+                                                               * <i>key entry</i> without a certificate chain).
+     */
+    public Certificate[] engineGetCertificateChain(String alias) {
+        permissionCheck();
+
+        Object entry = entries.get(alias.toLowerCase());
+
+        if (entry != null && entry instanceof KeyEntry) {
+            if (((KeyEntry)entry).chain == null) {
+                return null;
+            } else {
+                return ((KeyEntry)entry).chain.clone();
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the certificate associated with the given alias.
+     *
+     * <p>If the given alias name identifies a
+     * <i>trusted certificate entry</i>, the certificate associated with that
+     * entry is returned. If the given alias name identifies a
+     * <i>key entry</i>, the first element of the certificate chain of that
+     * entry is returned, or null if that entry does not have a certificate
+     * chain.
+     *
+     * @param alias the alias name
+     *
+     * @return the certificate, or null if the given alias does not exist or
+     * does not contain a certificate.
+     */
+    public Certificate engineGetCertificate(String alias) {
+        permissionCheck();
+
+        Object entry = entries.get(alias.toLowerCase());
+
+        if (entry != null) {
+            if (entry instanceof TrustedCertEntry) {
+                return ((TrustedCertEntry)entry).cert;
+            } else {
+                KeyEntry ke = (KeyEntry)entry;
+                if (ke.chain == null || ke.chain.length == 0) {
+                    return null;
+                }
+                return ke.chain[0];
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+        * Returns the creation date of the entry identified by the given alias.
+     *
+     * @param alias the alias name
+     *
+     * @return the creation date of this entry, or null if the given alias does
+     * not exist
+     */
+    public Date engineGetCreationDate(String alias) {
+        permissionCheck();
+
+        Object entry = entries.get(alias.toLowerCase());
+
+        if (entry != null) {
+            if (entry instanceof TrustedCertEntry) {
+                return new Date(((TrustedCertEntry)entry).date.getTime());
+            } else {
+                return new Date(((KeyEntry)entry).date.getTime());
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+        * Assigns the given key to the given alias, protecting it with the given
+     * password.
+     *
+     * <p>If the given key is of type <code>java.security.PrivateKey</code>,
+     * it must be accompanied by a certificate chain certifying the
+     * corresponding public key.
+     *
+     * <p>If the given alias already exists, the keystore information
+     * associated with it is overridden by the given key (and possibly
+                                                          * certificate chain).
+     *
+     * @param alias the alias name
+     * @param key the key to be associated with the alias
+     * @param password the password to protect the key
+     * @param chain the certificate chain for the corresponding public
+     * key (only required if the given key is of type
+            * <code>java.security.PrivateKey</code>).
+     *
+     * @exception KeyStoreException if the given key cannot be protected, or
+     * this operation fails for some other reason
+     */
+    public void engineSetKeyEntry(String alias, Key key, char[] password,
+                                  Certificate[] chain)
+        throws KeyStoreException
+    {
+        permissionCheck();
+
+        synchronized(entries) {
+            try {
+                KeyEntry entry = new KeyEntry();
+                entry.date = new Date();
+
+                if (key instanceof PrivateKey) {
+                    if ((key.getFormat().equals("PKCS#8")) ||
+                        (key.getFormat().equals("PKCS8"))) {
+                        entry.protectedPrivKey = encryptPrivateKey(key.getEncoded(), password);
+                        entry.password = password.clone();
+                    } else {
+                        throw new KeyStoreException("Private key is not encoded as PKCS#8");
+                    }
+                } else {
+                    throw new KeyStoreException("Key is not a PrivateKey");
+                }
+
+                // clone the chain
+                if (chain != null) {
+                    if ((chain.length > 1) && !validateChain(chain)) {
+                        throw new KeyStoreException("Certificate chain does not validate");
+                    }
+
+                    entry.chain = chain.clone();
+                    entry.chainRefs = new long[entry.chain.length];
+                }
+
+                String lowerAlias = alias.toLowerCase();
+                if (entries.get(lowerAlias) != null) {
+                    deletedEntries.put(lowerAlias, entries.get(lowerAlias));
+                }
+
+                entries.put(lowerAlias, entry);
+                addedEntries.put(lowerAlias, entry);
+            } catch (Exception nsae) {
+                KeyStoreException ke = new KeyStoreException("Key protection algorithm not found: " + nsae);
+                ke.initCause(nsae);
+                throw ke;
+            }
+        }
+    }
+
+    /**
+        * Assigns the given key (that has already been protected) to the given
+     * alias.
+     *
+     * <p>If the protected key is of type
+     * <code>java.security.PrivateKey</code>, it must be accompanied by a
+     * certificate chain certifying the corresponding public key. If the
+     * underlying keystore implementation is of type <code>jks</code>,
+     * <code>key</code> must be encoded as an
+     * <code>EncryptedPrivateKeyInfo</code> as defined in the PKCS #8 standard.
+     *
+     * <p>If the given alias already exists, the keystore information
+     * associated with it is overridden by the given key (and possibly
+                                                          * certificate chain).
+     *
+     * @param alias the alias name
+     * @param key the key (in protected format) to be associated with the alias
+     * @param chain the certificate chain for the corresponding public
+     * key (only useful if the protected key is of type
+            * <code>java.security.PrivateKey</code>).
+     *
+     * @exception KeyStoreException if this operation fails.
+     */
+    public void engineSetKeyEntry(String alias, byte[] key,
+                                  Certificate[] chain)
+        throws KeyStoreException
+    {
+        permissionCheck();
+
+        synchronized(entries) {
+            // key must be encoded as EncryptedPrivateKeyInfo as defined in
+            // PKCS#8
+            KeyEntry entry = new KeyEntry();
+            try {
+                EncryptedPrivateKeyInfo privateKey = new EncryptedPrivateKeyInfo(key);
+                entry.protectedPrivKey = privateKey.getEncoded();
+            } catch (IOException ioe) {
+                throw new KeyStoreException("key is not encoded as "
+                                            + "EncryptedPrivateKeyInfo");
+            }
+
+            entry.date = new Date();
+
+            if ((chain != null) &&
+                (chain.length != 0)) {
+                entry.chain = chain.clone();
+                entry.chainRefs = new long[entry.chain.length];
+            }
+
+            String lowerAlias = alias.toLowerCase();
+            if (entries.get(lowerAlias) != null) {
+                deletedEntries.put(lowerAlias, entries.get(alias));
+            }
+            entries.put(lowerAlias, entry);
+            addedEntries.put(lowerAlias, entry);
+        }
+    }
+
+    /**
+        * Assigns the given certificate to the given alias.
+     *
+     * <p>If the given alias already exists in this keystore and identifies a
+     * <i>trusted certificate entry</i>, the certificate associated with it is
+     * overridden by the given certificate.
+     *
+     * @param alias the alias name
+     * @param cert the certificate
+     *
+     * @exception KeyStoreException if the given alias already exists and does
+     * not identify a <i>trusted certificate entry</i>, or this operation
+     * fails for some other reason.
+     */
+    public void engineSetCertificateEntry(String alias, Certificate cert)
+        throws KeyStoreException
+    {
+        permissionCheck();
+
+        synchronized(entries) {
+
+            Object entry = entries.get(alias.toLowerCase());
+            if ((entry != null) && (entry instanceof KeyEntry)) {
+                throw new KeyStoreException
+                ("Cannot overwrite key entry with certificate");
+            }
+
+            // This will be slow, but necessary.  Enumerate the values and then see if the cert matches the one in the trusted cert entry.
+            // Security framework doesn't support the same certificate twice in a keychain.
+            Collection<Object> allValues = entries.values();
+
+            for (Object value : allValues) {
+                if (value instanceof TrustedCertEntry) {
+                    TrustedCertEntry tce = (TrustedCertEntry)value;
+                    if (tce.cert.equals(cert)) {
+                        throw new KeyStoreException("Keychain does not support mulitple copies of same certificate.");
+                    }
+                }
+            }
+
+            TrustedCertEntry trustedCertEntry = new TrustedCertEntry();
+            trustedCertEntry.cert = cert;
+            trustedCertEntry.date = new Date();
+            String lowerAlias = alias.toLowerCase();
+            if (entries.get(lowerAlias) != null) {
+                deletedEntries.put(lowerAlias, entries.get(lowerAlias));
+            }
+            entries.put(lowerAlias, trustedCertEntry);
+            addedEntries.put(lowerAlias, trustedCertEntry);
+        }
+    }
+
+    /**
+        * Deletes the entry identified by the given alias from this keystore.
+     *
+     * @param alias the alias name
+     *
+     * @exception KeyStoreException if the entry cannot be removed.
+     */
+    public void engineDeleteEntry(String alias)
+        throws KeyStoreException
+    {
+        permissionCheck();
+
+        synchronized(entries) {
+            Object entry = entries.remove(alias.toLowerCase());
+            deletedEntries.put(alias.toLowerCase(), entry);
+        }
+    }
+
+    /**
+        * Lists all the alias names of this keystore.
+     *
+     * @return enumeration of the alias names
+     */
+    public Enumeration<String> engineAliases() {
+        permissionCheck();
+        return entries.keys();
+    }
+
+    /**
+        * Checks if the given alias exists in this keystore.
+     *
+     * @param alias the alias name
+     *
+     * @return true if the alias exists, false otherwise
+     */
+    public boolean engineContainsAlias(String alias) {
+        permissionCheck();
+        return entries.containsKey(alias.toLowerCase());
+    }
+
+    /**
+        * Retrieves the number of entries in this keystore.
+     *
+     * @return the number of entries in this keystore
+     */
+    public int engineSize() {
+        permissionCheck();
+        return entries.size();
+    }
+
+    /**
+        * Returns true if the entry identified by the given alias is a
+     * <i>key entry</i>, and false otherwise.
+     *
+     * @return true if the entry identified by the given alias is a
+     * <i>key entry</i>, false otherwise.
+     */
+    public boolean engineIsKeyEntry(String alias) {
+        permissionCheck();
+        Object entry = entries.get(alias.toLowerCase());
+        if ((entry != null) && (entry instanceof KeyEntry)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+        * Returns true if the entry identified by the given alias is a
+     * <i>trusted certificate entry</i>, and false otherwise.
+     *
+     * @return true if the entry identified by the given alias is a
+     * <i>trusted certificate entry</i>, false otherwise.
+     */
+    public boolean engineIsCertificateEntry(String alias) {
+        permissionCheck();
+        Object entry = entries.get(alias.toLowerCase());
+        if ((entry != null) && (entry instanceof TrustedCertEntry)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+        * Returns the (alias) name of the first keystore entry whose certificate
+     * matches the given certificate.
+     *
+     * <p>This method attempts to match the given certificate with each
+     * keystore entry. If the entry being considered
+     * is a <i>trusted certificate entry</i>, the given certificate is
+     * compared to that entry's certificate. If the entry being considered is
+     * a <i>key entry</i>, the given certificate is compared to the first
+     * element of that entry's certificate chain (if a chain exists).
+     *
+     * @param cert the certificate to match with.
+     *
+     * @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) {
+        permissionCheck();
+        Certificate certElem;
+
+        for (Enumeration<String> e = entries.keys(); e.hasMoreElements(); ) {
+            String alias = e.nextElement();
+            Object entry = entries.get(alias);
+            if (entry instanceof TrustedCertEntry) {
+                certElem = ((TrustedCertEntry)entry).cert;
+            } else {
+                KeyEntry ke = (KeyEntry)entry;
+                if (ke.chain == null || ke.chain.length == 0) {
+                    continue;
+                }
+                certElem = ke.chain[0];
+            }
+            if (certElem.equals(cert)) {
+                return alias;
+            }
+        }
+        return null;
+    }
+
+    /**
+        * Stores this keystore to the given output stream, and protects its
+     * integrity with the given password.
+     *
+     * @param stream Ignored. the output stream to which this keystore is written.
+     * @param password the password to generate the keystore integrity check
+     *
+     * @exception IOException if there was an I/O problem with data
+     * @exception NoSuchAlgorithmException if the appropriate data integrity
+     * algorithm could not be found
+     * @exception CertificateException if any of the certificates included in
+     * the keystore data could not be stored
+     */
+    public void engineStore(OutputStream stream, char[] password)
+        throws IOException, NoSuchAlgorithmException, CertificateException
+    {
+        permissionCheck();
+
+        // Delete items that do have a keychain item ref.
+        for (Enumeration<String> e = deletedEntries.keys(); e.hasMoreElements(); ) {
+            String alias = e.nextElement();
+            Object entry = deletedEntries.get(alias);
+            if (entry instanceof TrustedCertEntry) {
+                if (((TrustedCertEntry)entry).certRef != 0) {
+                    _removeItemFromKeychain(((TrustedCertEntry)entry).certRef);
+                    _releaseKeychainItemRef(((TrustedCertEntry)entry).certRef);
+                }
+            } else {
+                Certificate certElem;
+                KeyEntry keyEntry = (KeyEntry)entry;
+
+                if (keyEntry.chain != null) {
+                    for (int i = 0; i < keyEntry.chain.length; i++) {
+                        if (keyEntry.chainRefs[i] != 0) {
+                            _removeItemFromKeychain(keyEntry.chainRefs[i]);
+                            _releaseKeychainItemRef(keyEntry.chainRefs[i]);
+                        }
+                    }
+
+                    if (keyEntry.keyRef != 0) {
+                        _removeItemFromKeychain(keyEntry.keyRef);
+                        _releaseKeychainItemRef(keyEntry.keyRef);
+                    }
+                }
+            }
+        }
+
+        // Add all of the certs or keys in the added entries.
+        // No need to check for 0 refs, as they are in the added list.
+        for (Enumeration<String> e = addedEntries.keys(); e.hasMoreElements(); ) {
+            String alias = e.nextElement();
+            Object entry = addedEntries.get(alias);
+            if (entry instanceof TrustedCertEntry) {
+                TrustedCertEntry tce = (TrustedCertEntry)entry;
+                Certificate certElem;
+                certElem = tce.cert;
+                tce.certRef = addCertificateToKeychain(alias, certElem);
+            } else {
+                KeyEntry keyEntry = (KeyEntry)entry;
+
+                if (keyEntry.chain != null) {
+                    for (int i = 0; i < keyEntry.chain.length; i++) {
+                        keyEntry.chainRefs[i] = addCertificateToKeychain(alias, keyEntry.chain[i]);
+                    }
+
+                    keyEntry.keyRef = _addItemToKeychain(alias, false, keyEntry.protectedPrivKey, keyEntry.password);
+                }
+            }
+        }
+
+        // Clear the added and deletedEntries hashtables here, now that we're done with the updates.
+        // For the deleted entries, we freed up the native references above.
+        deletedEntries.clear();
+        addedEntries.clear();
+    }
+
+    private long addCertificateToKeychain(String alias, Certificate cert) {
+        byte[] certblob = null;
+        long returnValue = 0;
+
+        try {
+            certblob = cert.getEncoded();
+            returnValue = _addItemToKeychain(alias, true, certblob, null);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return returnValue;
+    }
+
+    private native long _addItemToKeychain(String alias, boolean isCertificate, byte[] datablob, char[] password);
+    private native int _removeItemFromKeychain(long certRef);
+    private native void _releaseKeychainItemRef(long keychainItemRef);
+
+    /**
+      * Loads the keystore from the Keychain.
+     *
+     * @param stream Ignored - here for API compatibility.
+     * @param password Ignored - if user needs to unlock keychain Security
+     * framework will post any dialogs.
+     *
+     * @exception IOException if there is an I/O or format problem with the
+     * keystore data
+     * @exception NoSuchAlgorithmException if the algorithm used to check
+     * the integrity of the keystore cannot be found
+     * @exception CertificateException if any of the certificates in the
+     * keystore could not be loaded
+     */
+    public void engineLoad(InputStream stream, char[] password)
+        throws IOException, NoSuchAlgorithmException, CertificateException
+    {
+        permissionCheck();
+
+        // Release any stray keychain references before clearing out the entries.
+        synchronized(entries) {
+            for (Enumeration<String> e = entries.keys(); e.hasMoreElements(); ) {
+                String alias = e.nextElement();
+                Object entry = entries.get(alias);
+                if (entry instanceof TrustedCertEntry) {
+                    if (((TrustedCertEntry)entry).certRef != 0) {
+                        _releaseKeychainItemRef(((TrustedCertEntry)entry).certRef);
+                    }
+                } else {
+                    KeyEntry keyEntry = (KeyEntry)entry;
+
+                    if (keyEntry.chain != null) {
+                        for (int i = 0; i < keyEntry.chain.length; i++) {
+                            if (keyEntry.chainRefs[i] != 0) {
+                                _releaseKeychainItemRef(keyEntry.chainRefs[i]);
+                            }
+                        }
+
+                        if (keyEntry.keyRef != 0) {
+                            _releaseKeychainItemRef(keyEntry.keyRef);
+                        }
+                    }
+                }
+            }
+
+            entries.clear();
+            _scanKeychain();
+        }
+    }
+
+    private native void _scanKeychain();
+
+    /**
+     * Callback method from _scanKeychain.  If a trusted certificate is found, this method will be called.
+     */
+    private void createTrustedCertEntry(String alias, long keychainItemRef, long creationDate, byte[] derStream) {
+        TrustedCertEntry tce = new TrustedCertEntry();
+
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            InputStream input = new ByteArrayInputStream(derStream);
+            X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
+            input.close();
+            tce.cert = cert;
+            tce.certRef = keychainItemRef;
+
+            // Make a creation date.
+            if (creationDate != 0)
+                tce.date = new Date(creationDate);
+            else
+                tce.date = new Date();
+
+            int uniqueVal = 1;
+            String originalAlias = alias;
+
+            while (entries.containsKey(alias.toLowerCase())) {
+                alias = originalAlias + " " + uniqueVal;
+                uniqueVal++;
+            }
+
+            entries.put(alias.toLowerCase(), tce);
+        } catch (Exception e) {
+            // The certificate will be skipped.
+            System.err.println("KeychainStore Ignored Exception: " + e);
+        }
+    }
+
+    /**
+     * Callback method from _scanKeychain.  If an identity is found, this method will be called to create Java certificate
+     * and private key objects from the keychain data.
+     */
+    private void createKeyEntry(String alias, long creationDate, long secKeyRef, long[] secCertificateRefs, byte[][] rawCertData)
+        throws IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
+        KeyEntry ke = new KeyEntry();
+
+        // First, store off the private key information.  This is the easy part.
+        ke.protectedPrivKey = null;
+        ke.keyRef = secKeyRef;
+
+        // Make a creation date.
+        if (creationDate != 0)
+            ke.date = new Date(creationDate);
+        else
+            ke.date = new Date();
+
+        // Next, create X.509 Certificate objects from the raw data.  This is complicated
+        // because a certificate's public key may be too long for Java's default encryption strength.
+        List<CertKeychainItemPair> createdCerts = new ArrayList<>();
+
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+            for (int i = 0; i < rawCertData.length; i++) {
+                try {
+                    InputStream input = new ByteArrayInputStream(rawCertData[i]);
+                    X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
+                    input.close();
+
+                    // We successfully created the certificate, so track it and its corresponding SecCertificateRef.
+                    createdCerts.add(new CertKeychainItemPair(secCertificateRefs[i], cert));
+                } catch (CertificateException e) {
+                    // The certificate will be skipped.
+                    System.err.println("KeychainStore Ignored Exception: " + e);
+                }
+            }
+        } catch (CertificateException e) {
+            e.printStackTrace();
+        } catch (IOException ioe) {
+            ioe.printStackTrace();  // How would this happen?
+        }
+
+        // We have our certificates in the List, so now extract them into an array of
+        // Certificates and SecCertificateRefs.
+        CertKeychainItemPair[] objArray = createdCerts.toArray(new CertKeychainItemPair[0]);
+        Certificate[] certArray = new Certificate[objArray.length];
+        long[] certRefArray = new long[objArray.length];
+
+        for (int i = 0; i < objArray.length; i++) {
+            CertKeychainItemPair addedItem = objArray[i];
+            certArray[i] = addedItem.mCert;
+            certRefArray[i] = addedItem.mCertificateRef;
+        }
+
+        ke.chain = certArray;
+        ke.chainRefs = certRefArray;
+
+        // If we don't have already have an item with this item's alias
+        // create a new one for it.
+        int uniqueVal = 1;
+        String originalAlias = alias;
+
+        while (entries.containsKey(alias.toLowerCase())) {
+            alias = originalAlias + " " + uniqueVal;
+            uniqueVal++;
+        }
+
+        entries.put(alias.toLowerCase(), ke);
+    }
+
+    private class CertKeychainItemPair {
+        long mCertificateRef;
+        Certificate mCert;
+
+        CertKeychainItemPair(long inCertRef, Certificate cert) {
+            mCertificateRef = inCertRef;
+            mCert = cert;
+        }
+    }
+
+    /*
+     * Validate Certificate Chain
+     */
+    private boolean validateChain(Certificate[] certChain)
+    {
+        for (int i = 0; i < certChain.length-1; i++) {
+            X500Principal issuerDN =
+            ((X509Certificate)certChain[i]).getIssuerX500Principal();
+            X500Principal subjectDN =
+                ((X509Certificate)certChain[i+1]).getSubjectX500Principal();
+            if (!(issuerDN.equals(subjectDN)))
+                return false;
+        }
+        return true;
+    }
+
+    @SuppressWarnings("deprecation")
+    private byte[] fetchPrivateKeyFromBag(byte[] privateKeyInfo) throws IOException, NoSuchAlgorithmException, CertificateException
+    {
+        byte[] returnValue = null;
+        DerValue val = new DerValue(new ByteArrayInputStream(privateKeyInfo));
+        DerInputStream s = val.toDerInputStream();
+        int version = s.getInteger();
+
+        if (version != 3) {
+            throw new IOException("PKCS12 keystore not in version 3 format");
+        }
+
+        /*
+            * Read the authSafe.
+         */
+        byte[] authSafeData;
+        ContentInfo authSafe = new ContentInfo(s);
+        ObjectIdentifier contentType = authSafe.getContentType();
+
+        if (contentType.equals(ContentInfo.DATA_OID)) {
+            authSafeData = authSafe.getData();
+        } else /* signed data */ {
+            throw new IOException("public key protected PKCS12 not supported");
+        }
+
+        DerInputStream as = new DerInputStream(authSafeData);
+        DerValue[] safeContentsArray = as.getSequence(2);
+        int count = safeContentsArray.length;
+
+        /*
+         * Spin over the ContentInfos.
+         */
+        for (int i = 0; i < count; i++) {
+            byte[] safeContentsData;
+            ContentInfo safeContents;
+            DerInputStream sci;
+            byte[] eAlgId = null;
+
+            sci = new DerInputStream(safeContentsArray[i].toByteArray());
+            safeContents = new ContentInfo(sci);
+            contentType = safeContents.getContentType();
+            safeContentsData = null;
+
+            if (contentType.equals(ContentInfo.DATA_OID)) {
+                safeContentsData = safeContents.getData();
+            } else if (contentType.equals(ContentInfo.ENCRYPTED_DATA_OID)) {
+                // The password was used to export the private key from the keychain.
+                // The Keychain won't export the key with encrypted data, so we don't need
+                // to worry about it.
+                continue;
+            } else {
+                throw new IOException("public key protected PKCS12" +
+                                      " not supported");
+            }
+            DerInputStream sc = new DerInputStream(safeContentsData);
+            returnValue = extractKeyData(sc);
+        }
+
+        return returnValue;
+    }
+
+    @SuppressWarnings("deprecation")
+    private byte[] extractKeyData(DerInputStream stream)
+        throws IOException, NoSuchAlgorithmException, CertificateException
+    {
+        byte[] returnValue = null;
+        DerValue[] safeBags = stream.getSequence(2);
+        int count = safeBags.length;
+
+        /*
+         * Spin over the SafeBags.
+         */
+        for (int i = 0; i < count; i++) {
+            ObjectIdentifier bagId;
+            DerInputStream sbi;
+            DerValue bagValue;
+            Object bagItem = null;
+
+            sbi = safeBags[i].toDerInputStream();
+            bagId = sbi.getOID();
+            bagValue = sbi.getDerValue();
+            if (!bagValue.isContextSpecific((byte)0)) {
+                throw new IOException("unsupported PKCS12 bag value type "
+                                      + bagValue.tag);
+            }
+            bagValue = bagValue.data.getDerValue();
+            if (bagId.equals(PKCS8ShroudedKeyBag_OID)) {
+                // got what we were looking for.  Return it.
+                returnValue = bagValue.toByteArray();
+            } else {
+                // log error message for "unsupported PKCS12 bag type"
+                System.out.println("Unsupported bag type '" + bagId + "'");
+            }
+        }
+
+        return returnValue;
+    }
+
+    /*
+        * Generate PBE Algorithm Parameters
+     */
+    private AlgorithmParameters getAlgorithmParameters(String algorithm)
+        throws IOException
+    {
+        AlgorithmParameters algParams = null;
+
+        // create PBE parameters from salt and iteration count
+        PBEParameterSpec paramSpec =
+            new PBEParameterSpec(getSalt(), iterationCount);
+        try {
+            algParams = AlgorithmParameters.getInstance(algorithm);
+            algParams.init(paramSpec);
+        } catch (Exception e) {
+            IOException ioe =
+            new IOException("getAlgorithmParameters failed: " +
+                            e.getMessage());
+            ioe.initCause(e);
+            throw ioe;
+        }
+        return algParams;
+    }
+
+    // the source of randomness
+    private SecureRandom random;
+
+    /*
+     * Generate random salt
+     */
+    private byte[] getSalt()
+    {
+        // Generate a random salt.
+        byte[] salt = new byte[SALT_LEN];
+        if (random == null) {
+            random = new SecureRandom();
+        }
+        salt = random.generateSeed(SALT_LEN);
+        return salt;
+    }
+
+    /*
+     * parse Algorithm Parameters
+     */
+    private AlgorithmParameters parseAlgParameters(DerInputStream in)
+        throws IOException
+    {
+        AlgorithmParameters algParams = null;
+        try {
+            DerValue params;
+            if (in.available() == 0) {
+                params = null;
+            } else {
+                params = in.getDerValue();
+                if (params.tag == DerValue.tag_Null) {
+                    params = null;
+                }
+            }
+            if (params != null) {
+                algParams = AlgorithmParameters.getInstance("PBE");
+                algParams.init(params.toByteArray());
+            }
+        } catch (Exception e) {
+            IOException ioe =
+            new IOException("parseAlgParameters failed: " +
+                            e.getMessage());
+            ioe.initCause(e);
+            throw ioe;
+        }
+        return algParams;
+    }
+
+    /*
+     * Generate PBE key
+     */
+    private SecretKey getPBEKey(char[] password) throws IOException
+    {
+        SecretKey skey = null;
+
+        try {
+            PBEKeySpec keySpec = new PBEKeySpec(password);
+            SecretKeyFactory skFac = SecretKeyFactory.getInstance("PBE");
+            skey = skFac.generateSecret(keySpec);
+        } catch (Exception e) {
+            IOException ioe = new IOException("getSecretKey failed: " +
+                                              e.getMessage());
+            ioe.initCause(e);
+            throw ioe;
+        }
+        return skey;
+    }
+
+    /*
+     * Encrypt private key using Password-based encryption (PBE)
+     * as defined in PKCS#5.
+     *
+     * NOTE: Currently pbeWithSHAAnd3-KeyTripleDES-CBC algorithmID is
+     *       used to derive the key and IV.
+     *
+     * @return encrypted private key encoded as EncryptedPrivateKeyInfo
+     */
+    private byte[] encryptPrivateKey(byte[] data, char[] password)
+        throws IOException, NoSuchAlgorithmException, UnrecoverableKeyException
+    {
+        byte[] key = null;
+
+        try {
+            // create AlgorithmParameters
+            AlgorithmParameters algParams =
+            getAlgorithmParameters("PBEWithSHA1AndDESede");
+
+            // Use JCE
+            SecretKey skey = getPBEKey(password);
+            Cipher cipher = Cipher.getInstance("PBEWithSHA1AndDESede");
+            cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
+            byte[] encryptedKey = cipher.doFinal(data);
+
+            // wrap encrypted private key in EncryptedPrivateKeyInfo
+            // as defined in PKCS#8
+            AlgorithmId algid =
+                new AlgorithmId(pbeWithSHAAnd3KeyTripleDESCBC_OID, algParams);
+            EncryptedPrivateKeyInfo encrInfo =
+                new EncryptedPrivateKeyInfo(algid, encryptedKey);
+            key = encrInfo.getEncoded();
+        } catch (Exception e) {
+            UnrecoverableKeyException uke =
+            new UnrecoverableKeyException("Encrypt Private Key failed: "
+                                          + e.getMessage());
+            uke.initCause(e);
+            throw uke;
+        }
+
+        return key;
+    }
+
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m	Tue Aug 18 21:16:27 2015 +0000
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2011, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 "apple_security_KeychainStore.h"
+
+#import <Security/Security.h>
+#import <Security/SecImportExport.h>
+#import <CoreServices/CoreServices.h>  // (for require() macros)
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+
+static JNF_CLASS_CACHE(jc_KeychainStore, "apple/security/KeychainStore");
+static JNF_MEMBER_CACHE(jm_createTrustedCertEntry, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;JJ[B)V");
+static JNF_MEMBER_CACHE(jm_createKeyEntry, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
+
+static jstring getLabelFromItem(JNIEnv *env, SecKeychainItemRef inItem)
+{
+    OSStatus status;
+    jstring returnValue = NULL;
+    char *attribCString = NULL;
+
+    SecKeychainAttribute itemAttrs[] = { { kSecLabelItemAttr, 0, NULL } };
+    SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
+
+    status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
+
+    if(status) {
+        cssmPerror("getLabelFromItem: SecKeychainItemCopyContent", status);
+        goto errOut;
+    }
+
+    attribCString = malloc(itemAttrs[0].length + 1);
+    strncpy(attribCString, itemAttrs[0].data, itemAttrs[0].length);
+    attribCString[itemAttrs[0].length] = '\0';
+    returnValue = (*env)->NewStringUTF(env, attribCString);
+
+errOut:
+    SecKeychainItemFreeContent(&attrList, NULL);
+    if (attribCString) free(attribCString);
+    return returnValue;
+}
+
+static jlong getModDateFromItem(JNIEnv *env, SecKeychainItemRef inItem)
+{
+    OSStatus status;
+    SecKeychainAttribute itemAttrs[] = { { kSecModDateItemAttr, 0, NULL } };
+    SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
+    jlong returnValue = 0;
+
+    status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
+
+    if(status) {
+        // This is almost always missing, so don't dump an error.
+        // cssmPerror("getModDateFromItem: SecKeychainItemCopyContent", status);
+        goto errOut;
+    }
+
+    memcpy(&returnValue, itemAttrs[0].data, itemAttrs[0].length);
+
+errOut:
+    SecKeychainItemFreeContent(&attrList, NULL);
+    return returnValue;
+}
+
+static void setLabelForItem(NSString *inLabel, SecKeychainItemRef inItem)
+{
+    OSStatus status;
+    const char *labelCString = [inLabel UTF8String];
+
+    // Set up attribute vector (each attribute consists of {tag, length, pointer}):
+    SecKeychainAttribute attrs[] = {
+        { kSecLabelItemAttr, strlen(labelCString), (void *)labelCString }
+    };
+
+    const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
+
+    // Not changing data here, just attributes.
+    status = SecKeychainItemModifyContent(inItem, &attributes, 0, NULL);
+
+    if(status) {
+        cssmPerror("setLabelForItem: SecKeychainItemModifyContent", status);
+    }
+}
+
+/*
+ * Given a SecIdentityRef, do our best to construct a complete, ordered, and
+ * verified cert chain, returning the result in a CFArrayRef. The result is
+ * can be passed back to Java as a chain for a private key.
+ */
+static OSStatus completeCertChain(
+                                     SecIdentityRef         identity,
+                                     SecCertificateRef    trustedAnchor,    // optional additional trusted anchor
+                                     bool                 includeRoot,     // include the root in outArray
+                                     CFArrayRef            *outArray)        // created and RETURNED
+{
+    SecTrustRef                    secTrust = NULL;
+    SecPolicyRef                policy = NULL;
+    SecPolicySearchRef            policySearch = NULL;
+    SecTrustResultType            secTrustResult;
+    CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv;            // not used
+    CFArrayRef                    certChain = NULL;   // constructed chain, CERTS ONLY
+    CFMutableArrayRef             subjCerts;            // passed to SecTrust
+    CFMutableArrayRef             certArray;            // returned array starting with
+                                                    //   identity
+    CFIndex                     numResCerts;
+    CFIndex                     dex;
+    OSStatus                     ortn;
+      SecCertificateRef             certRef;
+
+    /* First element in out array is the SecIdentity */
+    certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+    CFArrayAppendValue(certArray, identity);
+
+    /* the single element in certs-to-be-evaluated comes from the identity */
+       ortn = SecIdentityCopyCertificate(identity, &certRef);
+    if(ortn) {
+        /* should never happen */
+        cssmPerror("SecIdentityCopyCertificate", ortn);
+        return ortn;
+    }
+
+    /*
+     * Now use SecTrust to get a complete cert chain, using all of the
+     * user's keychains to look for intermediate certs.
+     * NOTE this does NOT handle root certs which are not in the system
+     * root cert DB.
+     */
+    subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
+    CFArraySetValueAtIndex(subjCerts, 0, certRef);
+
+    /* the array owns the subject cert ref now */
+    CFRelease(certRef);
+
+    /* Get a SecPolicyRef for generic X509 cert chain verification */
+    ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
+                                 &CSSMOID_APPLE_X509_BASIC,
+                                 NULL,                // value
+                                 &policySearch);
+    if(ortn) {
+        /* should never happen */
+        cssmPerror("SecPolicySearchCreate", ortn);
+        goto errOut;
+    }
+    ortn = SecPolicySearchCopyNext(policySearch, &policy);
+    if(ortn) {
+        /* should never happen */
+        cssmPerror("SecPolicySearchCopyNext", ortn);
+        goto errOut;
+    }
+
+    /* build a SecTrustRef for specified policy and certs */
+    ortn = SecTrustCreateWithCertificates(subjCerts,
+                                          policy, &secTrust);
+    if(ortn) {
+        cssmPerror("SecTrustCreateWithCertificates", ortn);
+        goto errOut;
+    }
+
+    if(trustedAnchor) {
+        /*
+        * Tell SecTrust to trust this one in addition to the current
+         * trusted system-wide anchors.
+         */
+        CFMutableArrayRef newAnchors;
+        CFArrayRef currAnchors;
+
+        ortn = SecTrustCopyAnchorCertificates(&currAnchors);
+        if(ortn) {
+            /* should never happen */
+            cssmPerror("SecTrustCopyAnchorCertificates", ortn);
+            goto errOut;
+        }
+        newAnchors = CFArrayCreateMutableCopy(NULL,
+                                              CFArrayGetCount(currAnchors) + 1,
+                                              currAnchors);
+        CFRelease(currAnchors);
+        CFArrayAppendValue(newAnchors, trustedAnchor);
+        ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);
+        CFRelease(newAnchors);
+        if(ortn) {
+            cssmPerror("SecTrustSetAnchorCertificates", ortn);
+            goto errOut;
+        }
+    }
+
+    /* evaluate: GO */
+    ortn = SecTrustEvaluate(secTrust, &secTrustResult);
+    if(ortn) {
+        cssmPerror("SecTrustEvaluate", ortn);
+        goto errOut;
+    }
+    switch(secTrustResult) {
+        case kSecTrustResultUnspecified:
+            /* cert chain valid, no special UserTrust assignments; drop thru */
+        case kSecTrustResultProceed:
+            /* cert chain valid AND user explicitly trusts this */
+            break;
+        default:
+            /*
+             * Cert chain construction failed.
+             * Just go with the single subject cert we were given; maybe the
+             * peer can complete the chain.
+             */
+            ortn = noErr;
+            goto errOut;
+    }
+
+    /* get resulting constructed cert chain */
+    ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
+    if(ortn) {
+        cssmPerror("SecTrustEvaluate", ortn);
+        goto errOut;
+    }
+
+    /*
+     * Copy certs from constructed chain to our result array, skipping
+     * the leaf (which is already there, as a SecIdentityRef) and possibly
+     * a root.
+     */
+    numResCerts = CFArrayGetCount(certChain);
+    if(numResCerts < 1) {
+        /*
+         * Can't happen: If chain doesn't verify to a root, we'd
+         * have bailed after SecTrustEvaluate().
+         */
+        ortn = noErr;
+        goto errOut;
+    }
+    if(!includeRoot) {
+        /* skip the last (root) cert) */
+        numResCerts--;
+    }
+    for(dex=1; dex<numResCerts; dex++) {
+        certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);
+        CFArrayAppendValue(certArray, certRef);
+    }
+errOut:
+        /* clean up */
+        if(secTrust) {
+            CFRelease(secTrust);
+        }
+    if(subjCerts) {
+        CFRelease(subjCerts);
+    }
+    if(policy) {
+        CFRelease(policy);
+    }
+    if(policySearch) {
+        CFRelease(policySearch);
+    }
+    *outArray = certArray;
+    return ortn;
+}
+
+static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)
+{
+    // Search the user keychain list for all identities. Identities are a certificate/private key association that
+    // can be chosen for a purpose such as signing or an SSL connection.
+    SecIdentitySearchRef identitySearch = NULL;
+    // Pass 0 if you want all identities returned by this search
+    OSStatus err = SecIdentitySearchCreate(NULL, 0, &identitySearch);
+    SecIdentityRef theIdentity = NULL;
+    OSErr searchResult = noErr;
+
+    do {
+        searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);
+
+        if (searchResult == noErr) {
+            // Get the cert from the identity, then generate a chain.
+            SecCertificateRef certificate;
+            SecIdentityCopyCertificate(theIdentity, &certificate);
+            CFArrayRef certChain = NULL;
+
+            // *** Should do something with this error...
+            err = completeCertChain(theIdentity, NULL, TRUE, &certChain);
+
+            CFIndex i, certCount = CFArrayGetCount(certChain);
+
+            // Make a java array of certificate data from the chain.
+            jclass byteArrayClass = (*env)->FindClass(env, "[B");
+            if (byteArrayClass == NULL) {
+                goto errOut;
+            }
+            jobjectArray javaCertArray = (*env)->NewObjectArray(env, certCount, byteArrayClass, NULL);
+            // Cleanup first then check for a NULL return code
+            (*env)->DeleteLocalRef(env, byteArrayClass);
+            if (javaCertArray == NULL) {
+                goto errOut;
+            }
+
+            // And, make an array of the certificate refs.
+            jlongArray certRefArray = (*env)->NewLongArray(env, certCount);
+            if (certRefArray == NULL) {
+                goto errOut;
+            }
+
+            SecCertificateRef currCertRef = NULL;
+
+            for (i = 0; i < certCount; i++) {
+                CSSM_DATA currCertData;
+
+                if (i == 0)
+                    currCertRef = certificate;
+                else
+                    currCertRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);
+
+                bzero(&currCertData, sizeof(CSSM_DATA));
+                err = SecCertificateGetData(currCertRef, &currCertData);
+                jbyteArray encodedCertData = (*env)->NewByteArray(env, currCertData.Length);
+                if (encodedCertData == NULL) {
+                    goto errOut;
+                }
+                (*env)->SetByteArrayRegion(env, encodedCertData, 0, currCertData.Length, (jbyte *)currCertData.Data);
+                (*env)->SetObjectArrayElement(env, javaCertArray, i, encodedCertData);
+                jlong certRefElement = ptr_to_jlong(currCertRef);
+                (*env)->SetLongArrayRegion(env, certRefArray, i, 1, &certRefElement);
+            }
+
+            // Get the private key.  When needed we'll export the data from it later.
+            SecKeyRef privateKeyRef;
+            err = SecIdentityCopyPrivateKey(theIdentity, &privateKeyRef);
+
+            // Find the label.  It's a 'blob', but we interpret as characters.
+            jstring alias = getLabelFromItem(env, (SecKeychainItemRef)certificate);
+            if (alias == NULL) {
+                goto errOut;
+            }
+
+            // Find the creation date.
+            jlong creationDate = getModDateFromItem(env, (SecKeychainItemRef)certificate);
+
+            // Call back to the Java object to create Java objects corresponding to this security object.
+            jlong nativeKeyRef = ptr_to_jlong(privateKeyRef);
+            JNFCallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
+        }
+    } while (searchResult == noErr);
+
+errOut:
+    if (identitySearch != NULL) {
+        CFRelease(identitySearch);
+    }
+}
+
+static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
+{
+    // Search the user keychain list for all X509 certificates.
+    SecKeychainSearchRef keychainItemSearch = NULL;
+    OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);
+    SecKeychainItemRef theItem = NULL;
+    OSErr searchResult = noErr;
+
+    do {
+        searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
+
+        if (searchResult == noErr) {
+            // Make a byte array with the DER-encoded contents of the certificate.
+            SecCertificateRef certRef = (SecCertificateRef)theItem;
+            CSSM_DATA currCertificate;
+            err = SecCertificateGetData(certRef, &currCertificate);
+            jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);
+            if (certData == NULL) {
+                goto errOut;
+            }
+            (*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
+
+            // Find the label.  It's a 'blob', but we interpret as characters.
+            jstring alias = getLabelFromItem(env, theItem);
+            if (alias == NULL) {
+                goto errOut;
+            }
+
+            // Find the creation date.
+            jlong creationDate = getModDateFromItem(env, theItem);
+
+            // Call back to the Java object to create Java objects corresponding to this security object.
+            jlong nativeRef = ptr_to_jlong(certRef);
+            JNFCallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
+        }
+    } while (searchResult == noErr);
+
+errOut:
+    if (keychainItemSearch != NULL) {
+        CFRelease(keychainItemSearch);
+    }
+}
+
+/*
+ * Class:     apple_security_KeychainStore
+ * Method:    _getEncodedKeyData
+ * Signature: (J)[B
+     */
+JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyData
+(JNIEnv *env, jobject this, jlong keyRefLong, jcharArray passwordObj)
+{
+    SecKeyRef keyRef = (SecKeyRef)jlong_to_ptr(keyRefLong);
+    SecKeyImportExportParameters paramBlock;
+    OSStatus err = noErr;
+    CFDataRef exportedData = NULL;
+    jbyteArray returnValue = NULL;
+    CFStringRef passwordStrRef = NULL;
+
+    jsize passwordLen = 0;
+    jchar *passwordChars = NULL;
+
+    if (passwordObj) {
+        passwordLen = (*env)->GetArrayLength(env, passwordObj);
+
+        if (passwordLen > 0) {
+            passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
+            if (passwordChars == NULL) {
+                goto errOut;
+            }
+            passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
+        }
+    }
+
+    paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+    // Note that setting the flags field **requires** you to pass in a password of some kind.  The keychain will not prompt you.
+    paramBlock.flags = 0;
+    paramBlock.passphrase = passwordStrRef;
+    paramBlock.alertTitle = NULL;
+    paramBlock.alertPrompt = NULL;
+    paramBlock.accessRef = NULL;
+    paramBlock.keyUsage = CSSM_KEYUSE_ANY;
+    paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
+
+    err = SecKeychainItemExport(keyRef, kSecFormatPKCS12, 0, &paramBlock, &exportedData);
+
+    if (err == noErr) {
+        CFIndex size = CFDataGetLength(exportedData);
+        returnValue = (*env)->NewByteArray(env, size);
+        if (returnValue == NULL) {
+            goto errOut;
+        }
+        (*env)->SetByteArrayRegion(env, returnValue, 0, size, (jbyte *)CFDataGetBytePtr(exportedData));
+    }
+
+errOut:
+    if (exportedData) CFRelease(exportedData);
+    if (passwordStrRef) CFRelease(passwordStrRef);
+
+    return returnValue;
+}
+
+
+/*
+ * Class:     apple_security_KeychainStore
+ * Method:    _scanKeychain
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain
+(JNIEnv *env, jobject this)
+{
+    // Look for 'identities' -- private key and certificate chain pairs -- and add those.
+    // Search for these first, because a certificate that's found here as part of an identity will show up
+    // again later as a certificate.
+    addIdentitiesToKeystore(env, this);
+
+    // Scan current keychain for trusted certificates.
+    addCertificatesToKeystore(env, this);
+
+}
+
+/*
+ * Class:     apple_security_KeychainStore
+ * Method:    _addItemToKeychain
+ * Signature: (Ljava/lang/String;[B)I
+*/
+JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain
+(JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)
+{
+    OSStatus err;
+    jlong returnValue = 0;
+
+JNF_COCOA_ENTER(env);
+
+    jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);
+    jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);
+    if (rawData == NULL) {
+        goto errOut;
+    }
+
+    CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);
+    CFArrayRef createdItems = NULL;
+
+    SecKeychainRef defaultKeychain = NULL;
+    SecKeychainCopyDefault(&defaultKeychain);
+
+    SecExternalItemType dataType = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
+
+    // Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
+    SecKeyImportExportParameters paramBlock;
+    CFStringRef passwordStrRef = NULL;
+
+    jsize passwordLen = 0;
+    jchar *passwordChars = NULL;
+
+    if (passwordObj) {
+        passwordLen = (*env)->GetArrayLength(env, passwordObj);
+        passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
+        passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
+    }
+
+    paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+    // Note that setting the flags field **requires** you to pass in a password of some kind.  The keychain will not prompt you.
+    paramBlock.flags = 0;
+    paramBlock.passphrase = passwordStrRef;
+    paramBlock.alertTitle = NULL;
+    paramBlock.alertPrompt = NULL;
+    paramBlock.accessRef = NULL;
+    paramBlock.keyUsage = CSSM_KEYUSE_ANY;
+    paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
+
+    err = SecKeychainItemImport(cfDataToImport, NULL, &dataType, NULL,
+                                0, &paramBlock, defaultKeychain, &createdItems);
+
+    if (err == noErr) {
+        SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);
+
+        // Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
+        if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {
+            setLabelForItem(JNFJavaToNSString(env, alias), anItem);
+        }
+
+        // Retain the item, since it will be released once when the array holding it gets released.
+        CFRetain(anItem);
+        returnValue = ptr_to_jlong(anItem);
+    } else {
+        cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);
+    }
+
+    (*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);
+
+    if (createdItems != NULL) {
+        CFRelease(createdItems);
+    }
+
+errOut: ;
+
+JNF_COCOA_EXIT(env);
+
+    return returnValue;
+}
+
+/*
+ * Class:     apple_security_KeychainStore
+ * Method:    _removeItemFromKeychain
+ * Signature: (J)I
+*/
+JNIEXPORT jint JNICALL Java_apple_security_KeychainStore__1removeItemFromKeychain
+(JNIEnv *env, jobject this, jlong keychainItem)
+{
+    SecKeychainItemRef itemToRemove = jlong_to_ptr(keychainItem);
+    return SecKeychainItemDelete(itemToRemove);
+}
+
+/*
+ * Class:     apple_security_KeychainStore
+ * Method:    _releaseKeychainItemRef
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1releaseKeychainItemRef
+(JNIEnv *env, jobject this, jlong keychainItem)
+{
+    SecKeychainItemRef itemToFree = jlong_to_ptr(keychainItem);
+    CFRelease(itemToFree);
+}
--- a/src/java.base/share/classes/sun/security/jca/ProviderConfig.java	Tue Aug 18 12:49:00 2015 -0700
+++ b/src/java.base/share/classes/sun/security/jca/ProviderConfig.java	Tue Aug 18 21:16:27 2015 +0000
@@ -178,6 +178,26 @@
             p = new com.sun.crypto.provider.SunJCE();
         } else if (provName.equals("SunJSSE") || provName.equals("com.sun.net.ssl.internal.ssl.Provider")) {
             p = new com.sun.net.ssl.internal.ssl.Provider();
+        } else if (provName.equals("Apple") || provName.equals("apple.security.AppleProvider")) {
+            // need to use reflection since this class only exists on MacOsx
+            p = AccessController.doPrivileged(new PrivilegedAction<Provider>() {
+                public Provider run() {
+                    try {
+                        Class<?> c = Class.forName("apple.security.AppleProvider");
+                        if (Provider.class.isAssignableFrom(c)) {
+                            return (Provider) c.newInstance();
+                        } else {
+                            return null;
+                        }
+                    } catch (Exception ex) {
+                        if (debug != null) {
+                        debug.println("Error loading provider Apple");
+                        ex.printStackTrace();
+                    }
+                    return null;
+                }
+             }
+             });
         } else {
             if (isLoading) {
                 // because this method is synchronized, this can only
--- a/src/jdk.deploy.osx/macosx/classes/apple/security/AppleProvider.java	Tue Aug 18 12:49:00 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2011, 2015, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-package apple.security;
-
-import java.security.*;
-
-/**
- * The Apple Security Provider.
- */
-
-/**
- * Defines the Apple provider.
- *
- * This provider only exists to provide access to the Apple keychain-based KeyStore implementation
- */
-@SuppressWarnings("serial") // JDK implementation class
-public final class AppleProvider extends Provider {
-
-    private static final String info = "Apple Provider";
-
-    private static final class ProviderService extends Provider.Service {
-        ProviderService(Provider p, String type, String algo, String cn) {
-            super(p, type, algo, cn, null, null);
-        }
-
-        @Override
-        public Object newInstance(Object ctrParamObj)
-            throws NoSuchAlgorithmException {
-            String type = getType();
-            if (ctrParamObj != null) {
-                throw new InvalidParameterException
-                    ("constructorParameter not used with " + type + " engines");
-            }
-
-            String algo = getAlgorithm();
-            try {
-                if (type.equals("KeyStore")) {
-                    if (algo.equals("KeychainStore")) {
-                        return new KeychainStore();
-                    }
-                }
-            } catch (Exception ex) {
-                throw new NoSuchAlgorithmException("Error constructing " +
-                    type + " for " + algo + " using Apple", ex);
-            }
-            throw new ProviderException("No impl for " + algo +
-                " " + type);
-        }
-    }
-
-
-    public AppleProvider() {
-        /* We are the Apple provider */
-        super("Apple", 1.9d, info);
-
-        final Provider p = this;
-        AccessController.doPrivileged(new PrivilegedAction<Void>() {
-            public Void run() {
-                putService(new ProviderService(p, "KeyStore",
-                           "KeychainStore", "apple.security.KeychainStore"));
-                return null;
-            }
-        });
-    }
-}
--- a/src/jdk.deploy.osx/macosx/classes/apple/security/KeychainStore.java	Tue Aug 18 12:49:00 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1149 +0,0 @@
-/*
- * Copyright (c) 2011, 2015, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-package apple.security;
-
-import java.io.*;
-import java.security.*;
-import java.security.cert.*;
-import java.security.cert.Certificate;
-import java.security.spec.*;
-import java.util.*;
-
-import javax.crypto.*;
-import javax.crypto.spec.*;
-import javax.security.auth.x500.*;
-
-import sun.security.pkcs.*;
-import sun.security.pkcs.EncryptedPrivateKeyInfo;
-import sun.security.util.*;
-import sun.security.x509.*;
-
-/**
- * This class provides the keystore implementation referred to as "KeychainStore".
- * It uses the current user's keychain as its backing storage, and does NOT support
- * a file-based implementation.
- */
-
-public final class KeychainStore extends KeyStoreSpi {
-
-    // Private keys and their supporting certificate chains
-    // If a key came from the keychain it has a SecKeyRef and one or more
-    // SecCertificateRef.  When we delete the key we have to delete all of the corresponding
-    // native objects.
-    class KeyEntry {
-        Date date; // the creation date of this entry
-        byte[] protectedPrivKey;
-        char[] password;
-        long keyRef;  // SecKeyRef for this key
-        Certificate chain[];
-        long chainRefs[];  // SecCertificateRefs for this key's chain.
-    };
-
-    // Trusted certificates
-    class TrustedCertEntry {
-        Date date; // the creation date of this entry
-
-        Certificate cert;
-        long certRef;  // SecCertificateRef for this key
-    };
-
-    /**
-     * Entries that have been deleted.  When something calls engineStore we'll
-     * remove them from the keychain.
-     */
-    private Hashtable<String, Object> deletedEntries = new Hashtable<>();
-
-    /**
-     * Entries that have been added.  When something calls engineStore we'll
-     * add them to the keychain.
-     */
-    private Hashtable<String, Object> addedEntries = new Hashtable<>();
-
-    /**
-     * Private keys and certificates are stored in a hashtable.
-     * Hash entries are keyed by alias names.
-     */
-    private Hashtable<String, Object> entries = new Hashtable<>();
-
-    /**
-     * Algorithm identifiers and corresponding OIDs for the contents of the PKCS12 bag we get from the Keychain.
-     */
-    private static final int keyBag[]  = {1, 2, 840, 113549, 1, 12, 10, 1, 2};
-    private static final int pbeWithSHAAnd3KeyTripleDESCBC[] =     {1, 2, 840, 113549, 1, 12, 1, 3};
-    private static ObjectIdentifier PKCS8ShroudedKeyBag_OID;
-    private static ObjectIdentifier pbeWithSHAAnd3KeyTripleDESCBC_OID;
-
-    /**
-     * Constnats used in PBE decryption.
-     */
-    private static final int iterationCount = 1024;
-    private static final int SALT_LEN = 20;
-
-    static {
-        AccessController.doPrivileged(
-            new PrivilegedAction<Void>() {
-                public Void run() {
-                    System.loadLibrary("osx");
-                    return null;
-                }
-            });
-        try {
-            PKCS8ShroudedKeyBag_OID = new ObjectIdentifier(keyBag);
-            pbeWithSHAAnd3KeyTripleDESCBC_OID = new ObjectIdentifier(pbeWithSHAAnd3KeyTripleDESCBC);
-        } catch (IOException ioe) {
-            // should not happen
-        }
-    }
-
-    private static void permissionCheck() {
-        SecurityManager sec = System.getSecurityManager();
-
-        if (sec != null) {
-            sec.checkPermission(new RuntimePermission("useKeychainStore"));
-        }
-    }
-
-
-    /**
-     * Verify the Apple provider in the constructor.
-     *
-     * @exception SecurityException if fails to verify
-     * its own integrity
-     */
-    public KeychainStore() { }
-
-    /**
-        * Returns the key associated with the given alias, using the given
-     * password to recover it.
-     *
-     * @param alias the alias name
-     * @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>.
-     *
-     * @exception NoSuchAlgorithmException if the algorithm for recovering the
-     * key cannot be found
-     * @exception UnrecoverableKeyException if the key cannot be recovered
-     * (e.g., the given password is wrong).
-     */
-    public Key engineGetKey(String alias, char[] password)
-        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 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)) {
-            return null;
-        }
-
-        // This call gives us a PKCS12 bag, with the key inside it.
-        byte[] exportedKeyInfo = _getEncodedKeyData(((KeyEntry)entry).keyRef, password);
-        if (exportedKeyInfo == null) {
-            return null;
-        }
-
-        PrivateKey returnValue = null;
-
-        try {
-            byte[] pkcs8KeyData = fetchPrivateKeyFromBag(exportedKeyInfo);
-            byte[] encryptedKey;
-            AlgorithmParameters algParams;
-            ObjectIdentifier algOid;
-            try {
-                // get the encrypted private key
-                EncryptedPrivateKeyInfo encrInfo = new EncryptedPrivateKeyInfo(pkcs8KeyData);
-                encryptedKey = encrInfo.getEncryptedData();
-
-                // parse Algorithm parameters
-                DerValue val = new DerValue(encrInfo.getAlgorithm().encode());
-                DerInputStream in = val.toDerInputStream();
-                algOid = in.getOID();
-                algParams = parseAlgParameters(in);
-
-            } catch (IOException ioe) {
-                UnrecoverableKeyException uke =
-                new UnrecoverableKeyException("Private key not stored as "
-                                              + "PKCS#8 EncryptedPrivateKeyInfo: " + ioe);
-                uke.initCause(ioe);
-                throw uke;
-            }
-
-            // Use JCE to decrypt the data using the supplied password.
-            SecretKey skey = getPBEKey(password);
-            Cipher cipher = Cipher.getInstance(algOid.toString());
-            cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
-            byte[] decryptedPrivateKey = cipher.doFinal(encryptedKey);
-            PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(decryptedPrivateKey);
-
-             // Parse the key algorithm and then use a JCA key factory to create the private key.
-            DerValue val = new DerValue(decryptedPrivateKey);
-            DerInputStream in = val.toDerInputStream();
-
-            // Ignore this -- version should be 0.
-            int i = in.getInteger();
-
-            // Get the Algorithm ID next
-            DerValue[] value = in.getSequence(2);
-            AlgorithmId algId = new AlgorithmId(value[0].getOID());
-            String algName = algId.getName();
-
-            // Get a key factory for this algorithm.  It's likely to be 'RSA'.
-            KeyFactory kfac = KeyFactory.getInstance(algName);
-            returnValue = kfac.generatePrivate(kspec);
-        } catch (Exception e) {
-            UnrecoverableKeyException uke =
-            new UnrecoverableKeyException("Get Key failed: " +
-                                          e.getMessage());
-            uke.initCause(e);
-            throw uke;
-        }
-
-        return returnValue;
-    }
-
-    private native byte[] _getEncodedKeyData(long secKeyRef, char[] password);
-
-    /**
-     * Returns the certificate chain associated with the given alias.
-     *
-     * @param alias the alias name
-     *
-     * @return the certificate chain (ordered with the user's certificate first
-                                      * and the root certificate authority last), or null if the given alias
-     * does not exist or does not contain a certificate chain (i.e., the given
-                                                               * alias identifies either a <i>trusted certificate entry</i> or a
-                                                               * <i>key entry</i> without a certificate chain).
-     */
-    public Certificate[] engineGetCertificateChain(String alias) {
-        permissionCheck();
-
-        Object entry = entries.get(alias.toLowerCase());
-
-        if (entry != null && entry instanceof KeyEntry) {
-            if (((KeyEntry)entry).chain == null) {
-                return null;
-            } else {
-                return ((KeyEntry)entry).chain.clone();
-            }
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Returns the certificate associated with the given alias.
-     *
-     * <p>If the given alias name identifies a
-     * <i>trusted certificate entry</i>, the certificate associated with that
-     * entry is returned. If the given alias name identifies a
-     * <i>key entry</i>, the first element of the certificate chain of that
-     * entry is returned, or null if that entry does not have a certificate
-     * chain.
-     *
-     * @param alias the alias name
-     *
-     * @return the certificate, or null if the given alias does not exist or
-     * does not contain a certificate.
-     */
-    public Certificate engineGetCertificate(String alias) {
-        permissionCheck();
-
-        Object entry = entries.get(alias.toLowerCase());
-
-        if (entry != null) {
-            if (entry instanceof TrustedCertEntry) {
-                return ((TrustedCertEntry)entry).cert;
-            } else {
-                KeyEntry ke = (KeyEntry)entry;
-                if (ke.chain == null || ke.chain.length == 0) {
-                    return null;
-                }
-                return ke.chain[0];
-            }
-        } else {
-            return null;
-        }
-    }
-
-    /**
-        * Returns the creation date of the entry identified by the given alias.
-     *
-     * @param alias the alias name
-     *
-     * @return the creation date of this entry, or null if the given alias does
-     * not exist
-     */
-    public Date engineGetCreationDate(String alias) {
-        permissionCheck();
-
-        Object entry = entries.get(alias.toLowerCase());
-
-        if (entry != null) {
-            if (entry instanceof TrustedCertEntry) {
-                return new Date(((TrustedCertEntry)entry).date.getTime());
-            } else {
-                return new Date(((KeyEntry)entry).date.getTime());
-            }
-        } else {
-            return null;
-        }
-    }
-
-    /**
-        * Assigns the given key to the given alias, protecting it with the given
-     * password.
-     *
-     * <p>If the given key is of type <code>java.security.PrivateKey</code>,
-     * it must be accompanied by a certificate chain certifying the
-     * corresponding public key.
-     *
-     * <p>If the given alias already exists, the keystore information
-     * associated with it is overridden by the given key (and possibly
-                                                          * certificate chain).
-     *
-     * @param alias the alias name
-     * @param key the key to be associated with the alias
-     * @param password the password to protect the key
-     * @param chain the certificate chain for the corresponding public
-     * key (only required if the given key is of type
-            * <code>java.security.PrivateKey</code>).
-     *
-     * @exception KeyStoreException if the given key cannot be protected, or
-     * this operation fails for some other reason
-     */
-    public void engineSetKeyEntry(String alias, Key key, char[] password,
-                                  Certificate[] chain)
-        throws KeyStoreException
-    {
-        permissionCheck();
-
-        synchronized(entries) {
-            try {
-                KeyEntry entry = new KeyEntry();
-                entry.date = new Date();
-
-                if (key instanceof PrivateKey) {
-                    if ((key.getFormat().equals("PKCS#8")) ||
-                        (key.getFormat().equals("PKCS8"))) {
-                        entry.protectedPrivKey = encryptPrivateKey(key.getEncoded(), password);
-                        entry.password = password.clone();
-                    } else {
-                        throw new KeyStoreException("Private key is not encoded as PKCS#8");
-                    }
-                } else {
-                    throw new KeyStoreException("Key is not a PrivateKey");
-                }
-
-                // clone the chain
-                if (chain != null) {
-                    if ((chain.length > 1) && !validateChain(chain)) {
-                        throw new KeyStoreException("Certificate chain does not validate");
-                    }
-
-                    entry.chain = chain.clone();
-                    entry.chainRefs = new long[entry.chain.length];
-                }
-
-                String lowerAlias = alias.toLowerCase();
-                if (entries.get(lowerAlias) != null) {
-                    deletedEntries.put(lowerAlias, entries.get(lowerAlias));
-                }
-
-                entries.put(lowerAlias, entry);
-                addedEntries.put(lowerAlias, entry);
-            } catch (Exception nsae) {
-                KeyStoreException ke = new KeyStoreException("Key protection algorithm not found: " + nsae);
-                ke.initCause(nsae);
-                throw ke;
-            }
-        }
-    }
-
-    /**
-        * Assigns the given key (that has already been protected) to the given
-     * alias.
-     *
-     * <p>If the protected key is of type
-     * <code>java.security.PrivateKey</code>, it must be accompanied by a
-     * certificate chain certifying the corresponding public key. If the
-     * underlying keystore implementation is of type <code>jks</code>,
-     * <code>key</code> must be encoded as an
-     * <code>EncryptedPrivateKeyInfo</code> as defined in the PKCS #8 standard.
-     *
-     * <p>If the given alias already exists, the keystore information
-     * associated with it is overridden by the given key (and possibly
-                                                          * certificate chain).
-     *
-     * @param alias the alias name
-     * @param key the key (in protected format) to be associated with the alias
-     * @param chain the certificate chain for the corresponding public
-     * key (only useful if the protected key is of type
-            * <code>java.security.PrivateKey</code>).
-     *
-     * @exception KeyStoreException if this operation fails.
-     */
-    public void engineSetKeyEntry(String alias, byte[] key,
-                                  Certificate[] chain)
-        throws KeyStoreException
-    {
-        permissionCheck();
-
-        synchronized(entries) {
-            // key must be encoded as EncryptedPrivateKeyInfo as defined in
-            // PKCS#8
-            KeyEntry entry = new KeyEntry();
-            try {
-                EncryptedPrivateKeyInfo privateKey = new EncryptedPrivateKeyInfo(key);
-                entry.protectedPrivKey = privateKey.getEncoded();
-            } catch (IOException ioe) {
-                throw new KeyStoreException("key is not encoded as "
-                                            + "EncryptedPrivateKeyInfo");
-            }
-
-            entry.date = new Date();
-
-            if ((chain != null) &&
-                (chain.length != 0)) {
-                entry.chain = chain.clone();
-                entry.chainRefs = new long[entry.chain.length];
-            }
-
-            String lowerAlias = alias.toLowerCase();
-            if (entries.get(lowerAlias) != null) {
-                deletedEntries.put(lowerAlias, entries.get(alias));
-            }
-            entries.put(lowerAlias, entry);
-            addedEntries.put(lowerAlias, entry);
-        }
-    }
-
-    /**
-        * Assigns the given certificate to the given alias.
-     *
-     * <p>If the given alias already exists in this keystore and identifies a
-     * <i>trusted certificate entry</i>, the certificate associated with it is
-     * overridden by the given certificate.
-     *
-     * @param alias the alias name
-     * @param cert the certificate
-     *
-     * @exception KeyStoreException if the given alias already exists and does
-     * not identify a <i>trusted certificate entry</i>, or this operation
-     * fails for some other reason.
-     */
-    public void engineSetCertificateEntry(String alias, Certificate cert)
-        throws KeyStoreException
-    {
-        permissionCheck();
-
-        synchronized(entries) {
-
-            Object entry = entries.get(alias.toLowerCase());
-            if ((entry != null) && (entry instanceof KeyEntry)) {
-                throw new KeyStoreException
-                ("Cannot overwrite key entry with certificate");
-            }
-
-            // This will be slow, but necessary.  Enumerate the values and then see if the cert matches the one in the trusted cert entry.
-            // Security framework doesn't support the same certificate twice in a keychain.
-            Collection<Object> allValues = entries.values();
-
-            for (Object value : allValues) {
-                if (value instanceof TrustedCertEntry) {
-                    TrustedCertEntry tce = (TrustedCertEntry)value;
-                    if (tce.cert.equals(cert)) {
-                        throw new KeyStoreException("Keychain does not support mulitple copies of same certificate.");
-                    }
-                }
-            }
-
-            TrustedCertEntry trustedCertEntry = new TrustedCertEntry();
-            trustedCertEntry.cert = cert;
-            trustedCertEntry.date = new Date();
-            String lowerAlias = alias.toLowerCase();
-            if (entries.get(lowerAlias) != null) {
-                deletedEntries.put(lowerAlias, entries.get(lowerAlias));
-            }
-            entries.put(lowerAlias, trustedCertEntry);
-            addedEntries.put(lowerAlias, trustedCertEntry);
-        }
-    }
-
-    /**
-        * Deletes the entry identified by the given alias from this keystore.
-     *
-     * @param alias the alias name
-     *
-     * @exception KeyStoreException if the entry cannot be removed.
-     */
-    public void engineDeleteEntry(String alias)
-        throws KeyStoreException
-    {
-        permissionCheck();
-
-        synchronized(entries) {
-            Object entry = entries.remove(alias.toLowerCase());
-            deletedEntries.put(alias.toLowerCase(), entry);
-        }
-    }
-
-    /**
-        * Lists all the alias names of this keystore.
-     *
-     * @return enumeration of the alias names
-     */
-    public Enumeration<String> engineAliases() {
-        permissionCheck();
-        return entries.keys();
-    }
-
-    /**
-        * Checks if the given alias exists in this keystore.
-     *
-     * @param alias the alias name
-     *
-     * @return true if the alias exists, false otherwise
-     */
-    public boolean engineContainsAlias(String alias) {
-        permissionCheck();
-        return entries.containsKey(alias.toLowerCase());
-    }
-
-    /**
-        * Retrieves the number of entries in this keystore.
-     *
-     * @return the number of entries in this keystore
-     */
-    public int engineSize() {
-        permissionCheck();
-        return entries.size();
-    }
-
-    /**
-        * Returns true if the entry identified by the given alias is a
-     * <i>key entry</i>, and false otherwise.
-     *
-     * @return true if the entry identified by the given alias is a
-     * <i>key entry</i>, false otherwise.
-     */
-    public boolean engineIsKeyEntry(String alias) {
-        permissionCheck();
-        Object entry = entries.get(alias.toLowerCase());
-        if ((entry != null) && (entry instanceof KeyEntry)) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-        * Returns true if the entry identified by the given alias is a
-     * <i>trusted certificate entry</i>, and false otherwise.
-     *
-     * @return true if the entry identified by the given alias is a
-     * <i>trusted certificate entry</i>, false otherwise.
-     */
-    public boolean engineIsCertificateEntry(String alias) {
-        permissionCheck();
-        Object entry = entries.get(alias.toLowerCase());
-        if ((entry != null) && (entry instanceof TrustedCertEntry)) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-        * Returns the (alias) name of the first keystore entry whose certificate
-     * matches the given certificate.
-     *
-     * <p>This method attempts to match the given certificate with each
-     * keystore entry. If the entry being considered
-     * is a <i>trusted certificate entry</i>, the given certificate is
-     * compared to that entry's certificate. If the entry being considered is
-     * a <i>key entry</i>, the given certificate is compared to the first
-     * element of that entry's certificate chain (if a chain exists).
-     *
-     * @param cert the certificate to match with.
-     *
-     * @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) {
-        permissionCheck();
-        Certificate certElem;
-
-        for (Enumeration<String> e = entries.keys(); e.hasMoreElements(); ) {
-            String alias = e.nextElement();
-            Object entry = entries.get(alias);
-            if (entry instanceof TrustedCertEntry) {
-                certElem = ((TrustedCertEntry)entry).cert;
-            } else {
-                KeyEntry ke = (KeyEntry)entry;
-                if (ke.chain == null || ke.chain.length == 0) {
-                    continue;
-                }
-                certElem = ke.chain[0];
-            }
-            if (certElem.equals(cert)) {
-                return alias;
-            }
-        }
-        return null;
-    }
-
-    /**
-        * Stores this keystore to the given output stream, and protects its
-     * integrity with the given password.
-     *
-     * @param stream Ignored. the output stream to which this keystore is written.
-     * @param password the password to generate the keystore integrity check
-     *
-     * @exception IOException if there was an I/O problem with data
-     * @exception NoSuchAlgorithmException if the appropriate data integrity
-     * algorithm could not be found
-     * @exception CertificateException if any of the certificates included in
-     * the keystore data could not be stored
-     */
-    public void engineStore(OutputStream stream, char[] password)
-        throws IOException, NoSuchAlgorithmException, CertificateException
-    {
-        permissionCheck();
-
-        // Delete items that do have a keychain item ref.
-        for (Enumeration<String> e = deletedEntries.keys(); e.hasMoreElements(); ) {
-            String alias = e.nextElement();
-            Object entry = deletedEntries.get(alias);
-            if (entry instanceof TrustedCertEntry) {
-                if (((TrustedCertEntry)entry).certRef != 0) {
-                    _removeItemFromKeychain(((TrustedCertEntry)entry).certRef);
-                    _releaseKeychainItemRef(((TrustedCertEntry)entry).certRef);
-                }
-            } else {
-                Certificate certElem;
-                KeyEntry keyEntry = (KeyEntry)entry;
-
-                if (keyEntry.chain != null) {
-                    for (int i = 0; i < keyEntry.chain.length; i++) {
-                        if (keyEntry.chainRefs[i] != 0) {
-                            _removeItemFromKeychain(keyEntry.chainRefs[i]);
-                            _releaseKeychainItemRef(keyEntry.chainRefs[i]);
-                        }
-                    }
-
-                    if (keyEntry.keyRef != 0) {
-                        _removeItemFromKeychain(keyEntry.keyRef);
-                        _releaseKeychainItemRef(keyEntry.keyRef);
-                    }
-                }
-            }
-        }
-
-        // Add all of the certs or keys in the added entries.
-        // No need to check for 0 refs, as they are in the added list.
-        for (Enumeration<String> e = addedEntries.keys(); e.hasMoreElements(); ) {
-            String alias = e.nextElement();
-            Object entry = addedEntries.get(alias);
-            if (entry instanceof TrustedCertEntry) {
-                TrustedCertEntry tce = (TrustedCertEntry)entry;
-                Certificate certElem;
-                certElem = tce.cert;
-                tce.certRef = addCertificateToKeychain(alias, certElem);
-            } else {
-                KeyEntry keyEntry = (KeyEntry)entry;
-
-                if (keyEntry.chain != null) {
-                    for (int i = 0; i < keyEntry.chain.length; i++) {
-                        keyEntry.chainRefs[i] = addCertificateToKeychain(alias, keyEntry.chain[i]);
-                    }
-
-                    keyEntry.keyRef = _addItemToKeychain(alias, false, keyEntry.protectedPrivKey, keyEntry.password);
-                }
-            }
-        }
-
-        // Clear the added and deletedEntries hashtables here, now that we're done with the updates.
-        // For the deleted entries, we freed up the native references above.
-        deletedEntries.clear();
-        addedEntries.clear();
-    }
-
-    private long addCertificateToKeychain(String alias, Certificate cert) {
-        byte[] certblob = null;
-        long returnValue = 0;
-
-        try {
-            certblob = cert.getEncoded();
-            returnValue = _addItemToKeychain(alias, true, certblob, null);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-
-        return returnValue;
-    }
-
-    private native long _addItemToKeychain(String alias, boolean isCertificate, byte[] datablob, char[] password);
-    private native int _removeItemFromKeychain(long certRef);
-    private native void _releaseKeychainItemRef(long keychainItemRef);
-
-    /**
-      * Loads the keystore from the Keychain.
-     *
-     * @param stream Ignored - here for API compatibility.
-     * @param password Ignored - if user needs to unlock keychain Security
-     * framework will post any dialogs.
-     *
-     * @exception IOException if there is an I/O or format problem with the
-     * keystore data
-     * @exception NoSuchAlgorithmException if the algorithm used to check
-     * the integrity of the keystore cannot be found
-     * @exception CertificateException if any of the certificates in the
-     * keystore could not be loaded
-     */
-    public void engineLoad(InputStream stream, char[] password)
-        throws IOException, NoSuchAlgorithmException, CertificateException
-    {
-        permissionCheck();
-
-        // Release any stray keychain references before clearing out the entries.
-        synchronized(entries) {
-            for (Enumeration<String> e = entries.keys(); e.hasMoreElements(); ) {
-                String alias = e.nextElement();
-                Object entry = entries.get(alias);
-                if (entry instanceof TrustedCertEntry) {
-                    if (((TrustedCertEntry)entry).certRef != 0) {
-                        _releaseKeychainItemRef(((TrustedCertEntry)entry).certRef);
-                    }
-                } else {
-                    KeyEntry keyEntry = (KeyEntry)entry;
-
-                    if (keyEntry.chain != null) {
-                        for (int i = 0; i < keyEntry.chain.length; i++) {
-                            if (keyEntry.chainRefs[i] != 0) {
-                                _releaseKeychainItemRef(keyEntry.chainRefs[i]);
-                            }
-                        }
-
-                        if (keyEntry.keyRef != 0) {
-                            _releaseKeychainItemRef(keyEntry.keyRef);
-                        }
-                    }
-                }
-            }
-
-            entries.clear();
-            _scanKeychain();
-        }
-    }
-
-    private native void _scanKeychain();
-
-    /**
-     * Callback method from _scanKeychain.  If a trusted certificate is found, this method will be called.
-     */
-    private void createTrustedCertEntry(String alias, long keychainItemRef, long creationDate, byte[] derStream) {
-        TrustedCertEntry tce = new TrustedCertEntry();
-
-        try {
-            CertificateFactory cf = CertificateFactory.getInstance("X.509");
-            InputStream input = new ByteArrayInputStream(derStream);
-            X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
-            input.close();
-            tce.cert = cert;
-            tce.certRef = keychainItemRef;
-
-            // Make a creation date.
-            if (creationDate != 0)
-                tce.date = new Date(creationDate);
-            else
-                tce.date = new Date();
-
-            int uniqueVal = 1;
-            String originalAlias = alias;
-
-            while (entries.containsKey(alias.toLowerCase())) {
-                alias = originalAlias + " " + uniqueVal;
-                uniqueVal++;
-            }
-
-            entries.put(alias.toLowerCase(), tce);
-        } catch (Exception e) {
-            // The certificate will be skipped.
-            System.err.println("KeychainStore Ignored Exception: " + e);
-        }
-    }
-
-    /**
-     * Callback method from _scanKeychain.  If an identity is found, this method will be called to create Java certificate
-     * and private key objects from the keychain data.
-     */
-    private void createKeyEntry(String alias, long creationDate, long secKeyRef, long[] secCertificateRefs, byte[][] rawCertData)
-        throws IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
-        KeyEntry ke = new KeyEntry();
-
-        // First, store off the private key information.  This is the easy part.
-        ke.protectedPrivKey = null;
-        ke.keyRef = secKeyRef;
-
-        // Make a creation date.
-        if (creationDate != 0)
-            ke.date = new Date(creationDate);
-        else
-            ke.date = new Date();
-
-        // Next, create X.509 Certificate objects from the raw data.  This is complicated
-        // because a certificate's public key may be too long for Java's default encryption strength.
-        List<CertKeychainItemPair> createdCerts = new ArrayList<>();
-
-        try {
-            CertificateFactory cf = CertificateFactory.getInstance("X.509");
-
-            for (int i = 0; i < rawCertData.length; i++) {
-                try {
-                    InputStream input = new ByteArrayInputStream(rawCertData[i]);
-                    X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
-                    input.close();
-
-                    // We successfully created the certificate, so track it and its corresponding SecCertificateRef.
-                    createdCerts.add(new CertKeychainItemPair(secCertificateRefs[i], cert));
-                } catch (CertificateException e) {
-                    // The certificate will be skipped.
-                    System.err.println("KeychainStore Ignored Exception: " + e);
-                }
-            }
-        } catch (CertificateException e) {
-            e.printStackTrace();
-        } catch (IOException ioe) {
-            ioe.printStackTrace();  // How would this happen?
-        }
-
-        // We have our certificates in the List, so now extract them into an array of
-        // Certificates and SecCertificateRefs.
-        CertKeychainItemPair[] objArray = createdCerts.toArray(new CertKeychainItemPair[0]);
-        Certificate[] certArray = new Certificate[objArray.length];
-        long[] certRefArray = new long[objArray.length];
-
-        for (int i = 0; i < objArray.length; i++) {
-            CertKeychainItemPair addedItem = objArray[i];
-            certArray[i] = addedItem.mCert;
-            certRefArray[i] = addedItem.mCertificateRef;
-        }
-
-        ke.chain = certArray;
-        ke.chainRefs = certRefArray;
-
-        // If we don't have already have an item with this item's alias
-        // create a new one for it.
-        int uniqueVal = 1;
-        String originalAlias = alias;
-
-        while (entries.containsKey(alias.toLowerCase())) {
-            alias = originalAlias + " " + uniqueVal;
-            uniqueVal++;
-        }
-
-        entries.put(alias.toLowerCase(), ke);
-    }
-
-    private class CertKeychainItemPair {
-        long mCertificateRef;
-        Certificate mCert;
-
-        CertKeychainItemPair(long inCertRef, Certificate cert) {
-            mCertificateRef = inCertRef;
-            mCert = cert;
-        }
-    }
-
-    /*
-     * Validate Certificate Chain
-     */
-    private boolean validateChain(Certificate[] certChain)
-    {
-        for (int i = 0; i < certChain.length-1; i++) {
-            X500Principal issuerDN =
-            ((X509Certificate)certChain[i]).getIssuerX500Principal();
-            X500Principal subjectDN =
-                ((X509Certificate)certChain[i+1]).getSubjectX500Principal();
-            if (!(issuerDN.equals(subjectDN)))
-                return false;
-        }
-        return true;
-    }
-
-    @SuppressWarnings("deprecation")
-    private byte[] fetchPrivateKeyFromBag(byte[] privateKeyInfo) throws IOException, NoSuchAlgorithmException, CertificateException
-    {
-        byte[] returnValue = null;
-        DerValue val = new DerValue(new ByteArrayInputStream(privateKeyInfo));
-        DerInputStream s = val.toDerInputStream();
-        int version = s.getInteger();
-
-        if (version != 3) {
-            throw new IOException("PKCS12 keystore not in version 3 format");
-        }
-
-        /*
-            * Read the authSafe.
-         */
-        byte[] authSafeData;
-        ContentInfo authSafe = new ContentInfo(s);
-        ObjectIdentifier contentType = authSafe.getContentType();
-
-        if (contentType.equals(ContentInfo.DATA_OID)) {
-            authSafeData = authSafe.getData();
-        } else /* signed data */ {
-            throw new IOException("public key protected PKCS12 not supported");
-        }
-
-        DerInputStream as = new DerInputStream(authSafeData);
-        DerValue[] safeContentsArray = as.getSequence(2);
-        int count = safeContentsArray.length;
-
-        /*
-         * Spin over the ContentInfos.
-         */
-        for (int i = 0; i < count; i++) {
-            byte[] safeContentsData;
-            ContentInfo safeContents;
-            DerInputStream sci;
-            byte[] eAlgId = null;
-
-            sci = new DerInputStream(safeContentsArray[i].toByteArray());
-            safeContents = new ContentInfo(sci);
-            contentType = safeContents.getContentType();
-            safeContentsData = null;
-
-            if (contentType.equals(ContentInfo.DATA_OID)) {
-                safeContentsData = safeContents.getData();
-            } else if (contentType.equals(ContentInfo.ENCRYPTED_DATA_OID)) {
-                // The password was used to export the private key from the keychain.
-                // The Keychain won't export the key with encrypted data, so we don't need
-                // to worry about it.
-                continue;
-            } else {
-                throw new IOException("public key protected PKCS12" +
-                                      " not supported");
-            }
-            DerInputStream sc = new DerInputStream(safeContentsData);
-            returnValue = extractKeyData(sc);
-        }
-
-        return returnValue;
-    }
-
-    @SuppressWarnings("deprecation")
-    private byte[] extractKeyData(DerInputStream stream)
-        throws IOException, NoSuchAlgorithmException, CertificateException
-    {
-        byte[] returnValue = null;
-        DerValue[] safeBags = stream.getSequence(2);
-        int count = safeBags.length;
-
-        /*
-         * Spin over the SafeBags.
-         */
-        for (int i = 0; i < count; i++) {
-            ObjectIdentifier bagId;
-            DerInputStream sbi;
-            DerValue bagValue;
-            Object bagItem = null;
-
-            sbi = safeBags[i].toDerInputStream();
-            bagId = sbi.getOID();
-            bagValue = sbi.getDerValue();
-            if (!bagValue.isContextSpecific((byte)0)) {
-                throw new IOException("unsupported PKCS12 bag value type "
-                                      + bagValue.tag);
-            }
-            bagValue = bagValue.data.getDerValue();
-            if (bagId.equals(PKCS8ShroudedKeyBag_OID)) {
-                // got what we were looking for.  Return it.
-                returnValue = bagValue.toByteArray();
-            } else {
-                // log error message for "unsupported PKCS12 bag type"
-                System.out.println("Unsupported bag type '" + bagId + "'");
-            }
-        }
-
-        return returnValue;
-    }
-
-    /*
-        * Generate PBE Algorithm Parameters
-     */
-    private AlgorithmParameters getAlgorithmParameters(String algorithm)
-        throws IOException
-    {
-        AlgorithmParameters algParams = null;
-
-        // create PBE parameters from salt and iteration count
-        PBEParameterSpec paramSpec =
-            new PBEParameterSpec(getSalt(), iterationCount);
-        try {
-            algParams = AlgorithmParameters.getInstance(algorithm);
-            algParams.init(paramSpec);
-        } catch (Exception e) {
-            IOException ioe =
-            new IOException("getAlgorithmParameters failed: " +
-                            e.getMessage());
-            ioe.initCause(e);
-            throw ioe;
-        }
-        return algParams;
-    }
-
-    // the source of randomness
-    private SecureRandom random;
-
-    /*
-     * Generate random salt
-     */
-    private byte[] getSalt()
-    {
-        // Generate a random salt.
-        byte[] salt = new byte[SALT_LEN];
-        if (random == null) {
-            random = new SecureRandom();
-        }
-        salt = random.generateSeed(SALT_LEN);
-        return salt;
-    }
-
-    /*
-     * parse Algorithm Parameters
-     */
-    private AlgorithmParameters parseAlgParameters(DerInputStream in)
-        throws IOException
-    {
-        AlgorithmParameters algParams = null;
-        try {
-            DerValue params;
-            if (in.available() == 0) {
-                params = null;
-            } else {
-                params = in.getDerValue();
-                if (params.tag == DerValue.tag_Null) {
-                    params = null;
-                }
-            }
-            if (params != null) {
-                algParams = AlgorithmParameters.getInstance("PBE");
-                algParams.init(params.toByteArray());
-            }
-        } catch (Exception e) {
-            IOException ioe =
-            new IOException("parseAlgParameters failed: " +
-                            e.getMessage());
-            ioe.initCause(e);
-            throw ioe;
-        }
-        return algParams;
-    }
-
-    /*
-     * Generate PBE key
-     */
-    private SecretKey getPBEKey(char[] password) throws IOException
-    {
-        SecretKey skey = null;
-
-        try {
-            PBEKeySpec keySpec = new PBEKeySpec(password);
-            SecretKeyFactory skFac = SecretKeyFactory.getInstance("PBE");
-            skey = skFac.generateSecret(keySpec);
-        } catch (Exception e) {
-            IOException ioe = new IOException("getSecretKey failed: " +
-                                              e.getMessage());
-            ioe.initCause(e);
-            throw ioe;
-        }
-        return skey;
-    }
-
-    /*
-     * Encrypt private key using Password-based encryption (PBE)
-     * as defined in PKCS#5.
-     *
-     * NOTE: Currently pbeWithSHAAnd3-KeyTripleDES-CBC algorithmID is
-     *       used to derive the key and IV.
-     *
-     * @return encrypted private key encoded as EncryptedPrivateKeyInfo
-     */
-    private byte[] encryptPrivateKey(byte[] data, char[] password)
-        throws IOException, NoSuchAlgorithmException, UnrecoverableKeyException
-    {
-        byte[] key = null;
-
-        try {
-            // create AlgorithmParameters
-            AlgorithmParameters algParams =
-            getAlgorithmParameters("PBEWithSHA1AndDESede");
-
-            // Use JCE
-            SecretKey skey = getPBEKey(password);
-            Cipher cipher = Cipher.getInstance("PBEWithSHA1AndDESede");
-            cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
-            byte[] encryptedKey = cipher.doFinal(data);
-
-            // wrap encrypted private key in EncryptedPrivateKeyInfo
-            // as defined in PKCS#8
-            AlgorithmId algid =
-                new AlgorithmId(pbeWithSHAAnd3KeyTripleDESCBC_OID, algParams);
-            EncryptedPrivateKeyInfo encrInfo =
-                new EncryptedPrivateKeyInfo(algid, encryptedKey);
-            key = encrInfo.getEncoded();
-        } catch (Exception e) {
-            UnrecoverableKeyException uke =
-            new UnrecoverableKeyException("Encrypt Private Key failed: "
-                                          + e.getMessage());
-            uke.initCause(e);
-            throw uke;
-        }
-
-        return key;
-    }
-
-
-}
-
--- a/src/jdk.deploy.osx/macosx/native/libosx/KeystoreImpl.m	Tue Aug 18 12:49:00 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,589 +0,0 @@
-/*
- * Copyright (c) 2011, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 "apple_security_KeychainStore.h"
-
-#import <Security/Security.h>
-#import <Security/SecImportExport.h>
-#import <CoreServices/CoreServices.h>  // (for require() macros)
-#import <JavaNativeFoundation/JavaNativeFoundation.h>
-
-
-static JNF_CLASS_CACHE(jc_KeychainStore, "apple/security/KeychainStore");
-static JNF_MEMBER_CACHE(jm_createTrustedCertEntry, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;JJ[B)V");
-static JNF_MEMBER_CACHE(jm_createKeyEntry, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
-
-static jstring getLabelFromItem(JNIEnv *env, SecKeychainItemRef inItem)
-{
-    OSStatus status;
-    jstring returnValue = NULL;
-    char *attribCString = NULL;
-
-    SecKeychainAttribute itemAttrs[] = { { kSecLabelItemAttr, 0, NULL } };
-    SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
-
-    status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
-
-    if(status) {
-        cssmPerror("getLabelFromItem: SecKeychainItemCopyContent", status);
-        goto errOut;
-    }
-
-    attribCString = malloc(itemAttrs[0].length + 1);
-    strncpy(attribCString, itemAttrs[0].data, itemAttrs[0].length);
-    attribCString[itemAttrs[0].length] = '\0';
-    returnValue = (*env)->NewStringUTF(env, attribCString);
-
-errOut:
-    SecKeychainItemFreeContent(&attrList, NULL);
-    if (attribCString) free(attribCString);
-    return returnValue;
-}
-
-static jlong getModDateFromItem(JNIEnv *env, SecKeychainItemRef inItem)
-{
-    OSStatus status;
-    SecKeychainAttribute itemAttrs[] = { { kSecModDateItemAttr, 0, NULL } };
-    SecKeychainAttributeList attrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
-    jlong returnValue = 0;
-
-    status = SecKeychainItemCopyContent(inItem, NULL, &attrList, NULL, NULL);
-
-    if(status) {
-        // This is almost always missing, so don't dump an error.
-        // cssmPerror("getModDateFromItem: SecKeychainItemCopyContent", status);
-        goto errOut;
-    }
-
-    memcpy(&returnValue, itemAttrs[0].data, itemAttrs[0].length);
-
-errOut:
-    SecKeychainItemFreeContent(&attrList, NULL);
-    return returnValue;
-}
-
-static void setLabelForItem(NSString *inLabel, SecKeychainItemRef inItem)
-{
-    OSStatus status;
-    const char *labelCString = [inLabel UTF8String];
-
-    // Set up attribute vector (each attribute consists of {tag, length, pointer}):
-    SecKeychainAttribute attrs[] = {
-        { kSecLabelItemAttr, strlen(labelCString), (void *)labelCString }
-    };
-
-    const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
-
-    // Not changing data here, just attributes.
-    status = SecKeychainItemModifyContent(inItem, &attributes, 0, NULL);
-
-    if(status) {
-        cssmPerror("setLabelForItem: SecKeychainItemModifyContent", status);
-    }
-}
-
-/*
- * Given a SecIdentityRef, do our best to construct a complete, ordered, and
- * verified cert chain, returning the result in a CFArrayRef. The result is
- * can be passed back to Java as a chain for a private key.
- */
-static OSStatus completeCertChain(
-                                     SecIdentityRef         identity,
-                                     SecCertificateRef    trustedAnchor,    // optional additional trusted anchor
-                                     bool                 includeRoot,     // include the root in outArray
-                                     CFArrayRef            *outArray)        // created and RETURNED
-{
-    SecTrustRef                    secTrust = NULL;
-    SecPolicyRef                policy = NULL;
-    SecPolicySearchRef            policySearch = NULL;
-    SecTrustResultType            secTrustResult;
-    CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv;            // not used
-    CFArrayRef                    certChain = NULL;   // constructed chain, CERTS ONLY
-    CFMutableArrayRef             subjCerts;            // passed to SecTrust
-    CFMutableArrayRef             certArray;            // returned array starting with
-                                                    //   identity
-    CFIndex                     numResCerts;
-    CFIndex                     dex;
-    OSStatus                     ortn;
-      SecCertificateRef             certRef;
-
-    /* First element in out array is the SecIdentity */
-    certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-    CFArrayAppendValue(certArray, identity);
-
-    /* the single element in certs-to-be-evaluated comes from the identity */
-       ortn = SecIdentityCopyCertificate(identity, &certRef);
-    if(ortn) {
-        /* should never happen */
-        cssmPerror("SecIdentityCopyCertificate", ortn);
-        return ortn;
-    }
-
-    /*
-     * Now use SecTrust to get a complete cert chain, using all of the
-     * user's keychains to look for intermediate certs.
-     * NOTE this does NOT handle root certs which are not in the system
-     * root cert DB.
-     */
-    subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
-    CFArraySetValueAtIndex(subjCerts, 0, certRef);
-
-    /* the array owns the subject cert ref now */
-    CFRelease(certRef);
-
-    /* Get a SecPolicyRef for generic X509 cert chain verification */
-    ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
-                                 &CSSMOID_APPLE_X509_BASIC,
-                                 NULL,                // value
-                                 &policySearch);
-    if(ortn) {
-        /* should never happen */
-        cssmPerror("SecPolicySearchCreate", ortn);
-        goto errOut;
-    }
-    ortn = SecPolicySearchCopyNext(policySearch, &policy);
-    if(ortn) {
-        /* should never happen */
-        cssmPerror("SecPolicySearchCopyNext", ortn);
-        goto errOut;
-    }
-
-    /* build a SecTrustRef for specified policy and certs */
-    ortn = SecTrustCreateWithCertificates(subjCerts,
-                                          policy, &secTrust);
-    if(ortn) {
-        cssmPerror("SecTrustCreateWithCertificates", ortn);
-        goto errOut;
-    }
-
-    if(trustedAnchor) {
-        /*
-        * Tell SecTrust to trust this one in addition to the current
-         * trusted system-wide anchors.
-         */
-        CFMutableArrayRef newAnchors;
-        CFArrayRef currAnchors;
-
-        ortn = SecTrustCopyAnchorCertificates(&currAnchors);
-        if(ortn) {
-            /* should never happen */
-            cssmPerror("SecTrustCopyAnchorCertificates", ortn);
-            goto errOut;
-        }
-        newAnchors = CFArrayCreateMutableCopy(NULL,
-                                              CFArrayGetCount(currAnchors) + 1,
-                                              currAnchors);
-        CFRelease(currAnchors);
-        CFArrayAppendValue(newAnchors, trustedAnchor);
-        ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);
-        CFRelease(newAnchors);
-        if(ortn) {
-            cssmPerror("SecTrustSetAnchorCertificates", ortn);
-            goto errOut;
-        }
-    }
-
-    /* evaluate: GO */
-    ortn = SecTrustEvaluate(secTrust, &secTrustResult);
-    if(ortn) {
-        cssmPerror("SecTrustEvaluate", ortn);
-        goto errOut;
-    }
-    switch(secTrustResult) {
-        case kSecTrustResultUnspecified:
-            /* cert chain valid, no special UserTrust assignments; drop thru */
-        case kSecTrustResultProceed:
-            /* cert chain valid AND user explicitly trusts this */
-            break;
-        default:
-            /*
-             * Cert chain construction failed.
-             * Just go with the single subject cert we were given; maybe the
-             * peer can complete the chain.
-             */
-            ortn = noErr;
-            goto errOut;
-    }
-
-    /* get resulting constructed cert chain */
-    ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
-    if(ortn) {
-        cssmPerror("SecTrustEvaluate", ortn);
-        goto errOut;
-    }
-
-    /*
-     * Copy certs from constructed chain to our result array, skipping
-     * the leaf (which is already there, as a SecIdentityRef) and possibly
-     * a root.
-     */
-    numResCerts = CFArrayGetCount(certChain);
-    if(numResCerts < 1) {
-        /*
-         * Can't happen: If chain doesn't verify to a root, we'd
-         * have bailed after SecTrustEvaluate().
-         */
-        ortn = noErr;
-        goto errOut;
-    }
-    if(!includeRoot) {
-        /* skip the last (root) cert) */
-        numResCerts--;
-    }
-    for(dex=1; dex<numResCerts; dex++) {
-        certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);
-        CFArrayAppendValue(certArray, certRef);
-    }
-errOut:
-        /* clean up */
-        if(secTrust) {
-            CFRelease(secTrust);
-        }
-    if(subjCerts) {
-        CFRelease(subjCerts);
-    }
-    if(policy) {
-        CFRelease(policy);
-    }
-    if(policySearch) {
-        CFRelease(policySearch);
-    }
-    *outArray = certArray;
-    return ortn;
-}
-
-static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)
-{
-    // Search the user keychain list for all identities. Identities are a certificate/private key association that
-    // can be chosen for a purpose such as signing or an SSL connection.
-    SecIdentitySearchRef identitySearch = NULL;
-    // Pass 0 if you want all identities returned by this search
-    OSStatus err = SecIdentitySearchCreate(NULL, 0, &identitySearch);
-    SecIdentityRef theIdentity = NULL;
-    OSErr searchResult = noErr;
-
-    do {
-        searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);
-
-        if (searchResult == noErr) {
-            // Get the cert from the identity, then generate a chain.
-            SecCertificateRef certificate;
-            SecIdentityCopyCertificate(theIdentity, &certificate);
-            CFArrayRef certChain = NULL;
-
-            // *** Should do something with this error...
-            err = completeCertChain(theIdentity, NULL, TRUE, &certChain);
-
-            CFIndex i, certCount = CFArrayGetCount(certChain);
-
-            // Make a java array of certificate data from the chain.
-            jclass byteArrayClass = (*env)->FindClass(env, "[B");
-            if (byteArrayClass == NULL) {
-                goto errOut;
-            }
-            jobjectArray javaCertArray = (*env)->NewObjectArray(env, certCount, byteArrayClass, NULL);
-            // Cleanup first then check for a NULL return code
-            (*env)->DeleteLocalRef(env, byteArrayClass);
-            if (javaCertArray == NULL) {
-                goto errOut;
-            }
-
-            // And, make an array of the certificate refs.
-            jlongArray certRefArray = (*env)->NewLongArray(env, certCount);
-            if (certRefArray == NULL) {
-                goto errOut;
-            }
-
-            SecCertificateRef currCertRef = NULL;
-
-            for (i = 0; i < certCount; i++) {
-                CSSM_DATA currCertData;
-
-                if (i == 0)
-                    currCertRef = certificate;
-                else
-                    currCertRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);
-
-                bzero(&currCertData, sizeof(CSSM_DATA));
-                err = SecCertificateGetData(currCertRef, &currCertData);
-                jbyteArray encodedCertData = (*env)->NewByteArray(env, currCertData.Length);
-                if (encodedCertData == NULL) {
-                    goto errOut;
-                }
-                (*env)->SetByteArrayRegion(env, encodedCertData, 0, currCertData.Length, (jbyte *)currCertData.Data);
-                (*env)->SetObjectArrayElement(env, javaCertArray, i, encodedCertData);
-                jlong certRefElement = ptr_to_jlong(currCertRef);
-                (*env)->SetLongArrayRegion(env, certRefArray, i, 1, &certRefElement);
-            }
-
-            // Get the private key.  When needed we'll export the data from it later.
-            SecKeyRef privateKeyRef;
-            err = SecIdentityCopyPrivateKey(theIdentity, &privateKeyRef);
-
-            // Find the label.  It's a 'blob', but we interpret as characters.
-            jstring alias = getLabelFromItem(env, (SecKeychainItemRef)certificate);
-            if (alias == NULL) {
-                goto errOut;
-            }
-
-            // Find the creation date.
-            jlong creationDate = getModDateFromItem(env, (SecKeychainItemRef)certificate);
-
-            // Call back to the Java object to create Java objects corresponding to this security object.
-            jlong nativeKeyRef = ptr_to_jlong(privateKeyRef);
-            JNFCallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
-        }
-    } while (searchResult == noErr);
-
-errOut:
-    if (identitySearch != NULL) {
-        CFRelease(identitySearch);
-    }
-}
-
-static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
-{
-    // Search the user keychain list for all X509 certificates.
-    SecKeychainSearchRef keychainItemSearch = NULL;
-    OSStatus err = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, NULL, &keychainItemSearch);
-    SecKeychainItemRef theItem = NULL;
-    OSErr searchResult = noErr;
-
-    do {
-        searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
-
-        if (searchResult == noErr) {
-            // Make a byte array with the DER-encoded contents of the certificate.
-            SecCertificateRef certRef = (SecCertificateRef)theItem;
-            CSSM_DATA currCertificate;
-            err = SecCertificateGetData(certRef, &currCertificate);
-            jbyteArray certData = (*env)->NewByteArray(env, currCertificate.Length);
-            if (certData == NULL) {
-                goto errOut;
-            }
-            (*env)->SetByteArrayRegion(env, certData, 0, currCertificate.Length, (jbyte *)currCertificate.Data);
-
-            // Find the label.  It's a 'blob', but we interpret as characters.
-            jstring alias = getLabelFromItem(env, theItem);
-            if (alias == NULL) {
-                goto errOut;
-            }
-
-            // Find the creation date.
-            jlong creationDate = getModDateFromItem(env, theItem);
-
-            // Call back to the Java object to create Java objects corresponding to this security object.
-            jlong nativeRef = ptr_to_jlong(certRef);
-            JNFCallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
-        }
-    } while (searchResult == noErr);
-
-errOut:
-    if (keychainItemSearch != NULL) {
-        CFRelease(keychainItemSearch);
-    }
-}
-
-/*
- * Class:     apple_security_KeychainStore
- * Method:    _getEncodedKeyData
- * Signature: (J)[B
-     */
-JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyData
-(JNIEnv *env, jobject this, jlong keyRefLong, jcharArray passwordObj)
-{
-    SecKeyRef keyRef = (SecKeyRef)jlong_to_ptr(keyRefLong);
-    SecKeyImportExportParameters paramBlock;
-    OSStatus err = noErr;
-    CFDataRef exportedData = NULL;
-    jbyteArray returnValue = NULL;
-    CFStringRef passwordStrRef = NULL;
-
-    jsize passwordLen = 0;
-    jchar *passwordChars = NULL;
-
-    if (passwordObj) {
-        passwordLen = (*env)->GetArrayLength(env, passwordObj);
-
-        if (passwordLen > 0) {
-            passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
-            if (passwordChars == NULL) {
-                goto errOut;
-            }
-            passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
-        }
-    }
-
-    paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
-    // Note that setting the flags field **requires** you to pass in a password of some kind.  The keychain will not prompt you.
-    paramBlock.flags = 0;
-    paramBlock.passphrase = passwordStrRef;
-    paramBlock.alertTitle = NULL;
-    paramBlock.alertPrompt = NULL;
-    paramBlock.accessRef = NULL;
-    paramBlock.keyUsage = CSSM_KEYUSE_ANY;
-    paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
-
-    err = SecKeychainItemExport(keyRef, kSecFormatPKCS12, 0, &paramBlock, &exportedData);
-
-    if (err == noErr) {
-        CFIndex size = CFDataGetLength(exportedData);
-        returnValue = (*env)->NewByteArray(env, size);
-        if (returnValue == NULL) {
-            goto errOut;
-        }
-        (*env)->SetByteArrayRegion(env, returnValue, 0, size, (jbyte *)CFDataGetBytePtr(exportedData));
-    }
-
-errOut:
-    if (exportedData) CFRelease(exportedData);
-    if (passwordStrRef) CFRelease(passwordStrRef);
-
-    return returnValue;
-}
-
-
-/*
- * Class:     apple_security_KeychainStore
- * Method:    _scanKeychain
- * Signature: ()V
- */
-JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain
-(JNIEnv *env, jobject this)
-{
-    // Look for 'identities' -- private key and certificate chain pairs -- and add those.
-    // Search for these first, because a certificate that's found here as part of an identity will show up
-    // again later as a certificate.
-    addIdentitiesToKeystore(env, this);
-
-    // Scan current keychain for trusted certificates.
-    addCertificatesToKeystore(env, this);
-
-}
-
-/*
- * Class:     apple_security_KeychainStore
- * Method:    _addItemToKeychain
- * Signature: (Ljava/lang/String;[B)I
-*/
-JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain
-(JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)
-{
-    OSStatus err;
-    jlong returnValue = 0;
-
-JNF_COCOA_ENTER(env);
-
-    jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);
-    jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);
-    if (rawData == NULL) {
-        goto errOut;
-    }
-
-    CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);
-    CFArrayRef createdItems = NULL;
-
-    SecKeychainRef defaultKeychain = NULL;
-    SecKeychainCopyDefault(&defaultKeychain);
-
-    SecExternalItemType dataType = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
-
-    // Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
-    SecKeyImportExportParameters paramBlock;
-    CFStringRef passwordStrRef = NULL;
-
-    jsize passwordLen = 0;
-    jchar *passwordChars = NULL;
-
-    if (passwordObj) {
-        passwordLen = (*env)->GetArrayLength(env, passwordObj);
-        passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
-        passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen);
-    }
-
-    paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
-    // Note that setting the flags field **requires** you to pass in a password of some kind.  The keychain will not prompt you.
-    paramBlock.flags = 0;
-    paramBlock.passphrase = passwordStrRef;
-    paramBlock.alertTitle = NULL;
-    paramBlock.alertPrompt = NULL;
-    paramBlock.accessRef = NULL;
-    paramBlock.keyUsage = CSSM_KEYUSE_ANY;
-    paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
-
-    err = SecKeychainItemImport(cfDataToImport, NULL, &dataType, NULL,
-                                0, &paramBlock, defaultKeychain, &createdItems);
-
-    if (err == noErr) {
-        SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);
-
-        // Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
-        if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {
-            setLabelForItem(JNFJavaToNSString(env, alias), anItem);
-        }
-
-        // Retain the item, since it will be released once when the array holding it gets released.
-        CFRetain(anItem);
-        returnValue = ptr_to_jlong(anItem);
-    } else {
-        cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);
-    }
-
-    (*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);
-
-    if (createdItems != NULL) {
-        CFRelease(createdItems);
-    }
-
-errOut: ;
-
-JNF_COCOA_EXIT(env);
-
-    return returnValue;
-}
-
-/*
- * Class:     apple_security_KeychainStore
- * Method:    _removeItemFromKeychain
- * Signature: (J)I
-*/
-JNIEXPORT jint JNICALL Java_apple_security_KeychainStore__1removeItemFromKeychain
-(JNIEnv *env, jobject this, jlong keychainItem)
-{
-    SecKeychainItemRef itemToRemove = jlong_to_ptr(keychainItem);
-    return SecKeychainItemDelete(itemToRemove);
-}
-
-/*
- * Class:     apple_security_KeychainStore
- * Method:    _releaseKeychainItemRef
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1releaseKeychainItemRef
-(JNIEnv *env, jobject this, jlong keychainItem)
-{
-    SecKeychainItemRef itemToFree = jlong_to_ptr(keychainItem);
-    CFRelease(itemToFree);
-}