/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.security; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.Date; import java.util.Enumeration; import javax.crypto.SecretKey; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.PasswordCallback; /** * {@code KeyStoreSpi} is the Service Provider Interface (SPI) definition for * {@link KeyStore}. * * @see KeyStore */ public abstract class KeyStoreSpi { /** * Returns the key with the given alias, using the password to recover the * key from the store. * * @param alias * the alias for the entry. * @param password * the password used to recover the key. * @return the key with the specified alias, or {@code null} if the * specified alias is not bound to an entry. * @throws NoSuchAlgorithmException * if the algorithm for recovering the key is not available. * @throws UnrecoverableKeyException * if the key can not be recovered. */ public abstract Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException; /** * Returns the certificate chain for the entry with the given alias. * * @param alias * the alias for the entry * @return the certificate chain for the entry with the given alias, or * {@code null} if the specified alias is not bound to an entry. */ public abstract Certificate[] engineGetCertificateChain(String alias); /** * Returns the trusted certificate for the entry with the given alias. * * @param alias * the alias for the entry. * @return the trusted certificate for the entry with the given alias, or * {@code null} if the specified alias is not bound to an entry. */ public abstract Certificate engineGetCertificate(String alias); /** * Returns the creation date of the entry with the given alias. * * @param alias * the alias for the entry. * @return the creation date, or {@code null} if the specified alias is not * bound to an entry. */ public abstract Date engineGetCreationDate(String alias); /** * Associates the given alias with the key, password and certificate chain. * <p> * If the specified alias already exists, it will be reassigned. * * @param alias * the alias for the key. * @param key * the key. * @param password * the password. * @param chain * the certificate chain. * @throws KeyStoreException * if the specified key can not be protected, or if this * operation fails for another reason. * @throws IllegalArgumentException * if {@code key} is a {@code PrivateKey} and {@code chain} does * not contain any certificates. */ public abstract void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) throws KeyStoreException; /** * Associates the given alias with a key and a certificate chain. * <p> * If the specified alias already exists, it will be reassigned. * * @param alias * the alias for the key. * @param key * the key in an encoded format. * @param chain * the certificate chain. * @throws KeyStoreException * if this operation fails. * @throws IllegalArgumentException * if {@code key} is a {@code PrivateKey} and {@code chain} * does. */ public abstract void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException; /** * Associates the given alias with a certificate. * <p> * If the specified alias already exists, it will be reassigned. * * @param alias * the alias for the certificate. * @param cert * the certificate. * @throws KeyStoreException * if an existing alias is not associated to an entry containing * a trusted certificate, or this method fails for any other * reason. */ public abstract void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException; /** * Deletes the entry identified with the given alias from this {@code * KeyStoreSpi}. * * @param alias * the alias for the entry. * @throws KeyStoreException * if the entry can not be deleted. */ public abstract void engineDeleteEntry(String alias) throws KeyStoreException; /** * Returns an {@code Enumeration} over all alias names stored in this * {@code KeyStoreSpi}. * * @return an {@code Enumeration} over all alias names stored in this * {@code KeyStoreSpi}. */ public abstract Enumeration<String> engineAliases(); /** * Indicates whether the given alias is present in this {@code KeyStoreSpi}. * * @param alias * the alias of an entry. * @return {@code true} if the alias exists, {@code false} otherwise. */ public abstract boolean engineContainsAlias(String alias); /** * Returns the number of entries stored in this {@code KeyStoreSpi}. * * @return the number of entries stored in this {@code KeyStoreSpi}. */ public abstract int engineSize(); /** * Indicates whether the specified alias is associated with either a * {@link KeyStore.PrivateKeyEntry} or a {@link KeyStore.SecretKeyEntry}. * * @param alias * the alias of an entry. * @return {@code true} if the given alias is associated with a key entry. */ public abstract boolean engineIsKeyEntry(String alias); /** * Indicates whether the specified alias is associated with a * {@link KeyStore.TrustedCertificateEntry}. * * @param alias * the alias of an entry. * @return {@code true} if the given alias is associated with a certificate * entry. */ public abstract boolean engineIsCertificateEntry(String alias); /** * Returns the alias associated with the first entry whose certificate * matches the specified certificate. * * @param cert * the certificate to find the associated entry's alias for. * @return the alias or {@code null} if no entry with the specified * certificate can be found. */ public abstract String engineGetCertificateAlias(Certificate cert); /** * Writes this {@code KeyStoreSpi} to the specified {@code OutputStream}. * The data written to the {@code OutputStream} is protected by the * specified password. * * @param stream * the {@code OutputStream} to write the store's data to. * @param password * the password to protect the data. * @throws IOException * if a problem occurred while writing to the stream. * @throws NoSuchAlgorithmException * if the required algorithm is not available. * @throws CertificateException * if the an exception occurred while storing the certificates * of this code {@code KeyStoreSpi}. */ public abstract void engineStore(OutputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException; /** * Stores this {@code KeyStoreSpi} using the specified {@code * LoadStoreParameter}. * * @param param * the {@code LoadStoreParameter} that specifies how to store * this {@code KeyStoreSpi}, maybe {@code null}. * @throws IOException * if a problem occurred while writing to the stream. * @throws NoSuchAlgorithmException * if the required algorithm is not available. * @throws CertificateException * if the an exception occurred while storing the certificates * of this code {@code KeyStoreSpi}. * @throws IllegalArgumentException * if the given {@link KeyStore.LoadStoreParameter} is not * recognized. */ public void engineStore(KeyStore.LoadStoreParameter param) throws IOException, NoSuchAlgorithmException, CertificateException { throw new UnsupportedOperationException(); } /** * Loads this {@code KeyStoreSpi} from the given {@code InputStream}. * Utilizes the given password to verify the stored data. * * @param stream * the {@code InputStream} to load this {@code KeyStoreSpi}'s * data from. * @param password * the password to verify the stored data, maybe {@code null}. * @throws IOException * if a problem occurred while reading from the stream. * @throws NoSuchAlgorithmException * if the required algorithm is not available. * @throws CertificateException * if the an exception occurred while loading the certificates * of this code {@code KeyStoreSpi}. */ public abstract void engineLoad(InputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException; /** * Loads this {@code KeyStoreSpi} using the specified {@code * LoadStoreParameter}. * * @param param * the {@code LoadStoreParameter} that specifies how to load this * {@code KeyStoreSpi}, maybe {@code null}. * @throws IOException * if a problem occurred while reading from the stream. * @throws NoSuchAlgorithmException * if the required algorithm is not available. * @throws CertificateException * if the an exception occurred while loading the certificates * of this code {@code KeyStoreSpi}. * @throws IllegalArgumentException * if the given {@link KeyStore.LoadStoreParameter} is not * recognized. */ public void engineLoad(KeyStore.LoadStoreParameter param) throws IOException, NoSuchAlgorithmException, CertificateException { if (param == null) { engineLoad(null, null); return; } char[] pwd; KeyStore.ProtectionParameter pp = param.getProtectionParameter(); if (pp instanceof KeyStore.PasswordProtection) { try { pwd = ((KeyStore.PasswordProtection) pp).getPassword(); engineLoad(null, pwd); return; } catch (IllegalStateException e) { throw new IllegalArgumentException(e); } } if (pp instanceof KeyStore.CallbackHandlerProtection) { try { pwd = getPasswordFromCallBack(pp); engineLoad(null, pwd); return; } catch (UnrecoverableEntryException e) { throw new IllegalArgumentException(e); } } throw new UnsupportedOperationException("protectionParameter is neither PasswordProtection " + "nor CallbackHandlerProtection instance"); } /** * Returns the {@code Entry} with the given alias, using the specified * {@code ProtectionParameter}. * * @param alias * the alias of the requested entry. * @param protParam * the {@code ProtectionParameter}, used to protect the requested * entry, maybe {@code null}. * @return he {@code Entry} with the given alias, using the specified * {@code ProtectionParameter}. * @throws NoSuchAlgorithmException * if the required algorithm is not available. * @throws UnrecoverableEntryException * if the entry can not be recovered. * @throws KeyStoreException * if this operation fails */ public KeyStore.Entry engineGetEntry(String alias, KeyStore.ProtectionParameter protParam) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException { if (!engineContainsAlias(alias)) { return null; } if (engineIsCertificateEntry(alias)) { return new KeyStore.TrustedCertificateEntry( engineGetCertificate(alias)); } char[] passW = null; if (protParam != null) { if (protParam instanceof KeyStore.PasswordProtection) { try { passW = ((KeyStore.PasswordProtection) protParam) .getPassword(); } catch (IllegalStateException ee) { throw new KeyStoreException("Password was destroyed", ee); } } else if (protParam instanceof KeyStore.CallbackHandlerProtection) { passW = getPasswordFromCallBack(protParam); } else { throw new UnrecoverableEntryException("ProtectionParameter object is not " + "PasswordProtection: " + protParam); } } if (engineIsKeyEntry(alias)) { Key key = engineGetKey(alias, passW); if (key instanceof PrivateKey) { return new KeyStore.PrivateKeyEntry((PrivateKey) key, engineGetCertificateChain(alias)); } if (key instanceof SecretKey) { return new KeyStore.SecretKeyEntry((SecretKey) key); } } throw new NoSuchAlgorithmException("Unknown KeyStore.Entry object"); } /** * Stores the given {@code Entry} in this {@code KeyStoreSpi} and associates * the entry with the given {@code alias}. The entry is protected by the * specified {@code ProtectionParameter}. * <p> * If the specified alias already exists, it will be reassigned. * * @param alias * the alias for the entry. * @param entry * the entry to store. * @param protParam * the {@code ProtectionParameter} to protect the entry. * @throws KeyStoreException * if this operation fails. */ public void engineSetEntry(String alias, KeyStore.Entry entry, KeyStore.ProtectionParameter protParam) throws KeyStoreException { if (entry == null) { throw new KeyStoreException("entry == null"); } if (engineContainsAlias(alias)) { engineDeleteEntry(alias); } if (entry instanceof KeyStore.TrustedCertificateEntry) { KeyStore.TrustedCertificateEntry trE = (KeyStore.TrustedCertificateEntry) entry; engineSetCertificateEntry(alias, trE.getTrustedCertificate()); return; } char[] passW = null; if (protParam != null) { if (protParam instanceof KeyStore.PasswordProtection) { try { passW = ((KeyStore.PasswordProtection) protParam).getPassword(); } catch (IllegalStateException ee) { throw new KeyStoreException("Password was destroyed", ee); } } else if (protParam instanceof KeyStore.CallbackHandlerProtection) { try { passW = getPasswordFromCallBack(protParam); } catch (Exception e) { throw new KeyStoreException(e); } } else { throw new KeyStoreException("protParam should be PasswordProtection or " + "CallbackHandlerProtection"); } } if (entry instanceof KeyStore.PrivateKeyEntry) { KeyStore.PrivateKeyEntry prE = (KeyStore.PrivateKeyEntry) entry; engineSetKeyEntry(alias, prE.getPrivateKey(), passW, prE .getCertificateChain()); return; } if (entry instanceof KeyStore.SecretKeyEntry) { KeyStore.SecretKeyEntry skE = (KeyStore.SecretKeyEntry) entry; engineSetKeyEntry(alias, skE.getSecretKey(), passW, null); // engineSetKeyEntry(alias, skE.getSecretKey().getEncoded(), null); return; } throw new KeyStoreException("Entry object is neither PrivateKeyObject nor SecretKeyEntry " + "nor TrustedCertificateEntry: " + entry); } /** * Indicates whether the entry for the given alias is assignable to the * provided {@code Class}. * * @param alias * the alias for the entry. * @param entryClass * the type of the entry. * @return {@code true} if the {@code Entry} for the alias is assignable to * the specified {@code entryClass}. */ public boolean engineEntryInstanceOf(String alias, Class<? extends KeyStore.Entry> entryClass) { if (!engineContainsAlias(alias)) { return false; } try { if (engineIsCertificateEntry(alias)) { return entryClass .isAssignableFrom(Class .forName("java.security.KeyStore$TrustedCertificateEntry")); } if (engineIsKeyEntry(alias)) { if (entryClass.isAssignableFrom(Class .forName("java.security.KeyStore$PrivateKeyEntry"))) { return engineGetCertificate(alias) != null; } if (entryClass.isAssignableFrom(Class .forName("java.security.KeyStore$SecretKeyEntry"))) { return engineGetCertificate(alias) == null; } } } catch (ClassNotFoundException ignore) {} return false; } /* * This method returns password which is encapsulated in * CallbackHandlerProtection object If there is no implementation of * CallbackHandler then this method returns null */ static char[] getPasswordFromCallBack(KeyStore.ProtectionParameter protParam) throws UnrecoverableEntryException { if (protParam == null) { return null; } if (!(protParam instanceof KeyStore.CallbackHandlerProtection)) { throw new UnrecoverableEntryException("Incorrect ProtectionParameter"); } String clName = Security.getProperty("auth.login.defaultCallbackHandler"); if (clName == null) { throw new UnrecoverableEntryException("Default CallbackHandler was not defined"); } try { Class<?> cl = Class.forName(clName); CallbackHandler cbHand = (CallbackHandler) cl.newInstance(); PasswordCallback[] pwCb = { new PasswordCallback("password: ", true) }; cbHand.handle(pwCb); return pwCb[0].getPassword(); } catch (Exception e) { throw new UnrecoverableEntryException(e.toString()); } } }