Home | History | Annotate | Download | only in security
      1 /*
      2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package java.security;
     27 
     28 import java.io.*;
     29 import java.net.URI;
     30 import java.security.cert.Certificate;
     31 import java.security.cert.X509Certificate;
     32 import java.security.cert.CertificateException;
     33 import java.security.spec.AlgorithmParameterSpec;
     34 import java.util.*;
     35 import javax.crypto.SecretKey;
     36 
     37 import javax.security.auth.DestroyFailedException;
     38 import javax.security.auth.callback.*;
     39 
     40 /**
     41  * This class represents a storage facility for cryptographic
     42  * keys and certificates.
     43  *
     44  * <p> A {@code KeyStore} manages different types of entries.
     45  * Each type of entry implements the {@code KeyStore.Entry} interface.
     46  * Three basic {@code KeyStore.Entry} implementations are provided:
     47  *
     48  * <ul>
     49  * <li><b>KeyStore.PrivateKeyEntry</b>
     50  * <p> This type of entry holds a cryptographic {@code PrivateKey},
     51  * which is optionally stored in a protected format to prevent
     52  * unauthorized access.  It is also accompanied by a certificate chain
     53  * for the corresponding public key.
     54  *
     55  * <p> Private keys and certificate chains are used by a given entity for
     56  * self-authentication. Applications for this authentication include software
     57  * distribution organizations which sign JAR files as part of releasing
     58  * and/or licensing software.
     59  *
     60  * <li><b>KeyStore.SecretKeyEntry</b>
     61  * <p> This type of entry holds a cryptographic {@code SecretKey},
     62  * which is optionally stored in a protected format to prevent
     63  * unauthorized access.
     64  *
     65  * <li><b>KeyStore.TrustedCertificateEntry</b>
     66  * <p> This type of entry contains a single public key {@code Certificate}
     67  * belonging to another party. It is called a <i>trusted certificate</i>
     68  * because the keystore owner trusts that the public key in the certificate
     69  * indeed belongs to the identity identified by the <i>subject</i> (owner)
     70  * of the certificate.
     71  *
     72  * <p>This type of entry can be used to authenticate other parties.
     73  * </ul>
     74  *
     75  * <p> Each entry in a keystore is identified by an "alias" string. In the
     76  * case of private keys and their associated certificate chains, these strings
     77  * distinguish among the different ways in which the entity may authenticate
     78  * itself. For example, the entity may authenticate itself using different
     79  * certificate authorities, or using different public key algorithms.
     80  *
     81  * <p> Whether aliases are case sensitive is implementation dependent. In order
     82  * to avoid problems, it is recommended not to use aliases in a KeyStore that
     83  * only differ in case.
     84  *
     85  * <p> Whether keystores are persistent, and the mechanisms used by the
     86  * keystore if it is persistent, are not specified here. This allows
     87  * use of a variety of techniques for protecting sensitive (e.g., private or
     88  * secret) keys. Smart cards or other integrated cryptographic engines
     89  * (SafeKeyper) are one option, and simpler mechanisms such as files may also
     90  * be used (in a variety of formats).
     91  *
     92  * <p> Typical ways to request a KeyStore object include
     93  * relying on the default type and providing a specific keystore type.
     94  *
     95  * <ul>
     96  * <li>To rely on the default type:
     97  * <pre>
     98  *    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
     99  * </pre>
    100  * The system will return a keystore implementation for the default type.
    101  *
    102  * <li>To provide a specific keystore type:
    103  * <pre>
    104  *      KeyStore ks = KeyStore.getInstance("JKS");
    105  * </pre>
    106  * The system will return the most preferred implementation of the
    107  * specified keystore type available in the environment. <p>
    108  * </ul>
    109  *
    110  * <p> Before a keystore can be accessed, it must be
    111  * {@link #load(java.io.InputStream, char[]) loaded}.
    112  * <pre>
    113  *    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    114  *
    115  *    // get user password and file input stream
    116  *    char[] password = getPassword();
    117  *
    118  *    try (FileInputStream fis = new FileInputStream("keyStoreName")) {
    119  *        ks.load(fis, password);
    120  *    }
    121  * </pre>
    122  *
    123  * To create an empty keystore using the above {@code load} method,
    124  * pass {@code null} as the {@code InputStream} argument.
    125  *
    126  * <p> Once the keystore has been loaded, it is possible
    127  * to read existing entries from the keystore, or to write new entries
    128  * into the keystore:
    129  * <pre>
    130  *    KeyStore.ProtectionParameter protParam =
    131  *        new KeyStore.PasswordProtection(password);
    132  *
    133  *    // get my private key
    134  *    KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
    135  *        ks.getEntry("privateKeyAlias", protParam);
    136  *    PrivateKey myPrivateKey = pkEntry.getPrivateKey();
    137  *
    138  *    // save my secret key
    139  *    javax.crypto.SecretKey mySecretKey;
    140  *    KeyStore.SecretKeyEntry skEntry =
    141  *        new KeyStore.SecretKeyEntry(mySecretKey);
    142  *    ks.setEntry("secretKeyAlias", skEntry, protParam);
    143  *
    144  *    // store away the keystore
    145  *    try (FileOutputStream fos = new FileOutputStream("newKeyStoreName")) {
    146  *        ks.store(fos, password);
    147  *    }
    148  * </pre>
    149  *
    150  * Note that although the same password may be used to
    151  * load the keystore, to protect the private key entry,
    152  * to protect the secret key entry, and to store the keystore
    153  * (as is shown in the sample code above),
    154  * different passwords or other protection parameters
    155  * may also be used.
    156  *
    157  * <p> Android provides the following <code>KeyStore</code> types:
    158  * <table>
    159  *   <thead>
    160  *     <tr>
    161  *       <th>Algorithm</th>
    162  *       <th>Supported API Levels</th>
    163  *     </tr>
    164  *   </thead>
    165  *   <tbody>
    166  *     <tr>
    167  *       <td>AndroidCAStore</td>
    168  *       <td>14+</td>
    169  *     </tr>
    170  *     <tr>
    171  *       <td>AndroidKeyStore</td>
    172  *       <td>18+</td>
    173  *     </tr>
    174  *     <tr class="deprecated">
    175  *       <td>BCPKCS12</td>
    176  *       <td>1-8</td>
    177  *     </tr>
    178  *     <tr>
    179  *       <td>BKS</td>
    180  *       <td>1+</td>
    181  *     </tr>
    182  *     <tr>
    183  *       <td>BouncyCastle</td>
    184  *       <td>1+</td>
    185  *     </tr>
    186  *     <tr>
    187  *       <td>PKCS12</td>
    188  *       <td>1+</td>
    189  *     </tr>
    190  *     <tr class="deprecated">
    191  *       <td>PKCS12-DEF</td>
    192  *       <td>1-8</td>
    193  *     </tr>
    194  *   </tbody>
    195  * </table>
    196  *
    197  * These types are described in the <a href=
    198  * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyStore">
    199  * KeyStore section</a> of the
    200  * Java Cryptography Architecture Standard Algorithm Name Documentation.
    201  *
    202  * @author Jan Luehe
    203  *
    204  * @see java.security.PrivateKey
    205  * @see javax.crypto.SecretKey
    206  * @see java.security.cert.Certificate
    207  *
    208  * @since 1.2
    209  */
    210 
    211 public class KeyStore {
    212 
    213     // BEGIN Android-removed: this debugging mechanism is not supported in Android.
    214     /*
    215     private static final Debug pdebug =
    216                         Debug.getInstance("provider", "Provider");
    217     private static final boolean skipDebug =
    218         Debug.isOn("engine=") && !Debug.isOn("keystore");
    219     */
    220     // END Android-removed: this debugging mechanism is not supported in Android.
    221 
    222     /*
    223      * Constant to lookup in the Security properties file to determine
    224      * the default keystore type.
    225      * In the Security properties file, the default keystore type is given as:
    226      * <pre>
    227      * keystore.type=jks
    228      * </pre>
    229      */
    230     private static final String KEYSTORE_TYPE = "keystore.type";
    231 
    232     // The keystore type
    233     private String type;
    234 
    235     // The provider
    236     private Provider provider;
    237 
    238     // The provider implementation
    239     private KeyStoreSpi keyStoreSpi;
    240 
    241     // Has this keystore been initialized (loaded)?
    242     private boolean initialized = false;
    243 
    244     /**
    245      * A marker interface for {@code KeyStore}
    246      * {@link #load(KeyStore.LoadStoreParameter) load}
    247      * and
    248      * {@link #store(KeyStore.LoadStoreParameter) store}
    249      * parameters.
    250      *
    251      * @since 1.5
    252      */
    253     public static interface LoadStoreParameter {
    254         /**
    255          * Gets the parameter used to protect keystore data.
    256          *
    257          * @return the parameter used to protect keystore data, or null
    258          */
    259         public ProtectionParameter getProtectionParameter();
    260     }
    261 
    262     /**
    263      * A marker interface for keystore protection parameters.
    264      *
    265      * <p> The information stored in a {@code ProtectionParameter}
    266      * object protects the contents of a keystore.
    267      * For example, protection parameters may be used to check
    268      * the integrity of keystore data, or to protect the
    269      * confidentiality of sensitive keystore data
    270      * (such as a {@code PrivateKey}).
    271      *
    272      * @since 1.5
    273      */
    274     public static interface ProtectionParameter { }
    275 
    276     /**
    277      * A password-based implementation of {@code ProtectionParameter}.
    278      *
    279      * @since 1.5
    280      */
    281     public static class PasswordProtection implements
    282                 ProtectionParameter, javax.security.auth.Destroyable {
    283 
    284         private final char[] password;
    285         private final String protectionAlgorithm;
    286         private final AlgorithmParameterSpec protectionParameters;
    287         private volatile boolean destroyed = false;
    288 
    289         /**
    290          * Creates a password parameter.
    291          *
    292          * <p> The specified {@code password} is cloned before it is stored
    293          * in the new {@code PasswordProtection} object.
    294          *
    295          * @param password the password, which may be {@code null}
    296          */
    297         public PasswordProtection(char[] password) {
    298             this.password = (password == null) ? null : password.clone();
    299             this.protectionAlgorithm = null;
    300             this.protectionParameters = null;
    301         }
    302 
    303         /**
    304          * Creates a password parameter and specifies the protection algorithm
    305          * and associated parameters to use when encrypting a keystore entry.
    306          * <p>
    307          * The specified {@code password} is cloned before it is stored in the
    308          * new {@code PasswordProtection} object.
    309          *
    310          * @param password the password, which may be {@code null}
    311          * @param protectionAlgorithm the encryption algorithm name, for
    312          *     example, {@code PBEWithHmacSHA256AndAES_256}.
    313          *     See the Cipher section in the <a href=
    314          * "{@docRoot}/openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#Cipher">
    315          * Java Cryptography Architecture Standard Algorithm Name
    316          * Documentation</a>
    317          *     for information about standard encryption algorithm names.
    318          * @param protectionParameters the encryption algorithm parameter
    319          *     specification, which may be {@code null}
    320          * @exception NullPointerException if {@code protectionAlgorithm} is
    321          *     {@code null}
    322          *
    323          * @since 1.8
    324          */
    325         public PasswordProtection(char[] password, String protectionAlgorithm,
    326             AlgorithmParameterSpec protectionParameters) {
    327             if (protectionAlgorithm == null) {
    328                 throw new NullPointerException("invalid null input");
    329             }
    330             this.password = (password == null) ? null : password.clone();
    331             this.protectionAlgorithm = protectionAlgorithm;
    332             this.protectionParameters = protectionParameters;
    333         }
    334 
    335         /**
    336          * Gets the name of the protection algorithm.
    337          * If none was set then the keystore provider will use its default
    338          * protection algorithm. The name of the default protection algorithm
    339          * for a given keystore type is set using the
    340          * {@code 'keystore.<type>.keyProtectionAlgorithm'} security property.
    341          * For example, the
    342          * {@code keystore.PKCS12.keyProtectionAlgorithm} property stores the
    343          * name of the default key protection algorithm used for PKCS12
    344          * keystores. If the security property is not set, an
    345          * implementation-specific algorithm will be used.
    346          *
    347          * @return the algorithm name, or {@code null} if none was set
    348          *
    349          * @since 1.8
    350          */
    351         public String getProtectionAlgorithm() {
    352             return protectionAlgorithm;
    353         }
    354 
    355         /**
    356          * Gets the parameters supplied for the protection algorithm.
    357          *
    358          * @return the algorithm parameter specification, or {@code  null},
    359          *     if none was set
    360          *
    361          * @since 1.8
    362          */
    363         public AlgorithmParameterSpec getProtectionParameters() {
    364             return protectionParameters;
    365         }
    366 
    367         /**
    368          * Gets the password.
    369          *
    370          * <p>Note that this method returns a reference to the password.
    371          * If a clone of the array is created it is the caller's
    372          * responsibility to zero out the password information
    373          * after it is no longer needed.
    374          *
    375          * @see #destroy()
    376          * @return the password, which may be {@code null}
    377          * @exception IllegalStateException if the password has
    378          *              been cleared (destroyed)
    379          */
    380         public synchronized char[] getPassword() {
    381             if (destroyed) {
    382                 throw new IllegalStateException("password has been cleared");
    383             }
    384             return password;
    385         }
    386 
    387         /**
    388          * Clears the password.
    389          *
    390          * @exception DestroyFailedException if this method was unable
    391          *      to clear the password
    392          */
    393         public synchronized void destroy() throws DestroyFailedException {
    394             destroyed = true;
    395             if (password != null) {
    396                 Arrays.fill(password, ' ');
    397             }
    398         }
    399 
    400         /**
    401          * Determines if password has been cleared.
    402          *
    403          * @return true if the password has been cleared, false otherwise
    404          */
    405         public synchronized boolean isDestroyed() {
    406             return destroyed;
    407         }
    408     }
    409 
    410     /**
    411      * A ProtectionParameter encapsulating a CallbackHandler.
    412      *
    413      * @since 1.5
    414      */
    415     public static class CallbackHandlerProtection
    416             implements ProtectionParameter {
    417 
    418         private final CallbackHandler handler;
    419 
    420         /**
    421          * Constructs a new CallbackHandlerProtection from a
    422          * CallbackHandler.
    423          *
    424          * @param handler the CallbackHandler
    425          * @exception NullPointerException if handler is null
    426          */
    427         public CallbackHandlerProtection(CallbackHandler handler) {
    428             if (handler == null) {
    429                 throw new NullPointerException("handler must not be null");
    430             }
    431             this.handler = handler;
    432         }
    433 
    434         /**
    435          * Returns the CallbackHandler.
    436          *
    437          * @return the CallbackHandler.
    438          */
    439         public CallbackHandler getCallbackHandler() {
    440             return handler;
    441         }
    442 
    443     }
    444 
    445     /**
    446      * A marker interface for {@code KeyStore} entry types.
    447      *
    448      * @since 1.5
    449      */
    450     public static interface Entry {
    451 
    452         /**
    453          * Retrieves the attributes associated with an entry.
    454          * <p>
    455          * The default implementation returns an empty {@code Set}.
    456          *
    457          * @return an unmodifiable {@code Set} of attributes, possibly empty
    458          *
    459          * @since 1.8
    460          */
    461         public default Set<Attribute> getAttributes() {
    462             return Collections.<Attribute>emptySet();
    463         }
    464 
    465         /**
    466          * An attribute associated with a keystore entry.
    467          * It comprises a name and one or more values.
    468          *
    469          * @since 1.8
    470          */
    471         public interface Attribute {
    472             /**
    473              * Returns the attribute's name.
    474              *
    475              * @return the attribute name
    476              */
    477             public String getName();
    478 
    479             /**
    480              * Returns the attribute's value.
    481              * Multi-valued attributes encode their values as a single string.
    482              *
    483              * @return the attribute value
    484              */
    485             public String getValue();
    486         }
    487     }
    488 
    489     /**
    490      * A {@code KeyStore} entry that holds a {@code PrivateKey}
    491      * and corresponding certificate chain.
    492      *
    493      * @since 1.5
    494      */
    495     public static final class PrivateKeyEntry implements Entry {
    496 
    497         private final PrivateKey privKey;
    498         private final Certificate[] chain;
    499         private final Set<Attribute> attributes;
    500 
    501         /**
    502          * Constructs a {@code PrivateKeyEntry} with a
    503          * {@code PrivateKey} and corresponding certificate chain.
    504          *
    505          * <p> The specified {@code chain} is cloned before it is stored
    506          * in the new {@code PrivateKeyEntry} object.
    507          *
    508          * @param privateKey the {@code PrivateKey}
    509          * @param chain an array of {@code Certificate}s
    510          *      representing the certificate chain.
    511          *      The chain must be ordered and contain a
    512          *      {@code Certificate} at index 0
    513          *      corresponding to the private key.
    514          *
    515          * @exception NullPointerException if
    516          *      {@code privateKey} or {@code chain}
    517          *      is {@code null}
    518          * @exception IllegalArgumentException if the specified chain has a
    519          *      length of 0, if the specified chain does not contain
    520          *      {@code Certificate}s of the same type,
    521          *      or if the {@code PrivateKey} algorithm
    522          *      does not match the algorithm of the {@code PublicKey}
    523          *      in the end entity {@code Certificate} (at index 0)
    524          */
    525         public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) {
    526             this(privateKey, chain, Collections.<Attribute>emptySet());
    527         }
    528 
    529         /**
    530          * Constructs a {@code PrivateKeyEntry} with a {@code PrivateKey} and
    531          * corresponding certificate chain and associated entry attributes.
    532          *
    533          * <p> The specified {@code chain} and {@code attributes} are cloned
    534          * before they are stored in the new {@code PrivateKeyEntry} object.
    535          *
    536          * @param privateKey the {@code PrivateKey}
    537          * @param chain an array of {@code Certificate}s
    538          *      representing the certificate chain.
    539          *      The chain must be ordered and contain a
    540          *      {@code Certificate} at index 0
    541          *      corresponding to the private key.
    542          * @param attributes the attributes
    543          *
    544          * @exception NullPointerException if {@code privateKey}, {@code chain}
    545          *      or {@code attributes} is {@code null}
    546          * @exception IllegalArgumentException if the specified chain has a
    547          *      length of 0, if the specified chain does not contain
    548          *      {@code Certificate}s of the same type,
    549          *      or if the {@code PrivateKey} algorithm
    550          *      does not match the algorithm of the {@code PublicKey}
    551          *      in the end entity {@code Certificate} (at index 0)
    552          *
    553          * @since 1.8
    554          */
    555         public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain,
    556            Set<Attribute> attributes) {
    557 
    558             if (privateKey == null || chain == null || attributes == null) {
    559                 throw new NullPointerException("invalid null input");
    560             }
    561             if (chain.length == 0) {
    562                 throw new IllegalArgumentException
    563                                 ("invalid zero-length input chain");
    564             }
    565 
    566             Certificate[] clonedChain = chain.clone();
    567             String certType = clonedChain[0].getType();
    568             for (int i = 1; i < clonedChain.length; i++) {
    569                 if (!certType.equals(clonedChain[i].getType())) {
    570                     throw new IllegalArgumentException
    571                                 ("chain does not contain certificates " +
    572                                 "of the same type");
    573                 }
    574             }
    575             if (!privateKey.getAlgorithm().equals
    576                         (clonedChain[0].getPublicKey().getAlgorithm())) {
    577                 throw new IllegalArgumentException
    578                                 ("private key algorithm does not match " +
    579                                 "algorithm of public key in end entity " +
    580                                 "certificate (at index 0)");
    581             }
    582             this.privKey = privateKey;
    583 
    584             if (clonedChain[0] instanceof X509Certificate &&
    585                 !(clonedChain instanceof X509Certificate[])) {
    586 
    587                 this.chain = new X509Certificate[clonedChain.length];
    588                 System.arraycopy(clonedChain, 0,
    589                                 this.chain, 0, clonedChain.length);
    590             } else {
    591                 this.chain = clonedChain;
    592             }
    593 
    594             this.attributes =
    595                 Collections.unmodifiableSet(new HashSet<>(attributes));
    596         }
    597 
    598         /**
    599          * Gets the {@code PrivateKey} from this entry.
    600          *
    601          * @return the {@code PrivateKey} from this entry
    602          */
    603         public PrivateKey getPrivateKey() {
    604             return privKey;
    605         }
    606 
    607         /**
    608          * Gets the {@code Certificate} chain from this entry.
    609          *
    610          * <p> The stored chain is cloned before being returned.
    611          *
    612          * @return an array of {@code Certificate}s corresponding
    613          *      to the certificate chain for the public key.
    614          *      If the certificates are of type X.509,
    615          *      the runtime type of the returned array is
    616          *      {@code X509Certificate[]}.
    617          */
    618         public Certificate[] getCertificateChain() {
    619             return chain.clone();
    620         }
    621 
    622         /**
    623          * Gets the end entity {@code Certificate}
    624          * from the certificate chain in this entry.
    625          *
    626          * @return the end entity {@code Certificate} (at index 0)
    627          *      from the certificate chain in this entry.
    628          *      If the certificate is of type X.509,
    629          *      the runtime type of the returned certificate is
    630          *      {@code X509Certificate}.
    631          */
    632         public Certificate getCertificate() {
    633             return chain[0];
    634         }
    635 
    636         /**
    637          * Retrieves the attributes associated with an entry.
    638          * <p>
    639          *
    640          * @return an unmodifiable {@code Set} of attributes, possibly empty
    641          *
    642          * @since 1.8
    643          */
    644         @Override
    645         public Set<Attribute> getAttributes() {
    646             return attributes;
    647         }
    648 
    649         /**
    650          * Returns a string representation of this PrivateKeyEntry.
    651          * @return a string representation of this PrivateKeyEntry.
    652          */
    653         public String toString() {
    654             StringBuilder sb = new StringBuilder();
    655             sb.append("Private key entry and certificate chain with "
    656                 + chain.length + " elements:\r\n");
    657             for (Certificate cert : chain) {
    658                 sb.append(cert);
    659                 sb.append("\r\n");
    660             }
    661             return sb.toString();
    662         }
    663 
    664     }
    665 
    666     /**
    667      * A {@code KeyStore} entry that holds a {@code SecretKey}.
    668      *
    669      * @since 1.5
    670      */
    671     public static final class SecretKeyEntry implements Entry {
    672 
    673         private final SecretKey sKey;
    674         private final Set<Attribute> attributes;
    675 
    676         /**
    677          * Constructs a {@code SecretKeyEntry} with a
    678          * {@code SecretKey}.
    679          *
    680          * @param secretKey the {@code SecretKey}
    681          *
    682          * @exception NullPointerException if {@code secretKey}
    683          *      is {@code null}
    684          */
    685         public SecretKeyEntry(SecretKey secretKey) {
    686             if (secretKey == null) {
    687                 throw new NullPointerException("invalid null input");
    688             }
    689             this.sKey = secretKey;
    690             this.attributes = Collections.<Attribute>emptySet();
    691         }
    692 
    693         /**
    694          * Constructs a {@code SecretKeyEntry} with a {@code SecretKey} and
    695          * associated entry attributes.
    696          *
    697          * <p> The specified {@code attributes} is cloned before it is stored
    698          * in the new {@code SecretKeyEntry} object.
    699          *
    700          * @param secretKey the {@code SecretKey}
    701          * @param attributes the attributes
    702          *
    703          * @exception NullPointerException if {@code secretKey} or
    704          *     {@code attributes} is {@code null}
    705          *
    706          * @since 1.8
    707          */
    708         public SecretKeyEntry(SecretKey secretKey, Set<Attribute> attributes) {
    709 
    710             if (secretKey == null || attributes == null) {
    711                 throw new NullPointerException("invalid null input");
    712             }
    713             this.sKey = secretKey;
    714             this.attributes =
    715                 Collections.unmodifiableSet(new HashSet<>(attributes));
    716         }
    717 
    718         /**
    719          * Gets the {@code SecretKey} from this entry.
    720          *
    721          * @return the {@code SecretKey} from this entry
    722          */
    723         public SecretKey getSecretKey() {
    724             return sKey;
    725         }
    726 
    727         /**
    728          * Retrieves the attributes associated with an entry.
    729          * <p>
    730          *
    731          * @return an unmodifiable {@code Set} of attributes, possibly empty
    732          *
    733          * @since 1.8
    734          */
    735         @Override
    736         public Set<Attribute> getAttributes() {
    737             return attributes;
    738         }
    739 
    740         /**
    741          * Returns a string representation of this SecretKeyEntry.
    742          * @return a string representation of this SecretKeyEntry.
    743          */
    744         public String toString() {
    745             return "Secret key entry with algorithm " + sKey.getAlgorithm();
    746         }
    747     }
    748 
    749     /**
    750      * A {@code KeyStore} entry that holds a trusted
    751      * {@code Certificate}.
    752      *
    753      * @since 1.5
    754      */
    755     public static final class TrustedCertificateEntry implements Entry {
    756 
    757         private final Certificate cert;
    758         private final Set<Attribute> attributes;
    759 
    760         /**
    761          * Constructs a {@code TrustedCertificateEntry} with a
    762          * trusted {@code Certificate}.
    763          *
    764          * @param trustedCert the trusted {@code Certificate}
    765          *
    766          * @exception NullPointerException if
    767          *      {@code trustedCert} is {@code null}
    768          */
    769         public TrustedCertificateEntry(Certificate trustedCert) {
    770             if (trustedCert == null) {
    771                 throw new NullPointerException("invalid null input");
    772             }
    773             this.cert = trustedCert;
    774             this.attributes = Collections.<Attribute>emptySet();
    775         }
    776 
    777         /**
    778          * Constructs a {@code TrustedCertificateEntry} with a
    779          * trusted {@code Certificate} and associated entry attributes.
    780          *
    781          * <p> The specified {@code attributes} is cloned before it is stored
    782          * in the new {@code TrustedCertificateEntry} object.
    783          *
    784          * @param trustedCert the trusted {@code Certificate}
    785          * @param attributes the attributes
    786          *
    787          * @exception NullPointerException if {@code trustedCert} or
    788          *     {@code attributes} is {@code null}
    789          *
    790          * @since 1.8
    791          */
    792         public TrustedCertificateEntry(Certificate trustedCert,
    793            Set<Attribute> attributes) {
    794             if (trustedCert == null || attributes == null) {
    795                 throw new NullPointerException("invalid null input");
    796             }
    797             this.cert = trustedCert;
    798             this.attributes =
    799                 Collections.unmodifiableSet(new HashSet<>(attributes));
    800         }
    801 
    802         /**
    803          * Gets the trusted {@code Certficate} from this entry.
    804          *
    805          * @return the trusted {@code Certificate} from this entry
    806          */
    807         public Certificate getTrustedCertificate() {
    808             return cert;
    809         }
    810 
    811         /**
    812          * Retrieves the attributes associated with an entry.
    813          * <p>
    814          *
    815          * @return an unmodifiable {@code Set} of attributes, possibly empty
    816          *
    817          * @since 1.8
    818          */
    819         @Override
    820         public Set<Attribute> getAttributes() {
    821             return attributes;
    822         }
    823 
    824         /**
    825          * Returns a string representation of this TrustedCertificateEntry.
    826          * @return a string representation of this TrustedCertificateEntry.
    827          */
    828         public String toString() {
    829             return "Trusted certificate entry:\r\n" + cert.toString();
    830         }
    831     }
    832 
    833     /**
    834      * Creates a KeyStore object of the given type, and encapsulates the given
    835      * provider implementation (SPI object) in it.
    836      *
    837      * @param keyStoreSpi the provider implementation.
    838      * @param provider the provider.
    839      * @param type the keystore type.
    840      */
    841     protected KeyStore(KeyStoreSpi keyStoreSpi, Provider provider, String type)
    842     {
    843         this.keyStoreSpi = keyStoreSpi;
    844         this.provider = provider;
    845         this.type = type;
    846 
    847         // BEGIN Android-removed: this debugging mechanism is not supported in Android.
    848         /*
    849         if (!skipDebug && pdebug != null) {
    850             pdebug.println("KeyStore." + type.toUpperCase() + " type from: " +
    851                 this.provider.getName());
    852         }
    853         */
    854         // END Android-removed: this debugging mechanism is not supported in Android.
    855     }
    856 
    857     /**
    858      * Returns a keystore object of the specified type.
    859      *
    860      * <p> This method traverses the list of registered security Providers,
    861      * starting with the most preferred Provider.
    862      * A new KeyStore object encapsulating the
    863      * KeyStoreSpi implementation from the first
    864      * Provider that supports the specified type is returned.
    865      *
    866      * <p> Note that the list of registered providers may be retrieved via
    867      * the {@link Security#getProviders() Security.getProviders()} method.
    868      *
    869      * @param type the type of keystore.
    870      * See the KeyStore section in the <a href=
    871      * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyStore">
    872      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
    873      * for information about standard keystore types.
    874      *
    875      * @return a keystore object of the specified type.
    876      *
    877      * @exception KeyStoreException if no Provider supports a
    878      *          KeyStoreSpi implementation for the
    879      *          specified type.
    880      *
    881      * @see Provider
    882      */
    883     public static KeyStore getInstance(String type)
    884         throws KeyStoreException
    885     {
    886         try {
    887             Object[] objs = Security.getImpl(type, "KeyStore", (String)null);
    888             return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type);
    889         } catch (NoSuchAlgorithmException nsae) {
    890             throw new KeyStoreException(type + " not found", nsae);
    891         } catch (NoSuchProviderException nspe) {
    892             throw new KeyStoreException(type + " not found", nspe);
    893         }
    894     }
    895 
    896     /**
    897      * Returns a keystore object of the specified type.
    898      *
    899      * <p> A new KeyStore object encapsulating the
    900      * KeyStoreSpi implementation from the specified provider
    901      * is returned.  The specified provider must be registered
    902      * in the security provider list.
    903      *
    904      * <p> Note that the list of registered providers may be retrieved via
    905      * the {@link Security#getProviders() Security.getProviders()} method.
    906      *
    907      * @param type the type of keystore.
    908      * See the KeyStore section in the <a href=
    909      * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyStore">
    910      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
    911      * for information about standard keystore types.
    912      *
    913      * @param provider the name of the provider.
    914      *
    915      * @return a keystore object of the specified type.
    916      *
    917      * @exception KeyStoreException if a KeyStoreSpi
    918      *          implementation for the specified type is not
    919      *          available from the specified provider.
    920      *
    921      * @exception NoSuchProviderException if the specified provider is not
    922      *          registered in the security provider list.
    923      *
    924      * @exception IllegalArgumentException if the provider name is null
    925      *          or empty.
    926      *
    927      * @see Provider
    928      */
    929     public static KeyStore getInstance(String type, String provider)
    930         throws KeyStoreException, NoSuchProviderException
    931     {
    932         if (provider == null || provider.length() == 0)
    933             throw new IllegalArgumentException("missing provider");
    934         try {
    935             Object[] objs = Security.getImpl(type, "KeyStore", provider);
    936             return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type);
    937         } catch (NoSuchAlgorithmException nsae) {
    938             throw new KeyStoreException(type + " not found", nsae);
    939         }
    940     }
    941 
    942     /**
    943      * Returns a keystore object of the specified type.
    944      *
    945      * <p> A new KeyStore object encapsulating the
    946      * KeyStoreSpi implementation from the specified Provider
    947      * object is returned.  Note that the specified Provider object
    948      * does not have to be registered in the provider list.
    949      *
    950      * @param type the type of keystore.
    951      * See the KeyStore section in the <a href=
    952      * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyStore">
    953      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
    954      * for information about standard keystore types.
    955      *
    956      * @param provider the provider.
    957      *
    958      * @return a keystore object of the specified type.
    959      *
    960      * @exception KeyStoreException if KeyStoreSpi
    961      *          implementation for the specified type is not available
    962      *          from the specified Provider object.
    963      *
    964      * @exception IllegalArgumentException if the specified provider is null.
    965      *
    966      * @see Provider
    967      *
    968      * @since 1.4
    969      */
    970     public static KeyStore getInstance(String type, Provider provider)
    971         throws KeyStoreException
    972     {
    973         if (provider == null)
    974             throw new IllegalArgumentException("missing provider");
    975         try {
    976             Object[] objs = Security.getImpl(type, "KeyStore", provider);
    977             return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type);
    978         } catch (NoSuchAlgorithmException nsae) {
    979             throw new KeyStoreException(type + " not found", nsae);
    980         }
    981     }
    982 
    983     /**
    984      * Returns the default keystore type as specified by the
    985      * {@code keystore.type} security property, or the string
    986      * {@literal "jks"} (acronym for {@literal "Java keystore"})
    987      * if no such property exists.
    988      *
    989      * <p>The default keystore type can be used by applications that do not
    990      * want to use a hard-coded keystore type when calling one of the
    991      * {@code getInstance} methods, and want to provide a default keystore
    992      * type in case a user does not specify its own.
    993      *
    994      * <p>The default keystore type can be changed by setting the value of the
    995      * {@code keystore.type} security property to the desired keystore type.
    996      *
    997      * @return the default keystore type as specified by the
    998      * {@code keystore.type} security property, or the string {@literal "jks"}
    999      * if no such property exists.
   1000      * @see java.security.Security security properties
   1001      */
   1002     public final static String getDefaultType() {
   1003         String kstype;
   1004         kstype = AccessController.doPrivileged(new PrivilegedAction<String>() {
   1005             public String run() {
   1006                 return Security.getProperty(KEYSTORE_TYPE);
   1007             }
   1008         });
   1009         if (kstype == null) {
   1010             kstype = "jks";
   1011         }
   1012         return kstype;
   1013     }
   1014 
   1015     /**
   1016      * Returns the provider of this keystore.
   1017      *
   1018      * @return the provider of this keystore.
   1019      */
   1020     public final Provider getProvider()
   1021     {
   1022         return this.provider;
   1023     }
   1024 
   1025     /**
   1026      * Returns the type of this keystore.
   1027      *
   1028      * @return the type of this keystore.
   1029      */
   1030     public final String getType()
   1031     {
   1032         return this.type;
   1033     }
   1034 
   1035     /**
   1036      * Returns the key associated with the given alias, using the given
   1037      * password to recover it.  The key must have been associated with
   1038      * the alias by a call to {@code setKeyEntry},
   1039      * or by a call to {@code setEntry} with a
   1040      * {@code PrivateKeyEntry} or {@code SecretKeyEntry}.
   1041      *
   1042      * @param alias the alias name
   1043      * @param password the password for recovering the key
   1044      *
   1045      * @return the requested key, or null if the given alias does not exist
   1046      * or does not identify a key-related entry.
   1047      *
   1048      * @exception KeyStoreException if the keystore has not been initialized
   1049      * (loaded).
   1050      * @exception NoSuchAlgorithmException if the algorithm for recovering the
   1051      * key cannot be found
   1052      * @exception UnrecoverableKeyException if the key cannot be recovered
   1053      * (e.g., the given password is wrong).
   1054      */
   1055     public final Key getKey(String alias, char[] password)
   1056         throws KeyStoreException, NoSuchAlgorithmException,
   1057             UnrecoverableKeyException
   1058     {
   1059         if (!initialized) {
   1060             throw new KeyStoreException("Uninitialized keystore");
   1061         }
   1062         return keyStoreSpi.engineGetKey(alias, password);
   1063     }
   1064 
   1065     /**
   1066      * Returns the certificate chain associated with the given alias.
   1067      * The certificate chain must have been associated with the alias
   1068      * by a call to {@code setKeyEntry},
   1069      * or by a call to {@code setEntry} with a
   1070      * {@code PrivateKeyEntry}.
   1071      *
   1072      * @param alias the alias name
   1073      *
   1074      * @return the certificate chain (ordered with the user's certificate first
   1075      * followed by zero or more certificate authorities), or null if the given alias
   1076      * does not exist or does not contain a certificate chain
   1077      *
   1078      * @exception KeyStoreException if the keystore has not been initialized
   1079      * (loaded).
   1080      */
   1081     public final Certificate[] getCertificateChain(String alias)
   1082         throws KeyStoreException
   1083     {
   1084         if (!initialized) {
   1085             throw new KeyStoreException("Uninitialized keystore");
   1086         }
   1087         return keyStoreSpi.engineGetCertificateChain(alias);
   1088     }
   1089 
   1090     /**
   1091      * Returns the certificate associated with the given alias.
   1092      *
   1093      * <p> If the given alias name identifies an entry
   1094      * created by a call to {@code setCertificateEntry},
   1095      * or created by a call to {@code setEntry} with a
   1096      * {@code TrustedCertificateEntry},
   1097      * then the trusted certificate contained in that entry is returned.
   1098      *
   1099      * <p> If the given alias name identifies an entry
   1100      * created by a call to {@code setKeyEntry},
   1101      * or created by a call to {@code setEntry} with a
   1102      * {@code PrivateKeyEntry},
   1103      * then the first element of the certificate chain in that entry
   1104      * is returned.
   1105      *
   1106      * @param alias the alias name
   1107      *
   1108      * @return the certificate, or null if the given alias does not exist or
   1109      * does not contain a certificate.
   1110      *
   1111      * @exception KeyStoreException if the keystore has not been initialized
   1112      * (loaded).
   1113      */
   1114     public final Certificate getCertificate(String alias)
   1115         throws KeyStoreException
   1116     {
   1117         if (!initialized) {
   1118             throw new KeyStoreException("Uninitialized keystore");
   1119         }
   1120         return keyStoreSpi.engineGetCertificate(alias);
   1121     }
   1122 
   1123     /**
   1124      * Returns the creation date of the entry identified by the given alias.
   1125      *
   1126      * @param alias the alias name
   1127      *
   1128      * @return the creation date of this entry, or null if the given alias does
   1129      * not exist
   1130      *
   1131      * @exception KeyStoreException if the keystore has not been initialized
   1132      * (loaded).
   1133      */
   1134     public final Date getCreationDate(String alias)
   1135         throws KeyStoreException
   1136     {
   1137         if (!initialized) {
   1138             throw new KeyStoreException("Uninitialized keystore");
   1139         }
   1140         return keyStoreSpi.engineGetCreationDate(alias);
   1141     }
   1142 
   1143     /**
   1144      * Assigns the given key to the given alias, protecting it with the given
   1145      * password.
   1146      *
   1147      * <p>If the given key is of type {@code java.security.PrivateKey},
   1148      * it must be accompanied by a certificate chain certifying the
   1149      * corresponding public key.
   1150      *
   1151      * <p>If the given alias already exists, the keystore information
   1152      * associated with it is overridden by the given key (and possibly
   1153      * certificate chain).
   1154      *
   1155      * @param alias the alias name
   1156      * @param key the key to be associated with the alias
   1157      * @param password the password to protect the key
   1158      * @param chain the certificate chain for the corresponding public
   1159      * key (only required if the given key is of type
   1160      * {@code java.security.PrivateKey}).
   1161      *
   1162      * @exception KeyStoreException if the keystore has not been initialized
   1163      * (loaded), the given key cannot be protected, or this operation fails
   1164      * for some other reason
   1165      */
   1166     public final void setKeyEntry(String alias, Key key, char[] password,
   1167                                   Certificate[] chain)
   1168         throws KeyStoreException
   1169     {
   1170         if (!initialized) {
   1171             throw new KeyStoreException("Uninitialized keystore");
   1172         }
   1173         if ((key instanceof PrivateKey) &&
   1174             (chain == null || chain.length == 0)) {
   1175             throw new IllegalArgumentException("Private key must be "
   1176                                                + "accompanied by certificate "
   1177                                                + "chain");
   1178         }
   1179         keyStoreSpi.engineSetKeyEntry(alias, key, password, chain);
   1180     }
   1181 
   1182     /**
   1183      * Assigns the given key (that has already been protected) to the given
   1184      * alias.
   1185      *
   1186      * <p>If the protected key is of type
   1187      * {@code java.security.PrivateKey}, it must be accompanied by a
   1188      * certificate chain certifying the corresponding public key. If the
   1189      * underlying keystore implementation is of type {@code jks},
   1190      * {@code key} must be encoded as an
   1191      * {@code EncryptedPrivateKeyInfo} as defined in the PKCS #8 standard.
   1192      *
   1193      * <p>If the given alias already exists, the keystore information
   1194      * associated with it is overridden by the given key (and possibly
   1195      * certificate chain).
   1196      *
   1197      * @param alias the alias name
   1198      * @param key the key (in protected format) to be associated with the alias
   1199      * @param chain the certificate chain for the corresponding public
   1200      *          key (only useful if the protected key is of type
   1201      *          {@code java.security.PrivateKey}).
   1202      *
   1203      * @exception KeyStoreException if the keystore has not been initialized
   1204      * (loaded), or if this operation fails for some other reason.
   1205      */
   1206     public final void setKeyEntry(String alias, byte[] key,
   1207                                   Certificate[] chain)
   1208         throws KeyStoreException
   1209     {
   1210         if (!initialized) {
   1211             throw new KeyStoreException("Uninitialized keystore");
   1212         }
   1213         keyStoreSpi.engineSetKeyEntry(alias, key, chain);
   1214     }
   1215 
   1216     /**
   1217      * Assigns the given trusted certificate to the given alias.
   1218      *
   1219      * <p> If the given alias identifies an existing entry
   1220      * created by a call to {@code setCertificateEntry},
   1221      * or created by a call to {@code setEntry} with a
   1222      * {@code TrustedCertificateEntry},
   1223      * the trusted certificate in the existing entry
   1224      * is overridden by the given certificate.
   1225      *
   1226      * @param alias the alias name
   1227      * @param cert the certificate
   1228      *
   1229      * @exception KeyStoreException if the keystore has not been initialized,
   1230      * or the given alias already exists and does not identify an
   1231      * entry containing a trusted certificate,
   1232      * or this operation fails for some other reason.
   1233      */
   1234     public final void setCertificateEntry(String alias, Certificate cert)
   1235         throws KeyStoreException
   1236     {
   1237         if (!initialized) {
   1238             throw new KeyStoreException("Uninitialized keystore");
   1239         }
   1240         keyStoreSpi.engineSetCertificateEntry(alias, cert);
   1241     }
   1242 
   1243     /**
   1244      * Deletes the entry identified by the given alias from this keystore.
   1245      *
   1246      * @param alias the alias name
   1247      *
   1248      * @exception KeyStoreException if the keystore has not been initialized,
   1249      * or if the entry cannot be removed.
   1250      */
   1251     public final void deleteEntry(String alias)
   1252         throws KeyStoreException
   1253     {
   1254         if (!initialized) {
   1255             throw new KeyStoreException("Uninitialized keystore");
   1256         }
   1257         keyStoreSpi.engineDeleteEntry(alias);
   1258     }
   1259 
   1260     /**
   1261      * Lists all the alias names of this keystore.
   1262      *
   1263      * @return enumeration of the alias names
   1264      *
   1265      * @exception KeyStoreException if the keystore has not been initialized
   1266      * (loaded).
   1267      */
   1268     public final Enumeration<String> aliases()
   1269         throws KeyStoreException
   1270     {
   1271         if (!initialized) {
   1272             throw new KeyStoreException("Uninitialized keystore");
   1273         }
   1274         return keyStoreSpi.engineAliases();
   1275     }
   1276 
   1277     /**
   1278      * Checks if the given alias exists in this keystore.
   1279      *
   1280      * @param alias the alias name
   1281      *
   1282      * @return true if the alias exists, false otherwise
   1283      *
   1284      * @exception KeyStoreException if the keystore has not been initialized
   1285      * (loaded).
   1286      */
   1287     public final boolean containsAlias(String alias)
   1288         throws KeyStoreException
   1289     {
   1290         if (!initialized) {
   1291             throw new KeyStoreException("Uninitialized keystore");
   1292         }
   1293         return keyStoreSpi.engineContainsAlias(alias);
   1294     }
   1295 
   1296     /**
   1297      * Retrieves the number of entries in this keystore.
   1298      *
   1299      * @return the number of entries in this keystore
   1300      *
   1301      * @exception KeyStoreException if the keystore has not been initialized
   1302      * (loaded).
   1303      */
   1304     public final int size()
   1305         throws KeyStoreException
   1306     {
   1307         if (!initialized) {
   1308             throw new KeyStoreException("Uninitialized keystore");
   1309         }
   1310         return keyStoreSpi.engineSize();
   1311     }
   1312 
   1313     /**
   1314      * Returns true if the entry identified by the given alias
   1315      * was created by a call to {@code setKeyEntry},
   1316      * or created by a call to {@code setEntry} with a
   1317      * {@code PrivateKeyEntry} or a {@code SecretKeyEntry}.
   1318      *
   1319      * @param alias the alias for the keystore entry to be checked
   1320      *
   1321      * @return true if the entry identified by the given alias is a
   1322      * key-related entry, false otherwise.
   1323      *
   1324      * @exception KeyStoreException if the keystore has not been initialized
   1325      * (loaded).
   1326      */
   1327     public final boolean isKeyEntry(String alias)
   1328         throws KeyStoreException
   1329     {
   1330         if (!initialized) {
   1331             throw new KeyStoreException("Uninitialized keystore");
   1332         }
   1333         return keyStoreSpi.engineIsKeyEntry(alias);
   1334     }
   1335 
   1336     /**
   1337      * Returns true if the entry identified by the given alias
   1338      * was created by a call to {@code setCertificateEntry},
   1339      * or created by a call to {@code setEntry} with a
   1340      * {@code TrustedCertificateEntry}.
   1341      *
   1342      * @param alias the alias for the keystore entry to be checked
   1343      *
   1344      * @return true if the entry identified by the given alias contains a
   1345      * trusted certificate, false otherwise.
   1346      *
   1347      * @exception KeyStoreException if the keystore has not been initialized
   1348      * (loaded).
   1349      */
   1350     public final boolean isCertificateEntry(String alias)
   1351         throws KeyStoreException
   1352     {
   1353         if (!initialized) {
   1354             throw new KeyStoreException("Uninitialized keystore");
   1355         }
   1356         return keyStoreSpi.engineIsCertificateEntry(alias);
   1357     }
   1358 
   1359     /**
   1360      * Returns the (alias) name of the first keystore entry whose certificate
   1361      * matches the given certificate.
   1362      *
   1363      * <p> This method attempts to match the given certificate with each
   1364      * keystore entry. If the entry being considered was
   1365      * created by a call to {@code setCertificateEntry},
   1366      * or created by a call to {@code setEntry} with a
   1367      * {@code TrustedCertificateEntry},
   1368      * then the given certificate is compared to that entry's certificate.
   1369      *
   1370      * <p> If the entry being considered was
   1371      * created by a call to {@code setKeyEntry},
   1372      * or created by a call to {@code setEntry} with a
   1373      * {@code PrivateKeyEntry},
   1374      * then the given certificate is compared to the first
   1375      * element of that entry's certificate chain.
   1376      *
   1377      * @param cert the certificate to match with.
   1378      *
   1379      * @return the alias name of the first entry with a matching certificate,
   1380      * or null if no such entry exists in this keystore.
   1381      *
   1382      * @exception KeyStoreException if the keystore has not been initialized
   1383      * (loaded).
   1384      */
   1385     public final String getCertificateAlias(Certificate cert)
   1386         throws KeyStoreException
   1387     {
   1388         if (!initialized) {
   1389             throw new KeyStoreException("Uninitialized keystore");
   1390         }
   1391         return keyStoreSpi.engineGetCertificateAlias(cert);
   1392     }
   1393 
   1394     /**
   1395      * Stores this keystore to the given output stream, and protects its
   1396      * integrity with the given password.
   1397      *
   1398      * @param stream the output stream to which this keystore is written.
   1399      * @param password the password to generate the keystore integrity check
   1400      *
   1401      * @exception KeyStoreException if the keystore has not been initialized
   1402      * (loaded).
   1403      * @exception IOException if there was an I/O problem with data
   1404      * @exception NoSuchAlgorithmException if the appropriate data integrity
   1405      * algorithm could not be found
   1406      * @exception CertificateException if any of the certificates included in
   1407      * the keystore data could not be stored
   1408      */
   1409     public final void store(OutputStream stream, char[] password)
   1410         throws KeyStoreException, IOException, NoSuchAlgorithmException,
   1411             CertificateException
   1412     {
   1413         if (!initialized) {
   1414             throw new KeyStoreException("Uninitialized keystore");
   1415         }
   1416         keyStoreSpi.engineStore(stream, password);
   1417     }
   1418 
   1419     /**
   1420      * Stores this keystore using the given {@code LoadStoreParameter}.
   1421      *
   1422      * @param param the {@code LoadStoreParameter}
   1423      *          that specifies how to store the keystore,
   1424      *          which may be {@code null}
   1425      *
   1426      * @exception IllegalArgumentException if the given
   1427      *          {@code LoadStoreParameter}
   1428      *          input is not recognized
   1429      * @exception KeyStoreException if the keystore has not been initialized
   1430      *          (loaded)
   1431      * @exception IOException if there was an I/O problem with data
   1432      * @exception NoSuchAlgorithmException if the appropriate data integrity
   1433      *          algorithm could not be found
   1434      * @exception CertificateException if any of the certificates included in
   1435      *          the keystore data could not be stored
   1436      *
   1437      * @since 1.5
   1438      */
   1439     public final void store(LoadStoreParameter param)
   1440                 throws KeyStoreException, IOException,
   1441                 NoSuchAlgorithmException, CertificateException {
   1442         if (!initialized) {
   1443             throw new KeyStoreException("Uninitialized keystore");
   1444         }
   1445         keyStoreSpi.engineStore(param);
   1446     }
   1447 
   1448     /**
   1449      * Loads this KeyStore from the given input stream.
   1450      *
   1451      * <p>A password may be given to unlock the keystore
   1452      * (e.g. the keystore resides on a hardware token device),
   1453      * or to check the integrity of the keystore data.
   1454      * If a password is not given for integrity checking,
   1455      * then integrity checking is not performed.
   1456      *
   1457      * <p>In order to create an empty keystore, or if the keystore cannot
   1458      * be initialized from a stream, pass {@code null}
   1459      * as the {@code stream} argument.
   1460      *
   1461      * <p> Note that if this keystore has already been loaded, it is
   1462      * reinitialized and loaded again from the given input stream.
   1463      *
   1464      * @param stream the input stream from which the keystore is loaded,
   1465      * or {@code null}
   1466      * @param password the password used to check the integrity of
   1467      * the keystore, the password used to unlock the keystore,
   1468      * or {@code null}
   1469      *
   1470      * @exception IOException if there is an I/O or format problem with the
   1471      * keystore data, if a password is required but not given,
   1472      * or if the given password was incorrect. If the error is due to a
   1473      * wrong password, the {@link Throwable#getCause cause} of the
   1474      * {@code IOException} should be an
   1475      * {@code UnrecoverableKeyException}
   1476      * @exception NoSuchAlgorithmException if the algorithm used to check
   1477      * the integrity of the keystore cannot be found
   1478      * @exception CertificateException if any of the certificates in the
   1479      * keystore could not be loaded
   1480      */
   1481     public final void load(InputStream stream, char[] password)
   1482         throws IOException, NoSuchAlgorithmException, CertificateException
   1483     {
   1484         keyStoreSpi.engineLoad(stream, password);
   1485         initialized = true;
   1486     }
   1487 
   1488     /**
   1489      * Loads this keystore using the given {@code LoadStoreParameter}.
   1490      *
   1491      * <p> Note that if this KeyStore has already been loaded, it is
   1492      * reinitialized and loaded again from the given parameter.
   1493      *
   1494      * @param param the {@code LoadStoreParameter}
   1495      *          that specifies how to load the keystore,
   1496      *          which may be {@code null}
   1497      *
   1498      * @exception IllegalArgumentException if the given
   1499      *          {@code LoadStoreParameter}
   1500      *          input is not recognized
   1501      * @exception IOException if there is an I/O or format problem with the
   1502      *          keystore data. If the error is due to an incorrect
   1503      *         {@code ProtectionParameter} (e.g. wrong password)
   1504      *         the {@link Throwable#getCause cause} of the
   1505      *         {@code IOException} should be an
   1506      *         {@code UnrecoverableKeyException}
   1507      * @exception NoSuchAlgorithmException if the algorithm used to check
   1508      *          the integrity of the keystore cannot be found
   1509      * @exception CertificateException if any of the certificates in the
   1510      *          keystore could not be loaded
   1511      *
   1512      * @since 1.5
   1513      */
   1514     public final void load(LoadStoreParameter param)
   1515                 throws IOException, NoSuchAlgorithmException,
   1516                 CertificateException {
   1517 
   1518         keyStoreSpi.engineLoad(param);
   1519         initialized = true;
   1520     }
   1521 
   1522     /**
   1523      * Gets a keystore {@code Entry} for the specified alias
   1524      * with the specified protection parameter.
   1525      *
   1526      * @param alias get the keystore {@code Entry} for this alias
   1527      * @param protParam the {@code ProtectionParameter}
   1528      *          used to protect the {@code Entry},
   1529      *          which may be {@code null}
   1530      *
   1531      * @return the keystore {@code Entry} for the specified alias,
   1532      *          or {@code null} if there is no such entry
   1533      *
   1534      * @exception NullPointerException if
   1535      *          {@code alias} is {@code null}
   1536      * @exception NoSuchAlgorithmException if the algorithm for recovering the
   1537      *          entry cannot be found
   1538      * @exception UnrecoverableEntryException if the specified
   1539      *          {@code protParam} were insufficient or invalid
   1540      * @exception UnrecoverableKeyException if the entry is a
   1541      *          {@code PrivateKeyEntry} or {@code SecretKeyEntry}
   1542      *          and the specified {@code protParam} does not contain
   1543      *          the information needed to recover the key (e.g. wrong password)
   1544      * @exception KeyStoreException if the keystore has not been initialized
   1545      *          (loaded).
   1546      * @see #setEntry(String, KeyStore.Entry, KeyStore.ProtectionParameter)
   1547      *
   1548      * @since 1.5
   1549      */
   1550     public final Entry getEntry(String alias, ProtectionParameter protParam)
   1551                 throws NoSuchAlgorithmException, UnrecoverableEntryException,
   1552                 KeyStoreException {
   1553 
   1554         if (alias == null) {
   1555             throw new NullPointerException("invalid null input");
   1556         }
   1557         if (!initialized) {
   1558             throw new KeyStoreException("Uninitialized keystore");
   1559         }
   1560         return keyStoreSpi.engineGetEntry(alias, protParam);
   1561     }
   1562 
   1563     /**
   1564      * Saves a keystore {@code Entry} under the specified alias.
   1565      * The protection parameter is used to protect the
   1566      * {@code Entry}.
   1567      *
   1568      * <p> If an entry already exists for the specified alias,
   1569      * it is overridden.
   1570      *
   1571      * @param alias save the keystore {@code Entry} under this alias
   1572      * @param entry the {@code Entry} to save
   1573      * @param protParam the {@code ProtectionParameter}
   1574      *          used to protect the {@code Entry},
   1575      *          which may be {@code null}
   1576      *
   1577      * @exception NullPointerException if
   1578      *          {@code alias} or {@code entry}
   1579      *          is {@code null}
   1580      * @exception KeyStoreException if the keystore has not been initialized
   1581      *          (loaded), or if this operation fails for some other reason
   1582      *
   1583      * @see #getEntry(String, KeyStore.ProtectionParameter)
   1584      *
   1585      * @since 1.5
   1586      */
   1587     public final void setEntry(String alias, Entry entry,
   1588                         ProtectionParameter protParam)
   1589                 throws KeyStoreException {
   1590         if (alias == null || entry == null) {
   1591             throw new NullPointerException("invalid null input");
   1592         }
   1593         if (!initialized) {
   1594             throw new KeyStoreException("Uninitialized keystore");
   1595         }
   1596         keyStoreSpi.engineSetEntry(alias, entry, protParam);
   1597     }
   1598 
   1599     /**
   1600      * Determines if the keystore {@code Entry} for the specified
   1601      * {@code alias} is an instance or subclass of the specified
   1602      * {@code entryClass}.
   1603      *
   1604      * @param alias the alias name
   1605      * @param entryClass the entry class
   1606      *
   1607      * @return true if the keystore {@code Entry} for the specified
   1608      *          {@code alias} is an instance or subclass of the
   1609      *          specified {@code entryClass}, false otherwise
   1610      *
   1611      * @exception NullPointerException if
   1612      *          {@code alias} or {@code entryClass}
   1613      *          is {@code null}
   1614      * @exception KeyStoreException if the keystore has not been
   1615      *          initialized (loaded)
   1616      *
   1617      * @since 1.5
   1618      */
   1619     public final boolean
   1620         entryInstanceOf(String alias,
   1621                         Class<? extends KeyStore.Entry> entryClass)
   1622         throws KeyStoreException
   1623     {
   1624 
   1625         if (alias == null || entryClass == null) {
   1626             throw new NullPointerException("invalid null input");
   1627         }
   1628         if (!initialized) {
   1629             throw new KeyStoreException("Uninitialized keystore");
   1630         }
   1631         return keyStoreSpi.engineEntryInstanceOf(alias, entryClass);
   1632     }
   1633 
   1634     /**
   1635      * A description of a to-be-instantiated KeyStore object.
   1636      *
   1637      * <p>An instance of this class encapsulates the information needed to
   1638      * instantiate and initialize a KeyStore object. That process is
   1639      * triggered when the {@linkplain #getKeyStore} method is called.
   1640      *
   1641      * <p>This makes it possible to decouple configuration from KeyStore
   1642      * object creation and e.g. delay a password prompt until it is
   1643      * needed.
   1644      *
   1645      * @see KeyStore
   1646      * @see javax.net.ssl.KeyStoreBuilderParameters
   1647      * @since 1.5
   1648      */
   1649     public static abstract class Builder {
   1650 
   1651         // maximum times to try the callbackhandler if the password is wrong
   1652         static final int MAX_CALLBACK_TRIES = 3;
   1653 
   1654         /**
   1655          * Construct a new Builder.
   1656          */
   1657         protected Builder() {
   1658             // empty
   1659         }
   1660 
   1661         /**
   1662          * Returns the KeyStore described by this object.
   1663          *
   1664          * @return the {@code KeyStore} described by this object
   1665          * @exception KeyStoreException if an error occurred during the
   1666          *   operation, for example if the KeyStore could not be
   1667          *   instantiated or loaded
   1668          */
   1669         public abstract KeyStore getKeyStore() throws KeyStoreException;
   1670 
   1671         /**
   1672          * Returns the ProtectionParameters that should be used to obtain
   1673          * the {@link KeyStore.Entry Entry} with the given alias.
   1674          * The {@code getKeyStore} method must be invoked before this
   1675          * method may be called.
   1676          *
   1677          * @return the ProtectionParameters that should be used to obtain
   1678          *   the {@link KeyStore.Entry Entry} with the given alias.
   1679          * @param alias the alias of the KeyStore entry
   1680          * @throws NullPointerException if alias is null
   1681          * @throws KeyStoreException if an error occurred during the
   1682          *   operation
   1683          * @throws IllegalStateException if the getKeyStore method has
   1684          *   not been invoked prior to calling this method
   1685          */
   1686         public abstract ProtectionParameter getProtectionParameter(String alias)
   1687             throws KeyStoreException;
   1688 
   1689         /**
   1690          * Returns a new Builder that encapsulates the given KeyStore.
   1691          * The {@linkplain #getKeyStore} method of the returned object
   1692          * will return {@code keyStore}, the {@linkplain
   1693          * #getProtectionParameter getProtectionParameter()} method will
   1694          * return {@code protectionParameters}.
   1695          *
   1696          * <p> This is useful if an existing KeyStore object needs to be
   1697          * used with Builder-based APIs.
   1698          *
   1699          * @return a new Builder object
   1700          * @param keyStore the KeyStore to be encapsulated
   1701          * @param protectionParameter the ProtectionParameter used to
   1702          *   protect the KeyStore entries
   1703          * @throws NullPointerException if keyStore or
   1704          *   protectionParameters is null
   1705          * @throws IllegalArgumentException if the keyStore has not been
   1706          *   initialized
   1707          */
   1708         public static Builder newInstance(final KeyStore keyStore,
   1709                 final ProtectionParameter protectionParameter) {
   1710             if ((keyStore == null) || (protectionParameter == null)) {
   1711                 throw new NullPointerException();
   1712             }
   1713             if (keyStore.initialized == false) {
   1714                 throw new IllegalArgumentException("KeyStore not initialized");
   1715             }
   1716             return new Builder() {
   1717                 private volatile boolean getCalled;
   1718 
   1719                 public KeyStore getKeyStore() {
   1720                     getCalled = true;
   1721                     return keyStore;
   1722                 }
   1723 
   1724                 public ProtectionParameter getProtectionParameter(String alias)
   1725                 {
   1726                     if (alias == null) {
   1727                         throw new NullPointerException();
   1728                     }
   1729                     if (getCalled == false) {
   1730                         throw new IllegalStateException
   1731                             ("getKeyStore() must be called first");
   1732                     }
   1733                     return protectionParameter;
   1734                 }
   1735             };
   1736         }
   1737 
   1738         /**
   1739          * Returns a new Builder object.
   1740          *
   1741          * <p>The first call to the {@link #getKeyStore} method on the returned
   1742          * builder will create a KeyStore of type {@code type} and call
   1743          * its {@link KeyStore#load load()} method.
   1744          * The {@code inputStream} argument is constructed from
   1745          * {@code file}.
   1746          * If {@code protection} is a
   1747          * {@code PasswordProtection}, the password is obtained by
   1748          * calling the {@code getPassword} method.
   1749          * Otherwise, if {@code protection} is a
   1750          * {@code CallbackHandlerProtection}, the password is obtained
   1751          * by invoking the CallbackHandler.
   1752          *
   1753          * <p>Subsequent calls to {@link #getKeyStore} return the same object
   1754          * as the initial call. If the initial call to failed with a
   1755          * KeyStoreException, subsequent calls also throw a
   1756          * KeyStoreException.
   1757          *
   1758          * <p>The KeyStore is instantiated from {@code provider} if
   1759          * non-null. Otherwise, all installed providers are searched.
   1760          *
   1761          * <p>Calls to {@link #getProtectionParameter getProtectionParameter()}
   1762          * will return a {@link KeyStore.PasswordProtection PasswordProtection}
   1763          * object encapsulating the password that was used to invoke the
   1764          * {@code load} method.
   1765          *
   1766          * <p><em>Note</em> that the {@link #getKeyStore} method is executed
   1767          * within the {@link AccessControlContext} of the code invoking this
   1768          * method.
   1769          *
   1770          * @return a new Builder object
   1771          * @param type the type of KeyStore to be constructed
   1772          * @param provider the provider from which the KeyStore is to
   1773          *   be instantiated (or null)
   1774          * @param file the File that contains the KeyStore data
   1775          * @param protection the ProtectionParameter securing the KeyStore data
   1776          * @throws NullPointerException if type, file or protection is null
   1777          * @throws IllegalArgumentException if protection is not an instance
   1778          *   of either PasswordProtection or CallbackHandlerProtection; or
   1779          *   if file does not exist or does not refer to a normal file
   1780          */
   1781         public static Builder newInstance(String type, Provider provider,
   1782                 File file, ProtectionParameter protection) {
   1783             if ((type == null) || (file == null) || (protection == null)) {
   1784                 throw new NullPointerException();
   1785             }
   1786             if ((protection instanceof PasswordProtection == false) &&
   1787                 (protection instanceof CallbackHandlerProtection == false)) {
   1788                 throw new IllegalArgumentException
   1789                 ("Protection must be PasswordProtection or " +
   1790                  "CallbackHandlerProtection");
   1791             }
   1792             if (file.isFile() == false) {
   1793                 throw new IllegalArgumentException
   1794                     ("File does not exist or it does not refer " +
   1795                      "to a normal file: " + file);
   1796             }
   1797             return new FileBuilder(type, provider, file, protection,
   1798                 AccessController.getContext());
   1799         }
   1800 
   1801         private static final class FileBuilder extends Builder {
   1802 
   1803             private final String type;
   1804             private final Provider provider;
   1805             private final File file;
   1806             private ProtectionParameter protection;
   1807             private ProtectionParameter keyProtection;
   1808             private final AccessControlContext context;
   1809 
   1810             private KeyStore keyStore;
   1811 
   1812             private Throwable oldException;
   1813 
   1814             FileBuilder(String type, Provider provider, File file,
   1815                     ProtectionParameter protection,
   1816                     AccessControlContext context) {
   1817                 this.type = type;
   1818                 this.provider = provider;
   1819                 this.file = file;
   1820                 this.protection = protection;
   1821                 this.context = context;
   1822             }
   1823 
   1824             public synchronized KeyStore getKeyStore() throws KeyStoreException
   1825             {
   1826                 if (keyStore != null) {
   1827                     return keyStore;
   1828                 }
   1829                 if (oldException != null) {
   1830                     throw new KeyStoreException
   1831                         ("Previous KeyStore instantiation failed",
   1832                          oldException);
   1833                 }
   1834                 PrivilegedExceptionAction<KeyStore> action =
   1835                         new PrivilegedExceptionAction<KeyStore>() {
   1836                     public KeyStore run() throws Exception {
   1837                         if (protection instanceof CallbackHandlerProtection == false) {
   1838                             return run0();
   1839                         }
   1840                         // when using a CallbackHandler,
   1841                         // reprompt if the password is wrong
   1842                         int tries = 0;
   1843                         while (true) {
   1844                             tries++;
   1845                             try {
   1846                                 return run0();
   1847                             } catch (IOException e) {
   1848                                 if ((tries < MAX_CALLBACK_TRIES)
   1849                                         && (e.getCause() instanceof UnrecoverableKeyException)) {
   1850                                     continue;
   1851                                 }
   1852                                 throw e;
   1853                             }
   1854                         }
   1855                     }
   1856                     public KeyStore run0() throws Exception {
   1857                         KeyStore ks;
   1858                         if (provider == null) {
   1859                             ks = KeyStore.getInstance(type);
   1860                         } else {
   1861                             ks = KeyStore.getInstance(type, provider);
   1862                         }
   1863                         InputStream in = null;
   1864                         char[] password = null;
   1865                         try {
   1866                             in = new FileInputStream(file);
   1867                             if (protection instanceof PasswordProtection) {
   1868                                 password =
   1869                                 ((PasswordProtection)protection).getPassword();
   1870                                 keyProtection = protection;
   1871                             } else {
   1872                                 CallbackHandler handler =
   1873                                     ((CallbackHandlerProtection)protection)
   1874                                     .getCallbackHandler();
   1875                                 PasswordCallback callback = new PasswordCallback
   1876                                     ("Password for keystore " + file.getName(),
   1877                                     false);
   1878                                 handler.handle(new Callback[] {callback});
   1879                                 password = callback.getPassword();
   1880                                 if (password == null) {
   1881                                     throw new KeyStoreException("No password" +
   1882                                                                 " provided");
   1883                                 }
   1884                                 callback.clearPassword();
   1885                                 keyProtection = new PasswordProtection(password);
   1886                             }
   1887                             ks.load(in, password);
   1888                             return ks;
   1889                         } finally {
   1890                             if (in != null) {
   1891                                 in.close();
   1892                             }
   1893                         }
   1894                     }
   1895                 };
   1896                 try {
   1897                     keyStore = AccessController.doPrivileged(action, context);
   1898                     return keyStore;
   1899                 } catch (PrivilegedActionException e) {
   1900                     oldException = e.getCause();
   1901                     throw new KeyStoreException
   1902                         ("KeyStore instantiation failed", oldException);
   1903                 }
   1904             }
   1905 
   1906             public synchronized ProtectionParameter
   1907                         getProtectionParameter(String alias) {
   1908                 if (alias == null) {
   1909                     throw new NullPointerException();
   1910                 }
   1911                 if (keyStore == null) {
   1912                     throw new IllegalStateException
   1913                         ("getKeyStore() must be called first");
   1914                 }
   1915                 return keyProtection;
   1916             }
   1917         }
   1918 
   1919         /**
   1920          * Returns a new Builder object.
   1921          *
   1922          * <p>Each call to the {@link #getKeyStore} method on the returned
   1923          * builder will return a new KeyStore object of type {@code type}.
   1924          * Its {@link KeyStore#load(KeyStore.LoadStoreParameter) load()}
   1925          * method is invoked using a
   1926          * {@code LoadStoreParameter} that encapsulates
   1927          * {@code protection}.
   1928          *
   1929          * <p>The KeyStore is instantiated from {@code provider} if
   1930          * non-null. Otherwise, all installed providers are searched.
   1931          *
   1932          * <p>Calls to {@link #getProtectionParameter getProtectionParameter()}
   1933          * will return {@code protection}.
   1934          *
   1935          * <p><em>Note</em> that the {@link #getKeyStore} method is executed
   1936          * within the {@link AccessControlContext} of the code invoking this
   1937          * method.
   1938          *
   1939          * @return a new Builder object
   1940          * @param type the type of KeyStore to be constructed
   1941          * @param provider the provider from which the KeyStore is to
   1942          *   be instantiated (or null)
   1943          * @param protection the ProtectionParameter securing the Keystore
   1944          * @throws NullPointerException if type or protection is null
   1945          */
   1946         public static Builder newInstance(final String type,
   1947                 final Provider provider, final ProtectionParameter protection) {
   1948             if ((type == null) || (protection == null)) {
   1949                 throw new NullPointerException();
   1950             }
   1951             final AccessControlContext context = AccessController.getContext();
   1952             return new Builder() {
   1953                 private volatile boolean getCalled;
   1954                 private IOException oldException;
   1955 
   1956                 private final PrivilegedExceptionAction<KeyStore> action
   1957                         = new PrivilegedExceptionAction<KeyStore>() {
   1958 
   1959                     public KeyStore run() throws Exception {
   1960                         KeyStore ks;
   1961                         if (provider == null) {
   1962                             ks = KeyStore.getInstance(type);
   1963                         } else {
   1964                             ks = KeyStore.getInstance(type, provider);
   1965                         }
   1966                         LoadStoreParameter param = new SimpleLoadStoreParameter(protection);
   1967                         if (protection instanceof CallbackHandlerProtection == false) {
   1968                             ks.load(param);
   1969                         } else {
   1970                             // when using a CallbackHandler,
   1971                             // reprompt if the password is wrong
   1972                             int tries = 0;
   1973                             while (true) {
   1974                                 tries++;
   1975                                 try {
   1976                                     ks.load(param);
   1977                                     break;
   1978                                 } catch (IOException e) {
   1979                                     if (e.getCause() instanceof UnrecoverableKeyException) {
   1980                                         if (tries < MAX_CALLBACK_TRIES) {
   1981                                             continue;
   1982                                         } else {
   1983                                             oldException = e;
   1984                                         }
   1985                                     }
   1986                                     throw e;
   1987                                 }
   1988                             }
   1989                         }
   1990                         getCalled = true;
   1991                         return ks;
   1992                     }
   1993                 };
   1994 
   1995                 public synchronized KeyStore getKeyStore()
   1996                         throws KeyStoreException {
   1997                     if (oldException != null) {
   1998                         throw new KeyStoreException
   1999                             ("Previous KeyStore instantiation failed",
   2000                              oldException);
   2001                     }
   2002                     try {
   2003                         return AccessController.doPrivileged(action, context);
   2004                     } catch (PrivilegedActionException e) {
   2005                         Throwable cause = e.getCause();
   2006                         throw new KeyStoreException
   2007                             ("KeyStore instantiation failed", cause);
   2008                     }
   2009                 }
   2010 
   2011                 public ProtectionParameter getProtectionParameter(String alias)
   2012                 {
   2013                     if (alias == null) {
   2014                         throw new NullPointerException();
   2015                     }
   2016                     if (getCalled == false) {
   2017                         throw new IllegalStateException
   2018                             ("getKeyStore() must be called first");
   2019                     }
   2020                     return protection;
   2021                 }
   2022             };
   2023         }
   2024 
   2025     }
   2026 
   2027     static class SimpleLoadStoreParameter implements LoadStoreParameter {
   2028 
   2029         private final ProtectionParameter protection;
   2030 
   2031         SimpleLoadStoreParameter(ProtectionParameter protection) {
   2032             this.protection = protection;
   2033         }
   2034 
   2035         public ProtectionParameter getProtectionParameter() {
   2036             return protection;
   2037         }
   2038     }
   2039 
   2040 }
   2041