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