Home | History | Annotate | Download | only in security
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.security;
     19 
     20 import java.io.File;
     21 import java.io.FileInputStream;
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 import java.io.OutputStream;
     25 import java.security.cert.Certificate;
     26 import java.security.cert.CertificateException;
     27 import java.security.cert.X509Certificate;
     28 import java.util.Arrays;
     29 import java.util.Date;
     30 import java.util.Enumeration;
     31 import javax.crypto.SecretKey;
     32 import javax.security.auth.DestroyFailedException;
     33 import javax.security.auth.Destroyable;
     34 import javax.security.auth.callback.CallbackHandler;
     35 import libcore.io.IoUtils;
     36 import org.apache.harmony.security.fortress.Engine;
     37 
     38 /**
     39  * {@code KeyStore} is responsible for maintaining cryptographic keys and their
     40  * owners.
     41  * <p>
     42  * The type of the system key store can be changed by setting the {@code
     43  * 'keystore.type'} property in the file named {@code
     44  * JAVA_HOME/lib/security/java.security}.
     45  *
     46  * @see Certificate
     47  * @see PrivateKey
     48  */
     49 public class KeyStore {
     50 
     51     // Store KeyStore SERVICE name
     52     private static final String SERVICE = "KeyStore";
     53 
     54     // Used to access common engine functionality
     55     private static final Engine ENGINE = new Engine(SERVICE);
     56 
     57     //  Store KeyStore property name
     58     private static final String PROPERTYNAME = "keystore.type";
     59 
     60     //  Store default KeyStore type
     61     private static final String DEFAULT_KEYSTORE_TYPE = "jks";
     62 
     63     // Store KeyStore state (initialized or not)
     64     private boolean isInit;
     65 
     66     // Store used KeyStoreSpi
     67     private final KeyStoreSpi implSpi;
     68 
     69     // Store used provider
     70     private final Provider provider;
     71 
     72     // Store used type
     73     private final String type;
     74 
     75     /**
     76      * Constructs a new instance of {@code KeyStore} with the given arguments.
     77      *
     78      * @param keyStoreSpi
     79      *            the concrete key store.
     80      * @param provider
     81      *            the provider.
     82      * @param type
     83      *            the type of the {@code KeyStore} to be constructed.
     84      */
     85     protected KeyStore(KeyStoreSpi keyStoreSpi, Provider provider, String type) {
     86         this.type = type;
     87         this.provider = provider;
     88         this.implSpi = keyStoreSpi;
     89         isInit = false;
     90     }
     91 
     92     /**
     93      * Throws the standard "keystore not initialized" exception.
     94      */
     95     private static void throwNotInitialized() throws KeyStoreException {
     96         throw new KeyStoreException("KeyStore was not initialized");
     97     }
     98 
     99     /**
    100      * Returns a new instance of {@code KeyStore} with the specified type.
    101      *
    102      * @param type
    103      *            the type of the returned {@code KeyStore}.
    104      * @return a new instance of {@code KeyStore} with the specified type.
    105      * @throws KeyStoreException
    106      *             if an error occurred during the creation of the new {@code
    107      *             KeyStore}.
    108      * @throws NullPointerException if {@code type == null}
    109      * @see #getDefaultType
    110      */
    111     public static KeyStore getInstance(String type) throws KeyStoreException {
    112         if (type == null) {
    113             throw new NullPointerException();
    114         }
    115         try {
    116             Engine.SpiAndProvider sap = ENGINE.getInstance(type, null);
    117             return new KeyStore((KeyStoreSpi) sap.spi, sap.provider, type);
    118         } catch (NoSuchAlgorithmException e) {
    119             throw new KeyStoreException(e);
    120         }
    121     }
    122 
    123     /**
    124      * Returns a new instance of {@code KeyStore} from the specified provider
    125      * with the given type.
    126      *
    127      * @param type
    128      *            the type of the returned {@code KeyStore}.
    129      * @param provider
    130      *            name of the provider of the {@code KeyStore}.
    131      * @return a new instance of {@code KeyStore} from the specified provider
    132      *         with the given type.
    133      * @throws KeyStoreException
    134      *             if an error occurred during the creation of the new {@code
    135      *             KeyStore}.
    136      * @throws NoSuchProviderException
    137      *             if the specified provider is not available.
    138      * @throws IllegalArgumentException if {@code provider == null || provider.isEmpty()}
    139      * @throws NullPointerException
    140      *             if {@code type} is {@code null} (instead of
    141      *             NoSuchAlgorithmException) as in 1.4 release
    142      * @see #getDefaultType
    143      */
    144     public static KeyStore getInstance(String type, String provider)
    145             throws KeyStoreException, NoSuchProviderException {
    146         if (provider == null || provider.isEmpty()) {
    147             throw new IllegalArgumentException();
    148         }
    149         Provider impProvider = Security.getProvider(provider);
    150         if (impProvider == null) {
    151             throw new NoSuchProviderException(provider);
    152         }
    153         try {
    154             return getInstance(type, impProvider);
    155         } catch (Exception e) {
    156             throw new KeyStoreException(e);
    157         }
    158     }
    159 
    160     /**
    161      * Returns a new instance of {@code KeyStore} from the specified provider
    162      * with the given type.
    163      *
    164      * @param type
    165      *            the type of the returned {@code KeyStore}.
    166      * @param provider
    167      *            the provider of the {@code KeyStore}.
    168      * @return a new instance of {@code KeyStore} from the specified provider
    169      *         with the given type.
    170      * @throws KeyStoreException
    171      *             if an error occurred during the creation of the new {@code
    172      *             KeyStore}.
    173      * @throws IllegalArgumentException
    174      *             if {@code provider} is {@code null} or the empty string.
    175      * @throws NullPointerException if {@code type == null} (instead of
    176      *             NoSuchAlgorithmException) as in 1.4 release
    177      * @see #getDefaultType
    178      */
    179     public static KeyStore getInstance(String type, Provider provider) throws KeyStoreException {
    180         // check parameters
    181         if (provider == null) {
    182             throw new IllegalArgumentException();
    183         }
    184         if (type == null) {
    185             throw new NullPointerException();
    186         }
    187         // return KeyStore instance
    188         try {
    189             Object spi = ENGINE.getInstance(type, provider, null);
    190             return new KeyStore((KeyStoreSpi) spi, provider, type);
    191         } catch (Exception e) {
    192             // override exception
    193             throw new KeyStoreException(e);
    194         }
    195     }
    196 
    197     /**
    198      * Returns the default type for {@code KeyStore} instances.
    199      *
    200      * <p>The default is specified in the {@code 'keystore.type'} property in the
    201      * file named {@code java.security} properties file. If this property
    202      * is not set, {@code "jks"} will be used.
    203      *
    204      * @return the default type for {@code KeyStore} instances
    205      */
    206     public static final String getDefaultType() {
    207         String dt = Security.getProperty(PROPERTYNAME);
    208         return (dt == null ? DEFAULT_KEYSTORE_TYPE : dt);
    209     }
    210 
    211     /**
    212      * Returns the provider associated with this {@code KeyStore}.
    213      *
    214      * @return the provider associated with this {@code KeyStore}.
    215      */
    216     public final Provider getProvider() {
    217         return provider;
    218     }
    219 
    220     /**
    221      * Returns the type of this {@code KeyStore}.
    222      *
    223      * @return the type of this {@code KeyStore}.
    224      */
    225     public final String getType() {
    226         return type;
    227     }
    228 
    229     /**
    230      * Returns the key with the given alias, using the password to recover the
    231      * key from the store.
    232      *
    233      * @param alias
    234      *            the alias for the entry.
    235      * @param password
    236      *            the password used to recover the key.
    237      * @return the key with the specified alias, or {@code null} if the
    238      *         specified alias is not bound to an entry.
    239      * @throws KeyStoreException
    240      *             if this {@code KeyStore} is not initialized.
    241      * @throws NoSuchAlgorithmException
    242      *             if the algorithm for recovering the key is not available.
    243      * @throws UnrecoverableKeyException
    244      *             if the key can not be recovered.
    245      */
    246     public final Key getKey(String alias, char[] password)
    247             throws KeyStoreException, NoSuchAlgorithmException,
    248             UnrecoverableKeyException {
    249         if (!isInit) {
    250             throwNotInitialized();
    251         }
    252         return implSpi.engineGetKey(alias, password);
    253     }
    254 
    255     /**
    256      * Returns the certificate chain for the entry with the given alias.
    257      *
    258      * @param alias
    259      *            the alias for the entry.
    260      * @return the certificate chain for the entry with the given alias, or
    261      *         {@code null} if the specified alias is not bound to an entry.
    262      * @throws KeyStoreException
    263      *             if this {@code KeyStore} is not initialized.
    264      */
    265     public final Certificate[] getCertificateChain(String alias) throws KeyStoreException {
    266         if (!isInit) {
    267             throwNotInitialized();
    268         }
    269         return implSpi.engineGetCertificateChain(alias);
    270     }
    271 
    272     /**
    273      * Returns the trusted certificate for the entry with the given alias.
    274      *
    275      * @param alias
    276      *            the alias for the entry.
    277      * @return the trusted certificate for the entry with the given alias, or
    278      *         {@code null} if the specified alias is not bound to an entry.
    279      * @throws KeyStoreException
    280      *             if this {@code KeyStore} is not initialized.
    281      */
    282     public final Certificate getCertificate(String alias) throws KeyStoreException {
    283         if (!isInit) {
    284             throwNotInitialized();
    285         }
    286         return implSpi.engineGetCertificate(alias);
    287     }
    288 
    289     /**
    290      * Returns the creation date of the entry with the given alias.
    291      *
    292      * @param alias
    293      *            the alias for the entry.
    294      * @return the creation date, or {@code null} if the specified alias is not
    295      *         bound to an entry.
    296      * @throws KeyStoreException
    297      *             if this {@code KeyStore} is not initialized.
    298      */
    299     public final Date getCreationDate(String alias) throws KeyStoreException {
    300         if (!isInit) {
    301             throwNotInitialized();
    302         }
    303         return implSpi.engineGetCreationDate(alias);
    304     }
    305 
    306     /**
    307      * Associates the given alias with the key, password and certificate chain.
    308      * <p>
    309      * If the specified alias already exists, it will be reassigned.
    310      *
    311      * @param alias
    312      *            the alias for the key.
    313      * @param key
    314      *            the key.
    315      * @param password
    316      *            the password.
    317      * @param chain
    318      *            the certificate chain.
    319      * @throws KeyStoreException
    320      *             if this {@code KeyStore} is not initialized.
    321      * @throws IllegalArgumentException
    322      *             if {@code key} is a {@code PrivateKey} and {@code chain} does
    323      *             not contain any certificates.
    324      * @throws NullPointerException
    325      *             if {@code alias} is {@code null}.
    326      */
    327     public final void setKeyEntry(String alias, Key key, char[] password,
    328             Certificate[] chain) throws KeyStoreException {
    329         if (!isInit) {
    330             throwNotInitialized();
    331         }
    332 
    333         // Certificate chain is required for PrivateKey
    334         if (key != null && key instanceof PrivateKey && (chain == null || chain.length == 0)) {
    335             throw new IllegalArgumentException("Certificate chain is not defined for Private key");
    336         }
    337         implSpi.engineSetKeyEntry(alias, key, password, chain);
    338     }
    339 
    340     /**
    341      * Associates the given alias with a key and a certificate chain.
    342      * <p>
    343      * If the specified alias already exists, it will be reassigned.
    344      * <p>
    345      * If this {@code KeyStore} is of type {@code "jks"}, {@code key} must be
    346      * encoded conform to the PKS#8 standard as an
    347      * {@link javax.crypto.EncryptedPrivateKeyInfo}.
    348      *
    349      * @param alias
    350      *            the alias for the key.
    351      * @param key
    352      *            the key in an encoded format.
    353      * @param chain
    354      *            the certificate chain.
    355      * @throws KeyStoreException
    356      *             if this {@code KeyStore} is not initialized or if {@code key}
    357      *             is null.
    358      * @throws IllegalArgumentException
    359      *             if {@code key} is a {@code PrivateKey} and {@code chain}
    360      *             does.
    361      * @throws NullPointerException
    362      *             if {@code alias} is {@code null}.
    363      */
    364     public final void setKeyEntry(String alias, byte[] key, Certificate[] chain)
    365             throws KeyStoreException {
    366         if (!isInit) {
    367             throwNotInitialized();
    368         }
    369         implSpi.engineSetKeyEntry(alias, key, chain);
    370     }
    371 
    372     /**
    373      * Associates the given alias with a certificate.
    374      * <p>
    375      * If the specified alias already exists, it will be reassigned.
    376      *
    377      * @param alias
    378      *            the alias for the certificate.
    379      * @param cert
    380      *            the certificate.
    381      * @throws KeyStoreException
    382      *             if this {@code KeyStore} is not initialized, or an existing
    383      *             alias is not associated to an entry containing a trusted
    384      *             certificate, or this method fails for any other reason.
    385      * @throws NullPointerException
    386      *             if {@code alias} is {@code null}.
    387      */
    388     public final void setCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
    389         if (!isInit) {
    390             throwNotInitialized();
    391         }
    392         implSpi.engineSetCertificateEntry(alias, cert);
    393     }
    394 
    395     /**
    396      * Deletes the entry identified with the given alias from this {@code
    397      * KeyStore}.
    398      *
    399      * @param alias
    400      *            the alias for the entry.
    401      * @throws KeyStoreException
    402      *             if this {@code KeyStore} is not initialized, or if the entry
    403      *             can not be deleted.
    404      */
    405     public final void deleteEntry(String alias) throws KeyStoreException {
    406         if (!isInit) {
    407             throwNotInitialized();
    408         }
    409         implSpi.engineDeleteEntry(alias);
    410     }
    411 
    412     /**
    413      * Returns an {@code Enumeration} over all alias names stored in this
    414      * {@code KeyStore}.
    415      *
    416      * @return an {@code Enumeration} over all alias names stored in this
    417      *         {@code KeyStore}.
    418      * @throws KeyStoreException
    419      *             if this {@code KeyStore} is not initialized.
    420      */
    421     public final Enumeration<String> aliases() throws KeyStoreException {
    422         if (!isInit) {
    423             throwNotInitialized();
    424         }
    425         return implSpi.engineAliases();
    426     }
    427 
    428     /**
    429      * Indicates whether the given alias is present in this {@code KeyStore}.
    430      *
    431      * @param alias
    432      *            the alias of an entry.
    433      * @return {@code true} if the alias exists, {@code false} otherwise.
    434      * @throws KeyStoreException
    435      *             if this {@code KeyStore} is not initialized.
    436      */
    437     public final boolean containsAlias(String alias) throws KeyStoreException {
    438         if (!isInit) {
    439             throwNotInitialized();
    440         }
    441         return implSpi.engineContainsAlias(alias);
    442     }
    443 
    444     /**
    445      * Returns the number of entries stored in this {@code KeyStore}.
    446      *
    447      * @return the number of entries stored in this {@code KeyStore}.
    448      * @throws KeyStoreException
    449      *             if this {@code KeyStore} is not initialized.
    450      */
    451     public final int size() throws KeyStoreException {
    452         if (!isInit) {
    453             throwNotInitialized();
    454         }
    455         return implSpi.engineSize();
    456     }
    457 
    458     /**
    459      * Indicates whether the specified alias is associated with either a
    460      * {@link PrivateKeyEntry} or a {@link SecretKeyEntry}.
    461      *
    462      * @param alias
    463      *            the alias of an entry.
    464      * @return {@code true} if the given alias is associated with a key entry.
    465      * @throws KeyStoreException
    466      *             if this {@code KeyStore} is not initialized.
    467      */
    468     public final boolean isKeyEntry(String alias) throws KeyStoreException {
    469         if (!isInit) {
    470             throwNotInitialized();
    471         }
    472         return implSpi.engineIsKeyEntry(alias);
    473     }
    474 
    475     /**
    476      * Indicates whether the specified alias is associated with a
    477      * {@link TrustedCertificateEntry}.
    478      *
    479      * @param alias
    480      *            the alias of an entry.
    481      * @return {@code true} if the given alias is associated with a certificate
    482      *         entry.
    483      * @throws KeyStoreException
    484      *             if this {@code KeyStore} is not initialized.
    485      */
    486     public final boolean isCertificateEntry(String alias) throws KeyStoreException {
    487         if (!isInit) {
    488             throwNotInitialized();
    489         }
    490         return implSpi.engineIsCertificateEntry(alias);
    491     }
    492 
    493     /**
    494      * Returns the alias associated with the first entry whose certificate
    495      * matches the specified certificate.
    496      *
    497      * @param cert
    498      *            the certificate to find the associated entry's alias for.
    499      * @return the alias or {@code null} if no entry with the specified
    500      *         certificate can be found.
    501      * @throws KeyStoreException
    502      *             if this {@code KeyStore} is not initialized.
    503      */
    504     public final String getCertificateAlias(Certificate cert) throws KeyStoreException {
    505         if (!isInit) {
    506             throwNotInitialized();
    507         }
    508         return implSpi.engineGetCertificateAlias(cert);
    509     }
    510 
    511     /**
    512      * Writes this {@code KeyStore} to the specified {@code OutputStream}. The
    513      * data written to the {@code OutputStream} is protected by the specified
    514      * password.
    515      *
    516      * @param stream
    517      *            the {@code OutputStream} to write the store's data to.
    518      * @param password
    519      *            the password to protect the data.
    520      * @throws KeyStoreException
    521      *             if this {@code KeyStore} is not initialized.
    522      * @throws IOException
    523      *             if a problem occurred while writing to the stream.
    524      * @throws NoSuchAlgorithmException
    525      *             if the required algorithm is not available.
    526      * @throws CertificateException
    527      *             if an exception occurred while storing the certificates of
    528      *             this {@code KeyStore}.
    529      */
    530     public final void store(OutputStream stream, char[] password)
    531             throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
    532         if (!isInit) {
    533             throwNotInitialized();
    534         }
    535 
    536         //Just delegate stream and password to implSpi
    537         implSpi.engineStore(stream, password);
    538     }
    539 
    540     /**
    541      * Stores this {@code KeyStore} using the specified {@code
    542      * LoadStoreParameter}.
    543      *
    544      * @param param
    545      *            the {@code LoadStoreParameter} that specifies how to store
    546      *            this {@code KeyStore}, maybe {@code null}.
    547      * @throws KeyStoreException
    548      *             if this {@code KeyStore} is not initialized.
    549      * @throws IOException
    550      *             if a problem occurred while writing to the stream.
    551      * @throws NoSuchAlgorithmException
    552      *             if the required algorithm is not available.
    553      * @throws CertificateException
    554      *             if an exception occurred while storing the certificates of
    555      *             this {@code KeyStore}.
    556      * @throws IllegalArgumentException
    557      *             if the given {@link LoadStoreParameter} is not recognized.
    558      */
    559     public final void store(LoadStoreParameter param) throws KeyStoreException,
    560             IOException, NoSuchAlgorithmException, CertificateException {
    561         if (!isInit) {
    562             throwNotInitialized();
    563         }
    564         implSpi.engineStore(param);
    565     }
    566 
    567     /**
    568      * Initializes this {@code KeyStore} from the provided {@code InputStream}.
    569      * Pass {@code null} as the {@code stream} argument to initialize an empty
    570      * {@code KeyStore} or to initialize a {@code KeyStore} which does not rely
    571      * on an {@code InputStream}. This {@code KeyStore} utilizes the given
    572      * password to verify the stored data.
    573      *
    574      * @param stream
    575      *            the {@code InputStream} to load this {@code KeyStore}'s data
    576      *            from or {@code null}.
    577      * @param password
    578      *            the password to verify the stored data, maybe {@code null}.
    579      * @throws IOException
    580      *             if a problem occurred while reading from the stream.
    581      * @throws NoSuchAlgorithmException
    582      *             if the required algorithm is not available.
    583      * @throws CertificateException
    584      *             if an exception occurred while loading the certificates of
    585      *             this {@code KeyStore}.
    586      */
    587     public final void load(InputStream stream, char[] password)
    588             throws IOException, NoSuchAlgorithmException, CertificateException {
    589         implSpi.engineLoad(stream, password);
    590         isInit = true;
    591     }
    592 
    593     /**
    594      * Loads this {@code KeyStore} using the specified {@code
    595      * LoadStoreParameter}.
    596      *
    597      * @param param
    598      *            the {@code LoadStoreParameter} that specifies how to load this
    599      *            {@code KeyStore}, maybe {@code null}.
    600      * @throws IOException
    601      *             if a problem occurred while reading from the stream.
    602      * @throws NoSuchAlgorithmException
    603      *             if the required algorithm is not available.
    604      * @throws CertificateException
    605      *             if an exception occurred while loading the certificates of
    606      *             this {@code KeyStore}.
    607      * @throws IllegalArgumentException
    608      *             if the given {@link LoadStoreParameter} is not recognized.
    609      */
    610     public final void load(LoadStoreParameter param) throws IOException,
    611             NoSuchAlgorithmException, CertificateException {
    612         implSpi.engineLoad(param);
    613         isInit = true;
    614     }
    615 
    616     /**
    617      * Returns the {@code Entry} with the given alias, using the specified
    618      * {@code ProtectionParameter}.
    619      *
    620      * @param alias
    621      *            the alias of the requested entry.
    622      * @param param
    623      *            the {@code ProtectionParameter} used to protect the requested
    624      *            entry, maybe {@code null}.
    625      * @return he {@code Entry} with the given alias, using the specified
    626      *         {@code ProtectionParameter}.
    627      * @throws NoSuchAlgorithmException
    628      *             if the required algorithm is not available.
    629      * @throws UnrecoverableEntryException
    630      *             if the entry can not be recovered.
    631      * @throws KeyStoreException
    632      *             if this {@code KeyStore} is not initialized.
    633      * @throws NullPointerException
    634      *             if {@code alias} is {@code null}.
    635      */
    636     public final Entry getEntry(String alias, ProtectionParameter param)
    637             throws NoSuchAlgorithmException, UnrecoverableEntryException, KeyStoreException {
    638         if (alias == null) {
    639             throw new NullPointerException("alias == null");
    640         }
    641         if (!isInit) {
    642             throwNotInitialized();
    643         }
    644         return implSpi.engineGetEntry(alias, param);
    645     }
    646 
    647     /**
    648      * Stores the given {@code Entry} in this {@code KeyStore} and associates
    649      * the entry with the given {@code alias}. The entry is protected by the
    650      * specified {@code ProtectionParameter}.
    651      * <p>
    652      * If the specified alias already exists, it will be reassigned.
    653      *
    654      * @param alias
    655      *            the alias for the entry.
    656      * @param entry
    657      *            the entry to store.
    658      * @param param
    659      *            the {@code ProtectionParameter} to protect the entry.
    660      * @throws KeyStoreException
    661      *             if this {@code KeyStore} is not initialized.
    662      * @throws NullPointerException
    663      *             if {@code alias} is {@code null} or {@code entry} is {@code
    664      *             null}.
    665      */
    666     public final void setEntry(String alias, Entry entry,
    667             ProtectionParameter param) throws KeyStoreException {
    668         if (!isInit) {
    669             throwNotInitialized();
    670         }
    671         if (alias == null) {
    672             throw new NullPointerException("alias == null");
    673         }
    674         if (entry == null) {
    675             throw new NullPointerException("entry == null");
    676         }
    677         implSpi.engineSetEntry(alias, entry, param);
    678     }
    679 
    680     /**
    681      * Indicates whether the entry for the given alias is assignable to the
    682      * provided {@code Class}.
    683      *
    684      * @param alias
    685      *            the alias for the entry.
    686      * @param entryClass
    687      *            the type of the entry.
    688      * @return {@code true} if the {@code Entry} for the alias is assignable to
    689      *         the specified {@code entryClass}.
    690      * @throws KeyStoreException
    691      *             if this {@code KeyStore} is not initialized.
    692      */
    693     public final boolean entryInstanceOf(String alias,
    694             Class<? extends KeyStore.Entry> entryClass)
    695             throws KeyStoreException {
    696         if (alias == null) {
    697             throw new NullPointerException("alias == null");
    698         }
    699         if (entryClass == null) {
    700             throw new NullPointerException("entryClass == null");
    701         }
    702 
    703         if (!isInit) {
    704             throwNotInitialized();
    705         }
    706         return implSpi.engineEntryInstanceOf(alias, entryClass);
    707     }
    708 
    709     /**
    710      * {@code Builder} is used to construct new instances of {@code KeyStore}.
    711      */
    712     public abstract static class Builder {
    713         /**
    714          * Constructs a new instance of {@code Builder}.
    715          */
    716         protected Builder() {
    717         }
    718 
    719         /**
    720          * Returns the {@code KeyStore} created by this {@code Builder}.
    721          *
    722          * @return the {@code KeyStore} created by this {@code Builder}.
    723          * @throws KeyStoreException
    724          *             if an error occurred during construction.
    725          */
    726         public abstract KeyStore getKeyStore() throws KeyStoreException;
    727 
    728         /**
    729          * Returns the {@code ProtectionParameter} to be used when a {@code
    730          * Entry} with the specified alias is requested. Before this method is
    731          * invoked, {@link #getKeyStore()} must be called.
    732          *
    733          * @param alias
    734          *            the alias for the entry.
    735          * @return the {@code ProtectionParameter} to be used when a {@code
    736          *         Entry} with the specified alias is requested.
    737          * @throws KeyStoreException
    738          *             if an error occurred during the lookup for the protection
    739          *             parameter.
    740          * @throws IllegalStateException
    741          *             if {@link #getKeyStore()} is not called prior the
    742          *             invocation of this method.
    743          * @throws NullPointerException
    744          *             if {@code alias} is {@code null}.
    745          */
    746         public abstract ProtectionParameter getProtectionParameter(String alias)
    747                 throws KeyStoreException;
    748 
    749         /**
    750          * Returns a new {@code Builder} that holds the given {@code KeyStore}
    751          * and the given {@code ProtectionParameter}.
    752          *
    753          * @param keyStore
    754          *            the {@code KeyStore} to be held.
    755          * @param protectionParameter
    756          *            the {@code ProtectionParameter} to be held.
    757          * @return a new instance of {@code Builder} that holds the specified
    758          *         {@code KeyStore} and the specified {@code
    759          *         ProtectionParameter}.
    760          * @throws NullPointerException
    761          *             if {@code keyStore} or {@code protectionParameter} is
    762          *             {@code null}.
    763          * @throws IllegalArgumentException
    764          *             if the given {@code KeyStore} is not initialized.
    765          */
    766         public static Builder newInstance(KeyStore keyStore,
    767                 ProtectionParameter protectionParameter) {
    768             if (keyStore == null) {
    769                 throw new NullPointerException("keyStore == null");
    770             }
    771             if (protectionParameter == null) {
    772                 throw new NullPointerException("protectionParameter == null");
    773             }
    774             if (!keyStore.isInit) {
    775                 throw new IllegalArgumentException("KeyStore was not initialized");
    776             }
    777             return new BuilderImpl(keyStore, protectionParameter, null, null, null);
    778         }
    779 
    780         /**
    781          * Returns a new {@code Builder} that creates a new {@code KeyStore}
    782          * based on the provided arguments.
    783          * <p>
    784          * If {@code provider} is {@code null}, all installed providers are
    785          * searched, otherwise the key store from the specified provider is
    786          * used.
    787          *
    788          * @param type
    789          *            the type of the {@code KeyStore} to be constructed.
    790          * @param provider
    791          *            the provider of the {@code KeyStore} to be constructed,
    792          *            maybe {@code null}.
    793          * @param file
    794          *            the {@code File} that contains the data for the {@code
    795          *            KeyStore}.
    796          * @param protectionParameter
    797          *            the {@code ProtectionParameter} used to protect the stored
    798          *            keys.
    799          * @return a new {@code Builder} that creates a new {@code KeyStore}
    800          *         based on the provided arguments.
    801          * @throws NullPointerException
    802          *             if {@code type, protectionParameter} or {@code file} is
    803          *             {@code null}.
    804          * @throws IllegalArgumentException
    805          *             {@code protectionParameter} not an instance of either
    806          *             {@code PasswordProtection} or {@code
    807          *             CallbackHandlerProtection}, {@code file} is not a file or
    808          *             does not exist at all.
    809          */
    810         public static Builder newInstance(String type, Provider provider,
    811                 File file, ProtectionParameter protectionParameter) {
    812             // check null parameters
    813             if (type == null) {
    814                 throw new NullPointerException("type == null");
    815             }
    816             if (protectionParameter == null) {
    817                 throw new NullPointerException("protectionParameter == null");
    818             }
    819             if (file == null) {
    820                 throw new NullPointerException("file == null");
    821             }
    822             // protection parameter should be PasswordProtection or
    823             // CallbackHandlerProtection
    824             if (!(protectionParameter instanceof PasswordProtection)
    825                     && !(protectionParameter instanceof CallbackHandlerProtection)) {
    826                 throw new IllegalArgumentException("protectionParameter is neither "
    827                         + "PasswordProtection nor CallbackHandlerProtection instance");
    828             }
    829             // check file parameter
    830             if (!file.exists()) {
    831                 throw new IllegalArgumentException("File does not exist: " + file.getName());
    832             }
    833             if (!file.isFile()) {
    834                 throw new IllegalArgumentException("Not a regular file: " + file.getName());
    835             }
    836             // create new instance
    837             return new BuilderImpl(null, protectionParameter, file, type, provider);
    838         }
    839 
    840         /**
    841          * Returns a new {@code Builder} that creates a new {@code KeyStore}
    842          * based on the provided arguments.
    843          * <p>
    844          * If {@code provider} is {@code null}, all installed providers are
    845          * searched, otherwise the key store from the specified provider is
    846          * used.
    847          *
    848          * @param type
    849          *            the type of the {@code KeyStore} to be constructed.
    850          * @param provider
    851          *            the provider of the {@code KeyStore} to be constructed,
    852          *            maybe {@code null}.
    853          * @param protectionParameter
    854          *            the {@code ProtectionParameter} used to protect the stored
    855          *            keys.
    856          * @return a new {@code Builder} that creates a new {@code KeyStore}
    857          *         based on the provided arguments.
    858          * @throws NullPointerException
    859          *             if {@code type} or {@code protectionParameter} is {@code
    860          *             null}.
    861          * @throws IllegalArgumentException
    862          *             {@code protectionParameter} not an instance of either
    863          *             {@code PasswordProtection} or {@code
    864          *             CallbackHandlerProtection}, {@code file} is not a file or
    865          *             does not exist at all.
    866          */
    867         public static Builder newInstance(String type, Provider provider,
    868                 ProtectionParameter protectionParameter) {
    869             if (type == null) {
    870                 throw new NullPointerException("type == null");
    871             }
    872             if (protectionParameter == null) {
    873                 throw new NullPointerException("protectionParameter == null");
    874             }
    875             return new BuilderImpl(null, protectionParameter, null, type, provider);
    876         }
    877 
    878         /*
    879          * This class is implementation of abstract class KeyStore.Builder
    880          *
    881          * @author Vera Petrashkova
    882          *
    883          */
    884         private static class BuilderImpl extends Builder {
    885             // Store used KeyStore
    886             private KeyStore keyStore;
    887 
    888             // Store used ProtectionParameter
    889             private ProtectionParameter protParameter;
    890 
    891             // Store used KeyStore type
    892             private final String typeForKeyStore;
    893 
    894             // Store used KeyStore provider
    895             private final Provider providerForKeyStore;
    896 
    897             // Store used file for KeyStore loading
    898             private final File fileForLoad;
    899 
    900             // Store getKeyStore method was invoked or not for KeyStoreBuilder
    901             private boolean isGetKeyStore = false;
    902 
    903             // Store last Exception in getKeyStore()
    904             private KeyStoreException lastException;
    905 
    906             /**
    907              * Constructor BuilderImpl initializes private fields: keyStore,
    908              * protParameter, typeForKeyStore providerForKeyStore fileForLoad,
    909              * isGetKeyStore
    910              */
    911             BuilderImpl(KeyStore ks, ProtectionParameter pp, File file,
    912                         String type, Provider provider) {
    913                 keyStore = ks;
    914                 protParameter = pp;
    915                 fileForLoad = file;
    916                 typeForKeyStore = type;
    917                 providerForKeyStore = provider;
    918                 isGetKeyStore = false;
    919                 lastException = null;
    920             }
    921 
    922             /**
    923              * Implementation of abstract getKeyStore() method If
    924              * KeyStoreBuilder encapsulates KeyStore object then this object is
    925              * returned
    926              *
    927              * If KeyStoreBuilder encapsulates KeyStore type and provider then
    928              * KeyStore is created using these parameters. If KeyStoreBuilder
    929              * encapsulates file and ProtectionParameter then KeyStore data are
    930              * loaded from FileInputStream that is created on file. If file is
    931              * not defined then KeyStore object is initialized with null
    932              * InputStream and null password.
    933              *
    934              * Result KeyStore object is returned.
    935              */
    936             @Override
    937             public synchronized KeyStore getKeyStore() throws KeyStoreException {
    938                 // If KeyStore was created but in final block some exception was
    939                 // thrown
    940                 // then it was stored in lastException variable and will be
    941                 // thrown
    942                 // all subsequent calls of this method.
    943                 if (lastException != null) {
    944                     throw lastException;
    945                 }
    946                 if (keyStore != null) {
    947                     isGetKeyStore = true;
    948                     return keyStore;
    949                 }
    950 
    951                 try {
    952                     // get KeyStore instance using type or type and provider
    953                     final KeyStore ks = (providerForKeyStore == null ? KeyStore
    954                             .getInstance(typeForKeyStore) : KeyStore
    955                             .getInstance(typeForKeyStore, providerForKeyStore));
    956                     // protection parameter should be PasswordProtection
    957                     // or CallbackHandlerProtection
    958                     final char[] passwd;
    959                     if (protParameter instanceof PasswordProtection) {
    960                         passwd = ((PasswordProtection) protParameter)
    961                                 .getPassword();
    962                     } else if (protParameter instanceof CallbackHandlerProtection) {
    963                         passwd = KeyStoreSpi
    964                                 .getPasswordFromCallBack(protParameter);
    965                     } else {
    966                         throw new KeyStoreException("protectionParameter is neither "
    967                                 + "PasswordProtection nor CallbackHandlerProtection instance");
    968                     }
    969 
    970                     // load KeyStore from file
    971                     if (fileForLoad != null) {
    972                         FileInputStream fis = null;
    973                         try {
    974                             fis = new FileInputStream(fileForLoad);
    975                             ks.load(fis, passwd);
    976                         } finally {
    977                             IoUtils.closeQuietly(fis);
    978                         }
    979                     } else {
    980                         ks.load(new TmpLSParameter(protParameter));
    981                     }
    982 
    983                     isGetKeyStore = true;
    984                     return ks;
    985                 } catch (KeyStoreException e) {
    986                     // Store exception
    987                     throw lastException = e;
    988                 } catch (Exception e) {
    989                     // Override exception
    990                     throw lastException = new KeyStoreException(e);
    991                 }
    992             }
    993 
    994             /**
    995              * This is implementation of abstract method
    996              * getProtectionParameter(String alias)
    997              *
    998              * Return: ProtectionParameter to get Entry which was saved in
    999              * KeyStore with defined alias
   1000              */
   1001             @Override
   1002             public synchronized ProtectionParameter getProtectionParameter(
   1003                     String alias) throws KeyStoreException {
   1004                 if (alias == null) {
   1005                     throw new NullPointerException("alias == null");
   1006                 }
   1007                 if (!isGetKeyStore) {
   1008                     throw new IllegalStateException("getKeyStore() was not invoked");
   1009                 }
   1010                 return protParameter;
   1011             }
   1012         }
   1013 
   1014         /*
   1015          * Implementation of LoadStoreParameter interface
   1016          */
   1017         private static class TmpLSParameter implements LoadStoreParameter {
   1018 
   1019             // Store used protection parameter
   1020             private final ProtectionParameter protPar;
   1021 
   1022             /**
   1023              * Creates TmpLoadStoreParameter object
   1024              * @param protPar protection parameter
   1025              */
   1026             public TmpLSParameter(ProtectionParameter protPar) {
   1027                 this.protPar = protPar;
   1028             }
   1029 
   1030             /**
   1031              * This method returns protection parameter
   1032              */
   1033             public ProtectionParameter getProtectionParameter() {
   1034                 return protPar;
   1035             }
   1036         }
   1037     }
   1038 
   1039     /**
   1040      * {@code CallbackHandlerProtection} is a {@code ProtectionParameter} that
   1041      * encapsulates a {@link CallbackHandler}.
   1042      */
   1043     public static class CallbackHandlerProtection implements
   1044             ProtectionParameter {
   1045         // Store CallbackHandler
   1046         private final CallbackHandler callbackHandler;
   1047 
   1048         /**
   1049          * Constructs a new instance of {@code CallbackHandlerProtection} with
   1050          * the {@code CallbackHandler}.
   1051          *
   1052          * @param handler
   1053          *            the {@code CallbackHandler}.
   1054          * @throws NullPointerException
   1055          *             if {@code handler} is {@code null}.
   1056          */
   1057         public CallbackHandlerProtection(CallbackHandler handler) {
   1058             if (handler == null) {
   1059                 throw new NullPointerException("handler == null");
   1060             }
   1061             this.callbackHandler = handler;
   1062         }
   1063 
   1064         /**
   1065          * Returns the {@code CallbackHandler}.
   1066          *
   1067          * @return the {@code CallbackHandler}.
   1068          */
   1069         public CallbackHandler getCallbackHandler() {
   1070             return callbackHandler;
   1071         }
   1072     }
   1073 
   1074     /**
   1075      * {@code Entry} is the common marker interface for a {@code KeyStore}
   1076      * entry.
   1077      */
   1078     public static interface Entry {
   1079     }
   1080 
   1081     /**
   1082      * {@code LoadStoreParameter} represents a parameter that specifies how a
   1083      * {@code KeyStore} can be loaded and stored.
   1084      *
   1085      * @see KeyStore#load(LoadStoreParameter)
   1086      * @see KeyStore#store(LoadStoreParameter)
   1087      */
   1088     public static interface LoadStoreParameter {
   1089         /**
   1090          * Returns the {@code ProtectionParameter} which is used to protect data
   1091          * in the {@code KeyStore}.
   1092          *
   1093          * @return the {@code ProtectionParameter} which is used to protect data
   1094          *         in the {@code KeyStore}, maybe {@code null}.
   1095          */
   1096         public ProtectionParameter getProtectionParameter();
   1097     }
   1098 
   1099     /**
   1100      * {@code PasswordProtection} is a {@code ProtectionParameter} that protects
   1101      * a {@code KeyStore} using a password.
   1102      */
   1103     public static class PasswordProtection implements ProtectionParameter,
   1104             Destroyable {
   1105 
   1106         // Store password
   1107         private char[] password;
   1108 
   1109         private boolean isDestroyed = false;
   1110 
   1111         /**
   1112          * Constructs a new instance of {@code PasswordProtection} with a
   1113          * password. A copy of the password is stored in the new {@code
   1114          * PasswordProtection} object.
   1115          *
   1116          * @param password
   1117          *            the password, maybe {@code null}.
   1118          */
   1119         public PasswordProtection(char[] password) {
   1120             if (password != null) {
   1121                 this.password = password.clone();
   1122             }
   1123         }
   1124 
   1125         /**
   1126          * Returns the password.
   1127          *
   1128          * @return the password.
   1129          * @throws IllegalStateException
   1130          *             if the password has been destroyed.
   1131          */
   1132         public synchronized char[] getPassword() {
   1133             if (isDestroyed) {
   1134                 throw new IllegalStateException("Password was destroyed");
   1135             }
   1136             return password;
   1137         }
   1138 
   1139         /**
   1140          * Destroys / invalidates the password.
   1141          *
   1142          * @throws DestroyFailedException
   1143          *             if the password could not be invalidated.
   1144          */
   1145         public synchronized void destroy() throws DestroyFailedException {
   1146             isDestroyed = true;
   1147             if (password != null) {
   1148                 Arrays.fill(password, '\u0000');
   1149                 password = null;
   1150             }
   1151         }
   1152 
   1153         /**
   1154          * Indicates whether the password is invalidated.
   1155          *
   1156          * @return {@code true} if the password is invalidated, {@code false}
   1157          *         otherwise.
   1158          */
   1159         public synchronized boolean isDestroyed() {
   1160             return isDestroyed;
   1161         }
   1162     }
   1163 
   1164     /**
   1165      * {@code ProtectionParameter} is a marker interface for protection
   1166      * parameters. A protection parameter is used to protect the content of a
   1167      * {@code KeyStore}.
   1168      */
   1169     public static interface ProtectionParameter {
   1170     }
   1171 
   1172     /**
   1173      * {@code PrivateKeyEntry} represents a {@code KeyStore} entry that
   1174      * holds a private key.
   1175      */
   1176     public static final class PrivateKeyEntry implements Entry {
   1177         // Store Certificate chain
   1178         private Certificate[] chain;
   1179 
   1180         // Store PrivateKey
   1181         private PrivateKey privateKey;
   1182 
   1183         /**
   1184          * Constructs a new instance of {@code PrivateKeyEntry} with the given
   1185          * {@code PrivateKey} and the provided certificate chain.
   1186          *
   1187          * @param privateKey
   1188          *            the private key.
   1189          * @param chain
   1190          *            the ordered certificate chain with the certificate
   1191          *            corresponding to the private key at index 0.
   1192          * @throws NullPointerException
   1193          *             if {@code privateKey} or {@code chain} is {@code null}.
   1194          * @throws IllegalArgumentException
   1195          *             if {@code chain.length == 0}, the algorithm of the
   1196          *             private key does not match the algorithm of the public
   1197          *             key of the first certificate or the certificates are not
   1198          *             all of the same type.
   1199          */
   1200         public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) {
   1201             if (privateKey == null) {
   1202                 throw new NullPointerException("privateKey == null");
   1203             }
   1204             if (chain == null) {
   1205                 throw new NullPointerException("chain == null");
   1206             }
   1207 
   1208             if (chain.length == 0) {
   1209                 throw new IllegalArgumentException("chain.length == 0");
   1210             }
   1211             // Match algorithm of private key and algorithm of public key from
   1212             // the end certificate
   1213             String s = chain[0].getType();
   1214             if (!(chain[0].getPublicKey().getAlgorithm()).equals(privateKey.getAlgorithm())) {
   1215                 throw new IllegalArgumentException("Algorithm of private key does not match "
   1216                         + "algorithm of public key in end certificate of entry "
   1217                         + "(with index number: 0)");
   1218             }
   1219             // Match certificate types
   1220             for (int i = 1; i < chain.length; i++) {
   1221                 if (!s.equals(chain[i].getType())) {
   1222                     throw new IllegalArgumentException("Certificates from the given chain have "
   1223                                                        + "different types");
   1224                 }
   1225             }
   1226             // clone chain - this.chain = (Certificate[])chain.clone();
   1227             boolean isAllX509Certificates = true;
   1228             // assert chain length > 0
   1229             for (Certificate cert: chain) {
   1230                 if (!(cert instanceof X509Certificate)) {
   1231                     isAllX509Certificates = false;
   1232                     break;
   1233                 }
   1234             }
   1235 
   1236             if(isAllX509Certificates){
   1237                 this.chain = new X509Certificate[chain.length];
   1238             } else {
   1239                 this.chain = new Certificate[chain.length];
   1240             }
   1241             System.arraycopy(chain, 0, this.chain, 0, chain.length);
   1242             this.privateKey = privateKey;
   1243         }
   1244 
   1245         /**
   1246          * Returns the private key.
   1247          *
   1248          * @return the private key.
   1249          */
   1250         public PrivateKey getPrivateKey() {
   1251             return privateKey;
   1252         }
   1253 
   1254         /**
   1255          * Returns the certificate chain.
   1256          *
   1257          * @return the certificate chain.
   1258          */
   1259         public Certificate[] getCertificateChain() {
   1260             return chain.clone();
   1261         }
   1262 
   1263         /**
   1264          * Returns the certificate corresponding to the private key.
   1265          *
   1266          * @return the certificate corresponding to the private key.
   1267          */
   1268         public Certificate getCertificate() {
   1269             return chain[0];
   1270         }
   1271 
   1272         /**
   1273          * Returns a string containing a concise, human-readable description of
   1274          * this {@code PrivateKeyEntry}.
   1275          *
   1276          * @return a printable representation for this {@code PrivateKeyEntry}.
   1277          */
   1278         @Override
   1279         public String toString() {
   1280             StringBuilder sb = new StringBuilder(
   1281                     "PrivateKeyEntry: number of elements in certificate chain is ");
   1282             sb.append(Integer.toString(chain.length));
   1283             sb.append("\n");
   1284             for (int i = 0; i < chain.length; i++) {
   1285                 sb.append(chain[i].toString());
   1286                 sb.append("\n");
   1287             }
   1288             return sb.toString();
   1289         }
   1290     }
   1291 
   1292     /**
   1293      * {@code SecretKeyEntry} represents a {@code KeyStore} entry that
   1294      * holds a secret key.
   1295      */
   1296     public static final class SecretKeyEntry implements Entry {
   1297 
   1298         // Store SecretKey
   1299         private final SecretKey secretKey;
   1300 
   1301         /**
   1302          * Constructs a new instance of {@code SecretKeyEntry} with the given
   1303          * {@code SecretKey}.
   1304          *
   1305          * @param secretKey
   1306          *            the secret key.
   1307          * @throws NullPointerException
   1308          *             if {@code secretKey} is {@code null}.
   1309          */
   1310         public SecretKeyEntry(SecretKey secretKey) {
   1311             if (secretKey == null) {
   1312                 throw new NullPointerException("secretKey == null");
   1313             }
   1314             this.secretKey = secretKey;
   1315         }
   1316 
   1317         /**
   1318          * Returns the secret key.
   1319          *
   1320          * @return the secret key.
   1321          */
   1322         public SecretKey getSecretKey() {
   1323             return secretKey;
   1324         }
   1325 
   1326         /**
   1327          * Returns a string containing a concise, human-readable description of
   1328          * this {@code SecretKeyEntry}.
   1329          *
   1330          * @return a printable representation for this {@code
   1331          *         SecretKeyEntry}.
   1332          */
   1333         @Override
   1334         public String toString() {
   1335             StringBuilder sb = new StringBuilder("SecretKeyEntry: algorithm - ");
   1336             sb.append(secretKey.getAlgorithm());
   1337             return sb.toString();
   1338         }
   1339     }
   1340 
   1341     /**
   1342      * {@code TrustedCertificateEntry} represents a {@code KeyStore} entry that
   1343      * holds a trusted certificate.
   1344      */
   1345     public static final class TrustedCertificateEntry implements Entry {
   1346 
   1347         // Store trusted Certificate
   1348         private final Certificate trustCertificate;
   1349 
   1350         /**
   1351          * Constructs a new instance of {@code TrustedCertificateEntry} with the
   1352          * given {@code Certificate}.
   1353          *
   1354          * @param trustCertificate
   1355          *            the trusted certificate.
   1356          * @throws NullPointerException
   1357          *             if {@code trustCertificate} is {@code null}.
   1358          */
   1359         public TrustedCertificateEntry(Certificate trustCertificate) {
   1360             if (trustCertificate == null) {
   1361                 throw new NullPointerException("trustCertificate == null");
   1362             }
   1363             this.trustCertificate = trustCertificate;
   1364         }
   1365 
   1366         /**
   1367          * Returns the trusted certificate.
   1368          *
   1369          * @return the trusted certificate.
   1370          */
   1371         public Certificate getTrustedCertificate() {
   1372             return trustCertificate;
   1373         }
   1374 
   1375         /**
   1376          * Returns a string containing a concise, human-readable description of
   1377          * this {@code TrustedCertificateEntry}.
   1378          *
   1379          * @return a printable representation for this {@code
   1380          *         TrustedCertificateEntry}.
   1381          */
   1382         @Override
   1383         public String toString() {
   1384             return "Trusted certificate entry:\n" + trustCertificate;
   1385         }
   1386     }
   1387 }
   1388