| /* |
| * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * 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 sun.security.mscapi; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.security.AccessController; |
| import java.security.InvalidKeyException; |
| import java.security.KeyStoreSpi; |
| import java.security.KeyStoreException; |
| import java.security.UnrecoverableKeyException; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.SecurityPermission; |
| import java.security.cert.X509Certificate; |
| import java.security.cert.Certificate; |
| import java.security.cert.CertificateException; |
| import java.security.cert.CertificateFactory; |
| import java.security.interfaces.RSAPrivateCrtKey; |
| import java.util.*; |
| |
| import sun.security.action.GetPropertyAction; |
| |
| /** |
| * Implementation of key store for Windows using the Microsoft Crypto API. |
| * |
| * @since 1.6 |
| */ |
| abstract class KeyStore extends KeyStoreSpi { |
| |
| public static final class MY extends KeyStore { |
| public MY() { |
| super("MY"); |
| } |
| } |
| |
| public static final class ROOT extends KeyStore { |
| public ROOT() { |
| super("ROOT"); |
| } |
| } |
| |
| class KeyEntry |
| { |
| private Key privateKey; |
| private X509Certificate certChain[]; |
| private String alias; |
| |
| KeyEntry(Key key, X509Certificate[] chain) { |
| this(null, key, chain); |
| } |
| |
| KeyEntry(String alias, Key key, X509Certificate[] chain) { |
| this.privateKey = key; |
| this.certChain = chain; |
| /* |
| * The default alias for both entry types is derived from a |
| * hash value intrinsic to the first certificate in the chain. |
| */ |
| if (alias == null) { |
| this.alias = Integer.toString(chain[0].hashCode()); |
| } else { |
| this.alias = alias; |
| } |
| } |
| |
| /** |
| * Gets the alias for the keystore entry. |
| */ |
| String getAlias() |
| { |
| return alias; |
| } |
| |
| /** |
| * Sets the alias for the keystore entry. |
| */ |
| void setAlias(String alias) |
| { |
| // TODO - set friendly name prop in cert store |
| this.alias = alias; |
| } |
| |
| /** |
| * Gets the private key for the keystore entry. |
| */ |
| Key getPrivateKey() |
| { |
| return privateKey; |
| } |
| |
| /** |
| * Sets the private key for the keystore entry. |
| */ |
| void setPrivateKey(RSAPrivateCrtKey key) |
| throws InvalidKeyException, KeyStoreException |
| { |
| byte[] modulusBytes = key.getModulus().toByteArray(); |
| |
| // Adjust key length due to sign bit |
| int keyBitLength = (modulusBytes[0] == 0) |
| ? (modulusBytes.length - 1) * 8 |
| : modulusBytes.length * 8; |
| |
| byte[] keyBlob = generatePrivateKeyBlob( |
| keyBitLength, |
| modulusBytes, |
| key.getPublicExponent().toByteArray(), |
| key.getPrivateExponent().toByteArray(), |
| key.getPrimeP().toByteArray(), |
| key.getPrimeQ().toByteArray(), |
| key.getPrimeExponentP().toByteArray(), |
| key.getPrimeExponentQ().toByteArray(), |
| key.getCrtCoefficient().toByteArray()); |
| |
| privateKey = storePrivateKey(Objects.requireNonNull(keyBlob), |
| "{" + UUID.randomUUID().toString() + "}", keyBitLength); |
| } |
| |
| /** |
| * Gets the certificate chain for the keystore entry. |
| */ |
| X509Certificate[] getCertificateChain() |
| { |
| return certChain; |
| } |
| |
| /** |
| * Sets the certificate chain for the keystore entry. |
| */ |
| void setCertificateChain(X509Certificate[] chain) |
| throws CertificateException, KeyStoreException |
| { |
| for (int i = 0; i < chain.length; i++) { |
| byte[] encoding = chain[i].getEncoded(); |
| if (i == 0 && privateKey != null) { |
| storeCertificate(getName(), alias, encoding, |
| encoding.length, privateKey.getHCryptProvider(), |
| privateKey.getHCryptKey()); |
| |
| } else { |
| storeCertificate(getName(), alias, encoding, |
| encoding.length, 0L, 0L); // no private key to attach |
| } |
| } |
| certChain = chain; |
| } |
| }; |
| |
| /* |
| * An X.509 certificate factory. |
| * Used to create an X.509 certificate from its DER-encoding. |
| */ |
| private CertificateFactory certificateFactory = null; |
| |
| /* |
| * Compatibility mode: for applications that assume keystores are |
| * stream-based this mode tolerates (but ignores) a non-null stream |
| * or password parameter when passed to the load or store methods. |
| * The mode is enabled by default. |
| */ |
| private static final String KEYSTORE_COMPATIBILITY_MODE_PROP = |
| "sun.security.mscapi.keyStoreCompatibilityMode"; |
| private final boolean keyStoreCompatibilityMode; |
| |
| /* |
| * The keystore entries. |
| * Keys in the map are unique aliases (thus can differ from |
| * KeyEntry.getAlias()) |
| */ |
| private Map<String,KeyEntry> entries = new HashMap<>(); |
| |
| /* |
| * The keystore name. |
| * Case is not significant. |
| */ |
| private final String storeName; |
| |
| KeyStore(String storeName) { |
| // Get the compatibility mode |
| String prop = |
| AccessController.doPrivileged( |
| new GetPropertyAction(KEYSTORE_COMPATIBILITY_MODE_PROP)); |
| |
| if ("false".equalsIgnoreCase(prop)) { |
| keyStoreCompatibilityMode = false; |
| } else { |
| keyStoreCompatibilityMode = true; |
| } |
| |
| this.storeName = storeName; |
| } |
| |
| /** |
| * Returns the key associated with the given alias. |
| * <p> |
| * A compatibility mode is supported for applications that assume |
| * a password must be supplied. It permits (but ignores) a non-null |
| * <code>password</code>. The mode is enabled by default. |
| * Set the |
| * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> |
| * system property to <code>false</code> to disable compatibility mode |
| * and reject a non-null <code>password</code>. |
| * |
| * @param alias the alias name |
| * @param password the password, which should be <code>null</code> |
| * |
| * @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, |
| * or if compatibility mode is disabled and <code>password</code> is |
| * non-null. |
| * @exception UnrecoverableKeyException if the key cannot be recovered. |
| */ |
| public java.security.Key engineGetKey(String alias, char[] password) |
| throws NoSuchAlgorithmException, UnrecoverableKeyException |
| { |
| if (alias == null) { |
| return null; |
| } |
| |
| if (password != null && !keyStoreCompatibilityMode) { |
| throw new UnrecoverableKeyException("Password must be null"); |
| } |
| |
| if (engineIsKeyEntry(alias) == false) |
| return null; |
| |
| KeyEntry entry = entries.get(alias); |
| return (entry == null) |
| ? null |
| : entry.getPrivateKey(); |
| } |
| |
| /** |
| * 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) |
| { |
| if (alias == null) { |
| return null; |
| } |
| |
| KeyEntry entry = entries.get(alias); |
| X509Certificate[] certChain = (entry == null) |
| ? null |
| : entry.getCertificateChain(); |
| return (certChain == null) |
| ? null |
| : certChain.clone(); |
| } |
| |
| /** |
| * 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) |
| { |
| if (alias == null) { |
| return null; |
| } |
| |
| KeyEntry entry = entries.get(alias); |
| X509Certificate[] certChain = (entry == null) |
| ? null |
| : entry.getCertificateChain(); |
| return (certChain == null || certChain.length == 0) |
| ? null |
| : certChain[0]; |
| } |
| |
| /** |
| * 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) { |
| if (alias == null) { |
| return null; |
| } |
| return new Date(); |
| } |
| |
| /** |
| * Stores the given private key and associated certificate chain in the |
| * keystore. |
| * |
| * <p>The given java.security.PrivateKey <code>key</code> 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 certificate |
| * chain. Otherwise, a new entry is created. |
| * |
| * <p> |
| * A compatibility mode is supported for applications that assume |
| * a password must be supplied. It permits (but ignores) a non-null |
| * <code>password</code>. The mode is enabled by default. |
| * Set the |
| * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> |
| * system property to <code>false</code> to disable compatibility mode |
| * and reject a non-null <code>password</code>. |
| * |
| * @param alias the alias name |
| * @param key the private key to be associated with the alias |
| * @param password the password, which should be <code>null</code> |
| * @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 is not a private key, |
| * cannot be protected, or if compatibility mode is disabled and |
| * <code>password</code> is non-null, or if this operation fails for |
| * some other reason. |
| */ |
| public void engineSetKeyEntry(String alias, java.security.Key key, |
| char[] password, Certificate[] chain) throws KeyStoreException |
| { |
| if (alias == null) { |
| throw new KeyStoreException("alias must not be null"); |
| } |
| |
| if (password != null && !keyStoreCompatibilityMode) { |
| throw new KeyStoreException("Password must be null"); |
| } |
| |
| if (key instanceof RSAPrivateCrtKey) { |
| |
| KeyEntry entry = entries.get(alias); |
| |
| X509Certificate[] xchain; |
| if (chain != null) { |
| if (chain instanceof X509Certificate[]) { |
| xchain = (X509Certificate[]) chain; |
| } else { |
| xchain = new X509Certificate[chain.length]; |
| System.arraycopy(chain, 0, xchain, 0, chain.length); |
| } |
| } else { |
| xchain = null; |
| } |
| |
| if (entry == null) { |
| entry = |
| //TODO new KeyEntry(alias, key, (X509Certificate[]) chain); |
| new KeyEntry(alias, null, xchain); |
| storeWithUniqueAlias(alias, entry); |
| } |
| |
| entry.setAlias(alias); |
| |
| try { |
| entry.setPrivateKey((RSAPrivateCrtKey) key); |
| entry.setCertificateChain(xchain); |
| |
| } catch (CertificateException ce) { |
| throw new KeyStoreException(ce); |
| |
| } catch (InvalidKeyException ike) { |
| throw new KeyStoreException(ike); |
| } |
| |
| } else { |
| throw new UnsupportedOperationException( |
| "Cannot assign the key to the given alias."); |
| } |
| } |
| |
| /** |
| * 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 |
| { |
| throw new UnsupportedOperationException( |
| "Cannot assign the encoded key to the given alias."); |
| } |
| |
| /** |
| * 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 |
| { |
| if (alias == null) { |
| throw new KeyStoreException("alias must not be null"); |
| } |
| |
| if (cert instanceof X509Certificate) { |
| |
| // TODO - build CryptoAPI chain? |
| X509Certificate[] chain = |
| new X509Certificate[]{ (X509Certificate) cert }; |
| KeyEntry entry = entries.get(alias); |
| |
| if (entry == null) { |
| entry = |
| new KeyEntry(alias, null, chain); |
| storeWithUniqueAlias(alias, entry); |
| } |
| |
| if (entry.getPrivateKey() == null) { // trusted-cert entry |
| entry.setAlias(alias); |
| |
| try { |
| entry.setCertificateChain(chain); |
| |
| } catch (CertificateException ce) { |
| throw new KeyStoreException(ce); |
| } |
| } |
| |
| } else { |
| throw new UnsupportedOperationException( |
| "Cannot assign the certificate to the given alias."); |
| } |
| } |
| |
| /** |
| * 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 |
| { |
| if (alias == null) { |
| throw new KeyStoreException("alias must not be null"); |
| } |
| |
| KeyEntry entry = entries.remove(alias); |
| if (entry != null) { |
| // Get end-entity certificate and remove from system cert store |
| X509Certificate[] certChain = entry.getCertificateChain(); |
| if (certChain != null) { |
| |
| try { |
| |
| byte[] encoding = certChain[0].getEncoded(); |
| removeCertificate(getName(), entry.getAlias(), encoding, |
| encoding.length); |
| |
| } catch (CertificateException e) { |
| throw new KeyStoreException("Cannot remove entry: ", e); |
| } |
| } |
| Key privateKey = entry.getPrivateKey(); |
| if (privateKey != null) { |
| destroyKeyContainer( |
| Key.getContainerName(privateKey.getHCryptProvider())); |
| } |
| } |
| } |
| |
| /** |
| * Lists all the alias names of this keystore. |
| * |
| * @return enumeration of the alias names |
| */ |
| public Enumeration<String> engineAliases() { |
| final Iterator<String> iter = entries.keySet().iterator(); |
| |
| return new Enumeration<String>() |
| { |
| public boolean hasMoreElements() |
| { |
| return iter.hasNext(); |
| } |
| |
| public String nextElement() |
| { |
| return iter.next(); |
| } |
| }; |
| } |
| |
| /** |
| * 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) { |
| return entries.containsKey(alias); |
| } |
| |
| /** |
| * Retrieves the number of entries in this keystore. |
| * |
| * @return the number of entries in this keystore |
| */ |
| public int engineSize() { |
| 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) { |
| |
| if (alias == null) { |
| return false; |
| } |
| |
| KeyEntry entry = entries.get(alias); |
| return entry != null && entry.getPrivateKey() != null; |
| } |
| |
| /** |
| * 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) { |
| |
| if (alias == null) { |
| return false; |
| } |
| |
| KeyEntry entry = entries.get(alias); |
| return entry != null && entry.getPrivateKey() == null; |
| } |
| |
| /** |
| * 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) { |
| |
| for (Map.Entry<String,KeyEntry> mapEntry : entries.entrySet()) { |
| KeyEntry entry = mapEntry.getValue(); |
| if (entry.certChain != null && entry.certChain[0].equals(cert)) { |
| return entry.getAlias(); |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * engineStore is currently a no-op. |
| * Entries are stored during engineSetEntry. |
| * |
| * A compatibility mode is supported for applications that assume |
| * keystores are stream-based. It permits (but ignores) a non-null |
| * <code>stream</code> or <code>password</code>. |
| * The mode is enabled by default. |
| * Set the |
| * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> |
| * system property to <code>false</code> to disable compatibility mode |
| * and reject a non-null <code>stream</code> or <code>password</code>. |
| * |
| * @param stream the output stream, which should be <code>null</code> |
| * @param password the password, which should be <code>null</code> |
| * |
| * @exception IOException if compatibility mode is disabled and either |
| * parameter is non-null. |
| */ |
| public void engineStore(OutputStream stream, char[] password) |
| throws IOException, NoSuchAlgorithmException, CertificateException |
| { |
| if (stream != null && !keyStoreCompatibilityMode) { |
| throw new IOException("Keystore output stream must be null"); |
| } |
| |
| if (password != null && !keyStoreCompatibilityMode) { |
| throw new IOException("Keystore password must be null"); |
| } |
| } |
| |
| /** |
| * Loads the keystore. |
| * |
| * A compatibility mode is supported for applications that assume |
| * keystores are stream-based. It permits (but ignores) a non-null |
| * <code>stream</code> or <code>password</code>. |
| * The mode is enabled by default. |
| * Set the |
| * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> |
| * system property to <code>false</code> to disable compatibility mode |
| * and reject a non-null <code>stream</code> or <code>password</code>. |
| * |
| * @param stream the input stream, which should be <code>null</code>. |
| * @param password the password, which should be <code>null</code>. |
| * |
| * @exception IOException if there is an I/O or format problem with the |
| * keystore data. Or if compatibility mode is disabled and either |
| * parameter is non-null. |
| * @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 |
| * @exception SecurityException if the security check for |
| * <code>SecurityPermission("authProvider.<i>name</i>")</code> does not |
| * pass, where <i>name</i> is the value returned by |
| * this provider's <code>getName</code> method. |
| */ |
| public void engineLoad(InputStream stream, char[] password) |
| throws IOException, NoSuchAlgorithmException, CertificateException |
| { |
| if (stream != null && !keyStoreCompatibilityMode) { |
| throw new IOException("Keystore input stream must be null"); |
| } |
| |
| if (password != null && !keyStoreCompatibilityMode) { |
| throw new IOException("Keystore password must be null"); |
| } |
| |
| /* |
| * Use the same security check as AuthProvider.login |
| */ |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) { |
| sm.checkPermission(new SecurityPermission( |
| "authProvider.SunMSCAPI")); |
| } |
| |
| // Clear all key entries |
| entries.clear(); |
| |
| try { |
| |
| // Load keys and/or certificate chains |
| loadKeysOrCertificateChains(getName()); |
| |
| } catch (KeyStoreException e) { |
| throw new IOException(e); |
| } |
| } |
| |
| /** |
| * Stores the given entry into the map, making sure |
| * the alias, used as the key is unique. |
| * If the same alias already exists, it tries to append |
| * a suffix (1), (2), etc to it until it finds a unique |
| * value. |
| */ |
| private void storeWithUniqueAlias(String alias, KeyEntry entry) { |
| String uniqAlias = alias; |
| int uniqNum = 1; |
| |
| while (true) { |
| if (entries.putIfAbsent(uniqAlias, entry) == null) { |
| break; |
| } |
| uniqAlias = alias + " (" + (uniqNum++) + ")"; |
| } |
| } |
| |
| |
| /** |
| * Generates a certificate chain from the collection of |
| * certificates and stores the result into a key entry. |
| */ |
| private void generateCertificateChain(String alias, |
| Collection<? extends Certificate> certCollection) |
| { |
| try |
| { |
| X509Certificate[] certChain = |
| new X509Certificate[certCollection.size()]; |
| |
| int i = 0; |
| for (Iterator<? extends Certificate> iter = |
| certCollection.iterator(); iter.hasNext(); i++) |
| { |
| certChain[i] = (X509Certificate) iter.next(); |
| } |
| |
| storeWithUniqueAlias(alias, |
| new KeyEntry(alias, null, certChain)); |
| } |
| catch (Throwable e) |
| { |
| // Ignore the exception and skip this entry |
| // TODO - throw CertificateException? |
| } |
| } |
| |
| /** |
| * Generates RSA key and certificate chain from the private key handle, |
| * collection of certificates and stores the result into key entries. |
| */ |
| private void generateRSAKeyAndCertificateChain(String alias, |
| long hCryptProv, long hCryptKey, int keyLength, |
| Collection<? extends Certificate> certCollection) |
| { |
| try |
| { |
| X509Certificate[] certChain = |
| new X509Certificate[certCollection.size()]; |
| |
| int i = 0; |
| for (Iterator<? extends Certificate> iter = |
| certCollection.iterator(); iter.hasNext(); i++) |
| { |
| certChain[i] = (X509Certificate) iter.next(); |
| } |
| |
| storeWithUniqueAlias(alias, new KeyEntry(alias, |
| new RSAPrivateKey(hCryptProv, hCryptKey, keyLength), |
| certChain)); |
| } |
| catch (Throwable e) |
| { |
| // Ignore the exception and skip this entry |
| // TODO - throw CertificateException? |
| } |
| } |
| |
| /** |
| * Generates certificates from byte data and stores into cert collection. |
| * |
| * @param data Byte data. |
| * @param certCollection Collection of certificates. |
| */ |
| private void generateCertificate(byte[] data, |
| Collection<Certificate> certCollection) { |
| try |
| { |
| ByteArrayInputStream bis = new ByteArrayInputStream(data); |
| |
| // Obtain certificate factory |
| if (certificateFactory == null) { |
| certificateFactory = CertificateFactory.getInstance("X.509", "SUN"); |
| } |
| |
| // Generate certificate |
| Collection<? extends Certificate> c = |
| certificateFactory.generateCertificates(bis); |
| certCollection.addAll(c); |
| } |
| catch (CertificateException e) |
| { |
| // Ignore the exception and skip this certificate |
| // TODO - throw CertificateException? |
| } |
| catch (Throwable te) |
| { |
| // Ignore the exception and skip this certificate |
| // TODO - throw CertificateException? |
| } |
| } |
| |
| /** |
| * Returns the name of the keystore. |
| */ |
| private String getName() |
| { |
| return storeName; |
| } |
| |
| /** |
| * Load keys and/or certificates from keystore into Collection. |
| * |
| * @param name Name of keystore. |
| * @param entries Collection of key/certificate. |
| */ |
| private native void loadKeysOrCertificateChains(String name) |
| throws KeyStoreException; |
| |
| /** |
| * Stores a DER-encoded certificate into the certificate store |
| * |
| * @param name Name of the keystore. |
| * @param alias Name of the certificate. |
| * @param encoding DER-encoded certificate. |
| */ |
| private native void storeCertificate(String name, String alias, |
| byte[] encoding, int encodingLength, long hCryptProvider, |
| long hCryptKey) throws CertificateException, KeyStoreException; |
| |
| /** |
| * Removes the certificate from the certificate store |
| * |
| * @param name Name of the keystore. |
| * @param alias Name of the certificate. |
| * @param encoding DER-encoded certificate. |
| */ |
| private native void removeCertificate(String name, String alias, |
| byte[] encoding, int encodingLength) |
| throws CertificateException, KeyStoreException; |
| |
| /** |
| * Destroys the key container. |
| * |
| * @param keyContainerName The name of the key container. |
| */ |
| private native void destroyKeyContainer(String keyContainerName) |
| throws KeyStoreException; |
| |
| /** |
| * Generates a private-key BLOB from a key's components. |
| */ |
| private native byte[] generatePrivateKeyBlob( |
| int keyBitLength, |
| byte[] modulus, |
| byte[] publicExponent, |
| byte[] privateExponent, |
| byte[] primeP, |
| byte[] primeQ, |
| byte[] exponentP, |
| byte[] exponentQ, |
| byte[] crtCoefficient) throws InvalidKeyException; |
| |
| private native RSAPrivateKey storePrivateKey(byte[] keyBlob, |
| String keyContainerName, int keySize) throws KeyStoreException; |
| } |