1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package java.security;
28 
29 import java.io.*;
30 import java.util.*;
31 import java.security.KeyStore;
32 import java.security.KeyStore.*;
33 import java.security.cert.Certificate;
34 import java.security.cert.CertificateException;
35 
36 import javax.crypto.SecretKey;
37 import javax.security.auth.callback.*;
38 
39 /**
40  * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
41  * for the {@code KeyStore} class.
42  * All the abstract methods in this class must be implemented by each
43  * cryptographic service provider who wishes to supply the implementation
44  * of a keystore for a particular keystore type.
45  *
46  * @author Jan Luehe
47  *
48  *
49  * @see KeyStore
50  *
51  * @since 1.2
52  */
53 
54 public abstract class KeyStoreSpi {
55 
56     /**
57      * Returns the key associated with the given alias, using the given
58      * password to recover it.  The key must have been associated with
59      * the alias by a call to {@code setKeyEntry},
60      * or by a call to {@code setEntry} with a
61      * {@code PrivateKeyEntry} or {@code SecretKeyEntry}.
62      *
63      * @param alias the alias name
64      * @param password the password for recovering the key
65      *
66      * @return the requested key, or null if the given alias does not exist
67      * or does not identify a key-related entry.
68      *
69      * @exception NoSuchAlgorithmException if the algorithm for recovering the
70      * key cannot be found
71      * @exception UnrecoverableKeyException if the key cannot be recovered
72      * (e.g., the given password is wrong).
73      */
engineGetKey(String alias, char[] password)74     public abstract Key engineGetKey(String alias, char[] password)
75         throws NoSuchAlgorithmException, UnrecoverableKeyException;
76 
77     /**
78      * Returns the certificate chain associated with the given alias.
79      * The certificate chain must have been associated with the alias
80      * by a call to {@code setKeyEntry},
81      * or by a call to {@code setEntry} with a
82      * {@code PrivateKeyEntry}.
83      *
84      * @param alias the alias name
85      *
86      * @return the certificate chain (ordered with the user's certificate first
87      * and the root certificate authority last), or null if the given alias
88      * does not exist or does not contain a certificate chain
89      */
engineGetCertificateChain(String alias)90     public abstract Certificate[] engineGetCertificateChain(String alias);
91 
92     /**
93      * Returns the certificate associated with the given alias.
94      *
95      * <p> If the given alias name identifies an entry
96      * created by a call to {@code setCertificateEntry},
97      * or created by a call to {@code setEntry} with a
98      * {@code TrustedCertificateEntry},
99      * then the trusted certificate contained in that entry is returned.
100      *
101      * <p> If the given alias name identifies an entry
102      * created by a call to {@code setKeyEntry},
103      * or created by a call to {@code setEntry} with a
104      * {@code PrivateKeyEntry},
105      * then the first element of the certificate chain in that entry
106      * (if a chain exists) is returned.
107      *
108      * @param alias the alias name
109      *
110      * @return the certificate, or null if the given alias does not exist or
111      * does not contain a certificate.
112      */
engineGetCertificate(String alias)113     public abstract Certificate engineGetCertificate(String alias);
114 
115     /**
116      * Returns the creation date of the entry identified by the given alias.
117      *
118      * @param alias the alias name
119      *
120      * @return the creation date of this entry, or null if the given alias does
121      * not exist
122      */
engineGetCreationDate(String alias)123     public abstract Date engineGetCreationDate(String alias);
124 
125     /**
126      * Assigns the given key to the given alias, protecting it with the given
127      * password.
128      *
129      * <p>If the given key is of type {@code java.security.PrivateKey},
130      * it must be accompanied by a certificate chain certifying the
131      * corresponding public key.
132      *
133      * <p>If the given alias already exists, the keystore information
134      * associated with it is overridden by the given key (and possibly
135      * certificate chain).
136      *
137      * @param alias the alias name
138      * @param key the key to be associated with the alias
139      * @param password the password to protect the key
140      * @param chain the certificate chain for the corresponding public
141      * key (only required if the given key is of type
142      * {@code java.security.PrivateKey}).
143      *
144      * @exception KeyStoreException if the given key cannot be protected, or
145      * this operation fails for some other reason
146      */
engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)147     public abstract void engineSetKeyEntry(String alias, Key key,
148                                            char[] password,
149                                            Certificate[] chain)
150         throws KeyStoreException;
151 
152     /**
153      * Assigns the given key (that has already been protected) to the given
154      * alias.
155      *
156      * <p>If the protected key is of type
157      * {@code java.security.PrivateKey},
158      * it must be accompanied by a certificate chain certifying the
159      * corresponding public key.
160      *
161      * <p>If the given alias already exists, the keystore information
162      * associated with it is overridden by the given key (and possibly
163      * certificate chain).
164      *
165      * @param alias the alias name
166      * @param key the key (in protected format) to be associated with the alias
167      * @param chain the certificate chain for the corresponding public
168      * key (only useful if the protected key is of type
169      * {@code java.security.PrivateKey}).
170      *
171      * @exception KeyStoreException if this operation fails.
172      */
engineSetKeyEntry(String alias, byte[] key, Certificate[] chain)173     public abstract void engineSetKeyEntry(String alias, byte[] key,
174                                            Certificate[] chain)
175         throws KeyStoreException;
176 
177     /**
178      * Assigns the given certificate to the given alias.
179      *
180      * <p> If the given alias identifies an existing entry
181      * created by a call to {@code setCertificateEntry},
182      * or created by a call to {@code setEntry} with a
183      * {@code TrustedCertificateEntry},
184      * the trusted certificate in the existing entry
185      * is overridden by the given certificate.
186      *
187      * @param alias the alias name
188      * @param cert the certificate
189      *
190      * @exception KeyStoreException if the given alias already exists and does
191      * not identify an entry containing a trusted certificate,
192      * or this operation fails for some other reason.
193      */
engineSetCertificateEntry(String alias, Certificate cert)194     public abstract void engineSetCertificateEntry(String alias,
195                                                    Certificate cert)
196         throws KeyStoreException;
197 
198     /**
199      * Deletes the entry identified by the given alias from this keystore.
200      *
201      * @param alias the alias name
202      *
203      * @exception KeyStoreException if the entry cannot be removed.
204      */
engineDeleteEntry(String alias)205     public abstract void engineDeleteEntry(String alias)
206         throws KeyStoreException;
207 
208     /**
209      * Lists all the alias names of this keystore.
210      *
211      * @return enumeration of the alias names
212      */
engineAliases()213     public abstract Enumeration<String> engineAliases();
214 
215     /**
216      * Checks if the given alias exists in this keystore.
217      *
218      * @param alias the alias name
219      *
220      * @return true if the alias exists, false otherwise
221      */
engineContainsAlias(String alias)222     public abstract boolean engineContainsAlias(String alias);
223 
224     /**
225      * Retrieves the number of entries in this keystore.
226      *
227      * @return the number of entries in this keystore
228      */
engineSize()229     public abstract int engineSize();
230 
231     /**
232      * Returns true if the entry identified by the given alias
233      * was created by a call to {@code setKeyEntry},
234      * or created by a call to {@code setEntry} with a
235      * {@code PrivateKeyEntry} or a {@code SecretKeyEntry}.
236      *
237      * @param alias the alias for the keystore entry to be checked
238      *
239      * @return true if the entry identified by the given alias is a
240      * key-related, false otherwise.
241      */
engineIsKeyEntry(String alias)242     public abstract boolean engineIsKeyEntry(String alias);
243 
244     /**
245      * Returns true if the entry identified by the given alias
246      * was created by a call to {@code setCertificateEntry},
247      * or created by a call to {@code setEntry} with a
248      * {@code TrustedCertificateEntry}.
249      *
250      * @param alias the alias for the keystore entry to be checked
251      *
252      * @return true if the entry identified by the given alias contains a
253      * trusted certificate, false otherwise.
254      */
engineIsCertificateEntry(String alias)255     public abstract boolean engineIsCertificateEntry(String alias);
256 
257     /**
258      * Returns the (alias) name of the first keystore entry whose certificate
259      * matches the given certificate.
260      *
261      * <p>This method attempts to match the given certificate with each
262      * keystore entry. If the entry being considered was
263      * created by a call to {@code setCertificateEntry},
264      * or created by a call to {@code setEntry} with a
265      * {@code TrustedCertificateEntry},
266      * then the given certificate is compared to that entry's certificate.
267      *
268      * <p> If the entry being considered was
269      * created by a call to {@code setKeyEntry},
270      * or created by a call to {@code setEntry} with a
271      * {@code PrivateKeyEntry},
272      * then the given certificate is compared to the first
273      * element of that entry's certificate chain.
274      *
275      * @param cert the certificate to match with.
276      *
277      * @return the alias name of the first entry with matching certificate,
278      * or null if no such entry exists in this keystore.
279      */
engineGetCertificateAlias(Certificate cert)280     public abstract String engineGetCertificateAlias(Certificate cert);
281 
282     /**
283      * Stores this keystore to the given output stream, and protects its
284      * integrity with the given password.
285      *
286      * @param stream the output stream to which this keystore is written.
287      * @param password the password to generate the keystore integrity check
288      *
289      * @exception IOException if there was an I/O problem with data
290      * @exception NoSuchAlgorithmException if the appropriate data integrity
291      * algorithm could not be found
292      * @exception CertificateException if any of the certificates included in
293      * the keystore data could not be stored
294      */
engineStore(OutputStream stream, char[] password)295     public abstract void engineStore(OutputStream stream, char[] password)
296         throws IOException, NoSuchAlgorithmException, CertificateException;
297 
298     /**
299      * Stores this keystore using the given
300      * {@code KeyStore.LoadStoreParmeter}.
301      *
302      * @param param the {@code KeyStore.LoadStoreParmeter}
303      *          that specifies how to store the keystore,
304      *          which may be {@code null}
305      *
306      * @exception IllegalArgumentException if the given
307      *          {@code KeyStore.LoadStoreParmeter}
308      *          input is not recognized
309      * @exception IOException if there was an I/O problem with data
310      * @exception NoSuchAlgorithmException if the appropriate data integrity
311      *          algorithm could not be found
312      * @exception CertificateException if any of the certificates included in
313      *          the keystore data could not be stored
314      *
315      * @since 1.5
316      */
engineStore(KeyStore.LoadStoreParameter param)317     public void engineStore(KeyStore.LoadStoreParameter param)
318                 throws IOException, NoSuchAlgorithmException,
319                 CertificateException {
320         throw new UnsupportedOperationException();
321     }
322 
323     /**
324      * Loads the keystore from the given input stream.
325      *
326      * <p>A password may be given to unlock the keystore
327      * (e.g. the keystore resides on a hardware token device),
328      * or to check the integrity of the keystore data.
329      * If a password is not given for integrity checking,
330      * then integrity checking is not performed.
331      *
332      * @param stream the input stream from which the keystore is loaded,
333      * or {@code null}
334      * @param password the password used to check the integrity of
335      * the keystore, the password used to unlock the keystore,
336      * or {@code null}
337      *
338      * @exception IOException if there is an I/O or format problem with the
339      * keystore data, if a password is required but not given,
340      * or if the given password was incorrect. If the error is due to a
341      * wrong password, the {@link Throwable#getCause cause} of the
342      * {@code IOException} should be an
343      * {@code UnrecoverableKeyException}
344      * @exception NoSuchAlgorithmException if the algorithm used to check
345      * the integrity of the keystore cannot be found
346      * @exception CertificateException if any of the certificates in the
347      * keystore could not be loaded
348      */
engineLoad(InputStream stream, char[] password)349     public abstract void engineLoad(InputStream stream, char[] password)
350         throws IOException, NoSuchAlgorithmException, CertificateException;
351 
352     /**
353      * Loads the keystore using the given
354      * {@code KeyStore.LoadStoreParameter}.
355      *
356      * <p> Note that if this KeyStore has already been loaded, it is
357      * reinitialized and loaded again from the given parameter.
358      *
359      * @param param the {@code KeyStore.LoadStoreParameter}
360      *          that specifies how to load the keystore,
361      *          which may be {@code null}
362      *
363      * @exception IllegalArgumentException if the given
364      *          {@code KeyStore.LoadStoreParameter}
365      *          input is not recognized
366      * @exception IOException if there is an I/O or format problem with the
367      *          keystore data. If the error is due to an incorrect
368      *         {@code ProtectionParameter} (e.g. wrong password)
369      *         the {@link Throwable#getCause cause} of the
370      *         {@code IOException} should be an
371      *         {@code UnrecoverableKeyException}
372      * @exception NoSuchAlgorithmException if the algorithm used to check
373      *          the integrity of the keystore cannot be found
374      * @exception CertificateException if any of the certificates in the
375      *          keystore could not be loaded
376      *
377      * @since 1.5
378      */
engineLoad(KeyStore.LoadStoreParameter param)379     public void engineLoad(KeyStore.LoadStoreParameter param)
380                 throws IOException, NoSuchAlgorithmException,
381                 CertificateException {
382 
383         if (param == null) {
384             engineLoad((InputStream)null, (char[])null);
385             return;
386         }
387 
388         if (param instanceof KeyStore.SimpleLoadStoreParameter) {
389             ProtectionParameter protection = param.getProtectionParameter();
390             char[] password;
391             if (protection instanceof PasswordProtection) {
392                 password = ((PasswordProtection)protection).getPassword();
393             } else if (protection instanceof CallbackHandlerProtection) {
394                 CallbackHandler handler =
395                     ((CallbackHandlerProtection)protection).getCallbackHandler();
396                 PasswordCallback callback =
397                     new PasswordCallback("Password: ", false);
398                 try {
399                     handler.handle(new Callback[] {callback});
400                 } catch (UnsupportedCallbackException e) {
401                     throw new NoSuchAlgorithmException
402                         ("Could not obtain password", e);
403                 }
404                 password = callback.getPassword();
405                 callback.clearPassword();
406                 if (password == null) {
407                     throw new NoSuchAlgorithmException
408                         ("No password provided");
409                 }
410             } else {
411                 throw new NoSuchAlgorithmException("ProtectionParameter must"
412                     + " be PasswordProtection or CallbackHandlerProtection");
413             }
414             engineLoad(null, password);
415             return;
416         }
417 
418         throw new UnsupportedOperationException();
419     }
420 
421     /**
422      * Gets a {@code KeyStore.Entry} for the specified alias
423      * with the specified protection parameter.
424      *
425      * @param alias get the {@code KeyStore.Entry} for this alias
426      * @param protParam the {@code ProtectionParameter}
427      *          used to protect the {@code Entry},
428      *          which may be {@code null}
429      *
430      * @return the {@code KeyStore.Entry} for the specified alias,
431      *          or {@code null} if there is no such entry
432      *
433      * @exception KeyStoreException if the operation failed
434      * @exception NoSuchAlgorithmException if the algorithm for recovering the
435      *          entry cannot be found
436      * @exception UnrecoverableEntryException if the specified
437      *          {@code protParam} were insufficient or invalid
438      * @exception UnrecoverableKeyException if the entry is a
439      *          {@code PrivateKeyEntry} or {@code SecretKeyEntry}
440      *          and the specified {@code protParam} does not contain
441      *          the information needed to recover the key (e.g. wrong password)
442      *
443      * @since 1.5
444      */
engineGetEntry(String alias, KeyStore.ProtectionParameter protParam)445     public KeyStore.Entry engineGetEntry(String alias,
446                         KeyStore.ProtectionParameter protParam)
447                 throws KeyStoreException, NoSuchAlgorithmException,
448                 UnrecoverableEntryException {
449 
450         if (!engineContainsAlias(alias)) {
451             return null;
452         }
453 
454         if (protParam != null &&
455                 !(protParam instanceof KeyStore.PasswordProtection)) {
456             throw new UnsupportedOperationException();
457         }
458 
459         if (engineIsCertificateEntry(alias)) {
460             if (protParam == null) {
461                 return new KeyStore.TrustedCertificateEntry
462                         (engineGetCertificate(alias));
463             } else {
464                 throw new UnsupportedOperationException
465                     ("trusted certificate entries are not password-protected");
466             }
467         } else if (engineIsKeyEntry(alias)) {
468           char[] password = null;
469           if (protParam != null) {
470               KeyStore.PasswordProtection pp =
471                       (KeyStore.PasswordProtection)protParam;
472               password = pp.getPassword();
473           }
474           Key key = engineGetKey(alias, password);
475           if (key instanceof PrivateKey) {
476               Certificate[] chain = engineGetCertificateChain(alias);
477               return new KeyStore.PrivateKeyEntry((PrivateKey)key, chain);
478           } else if (key instanceof SecretKey) {
479               return new KeyStore.SecretKeyEntry((SecretKey)key);
480           }
481         }
482         throw new UnsupportedOperationException();
483     }
484 
485     /**
486      * Saves a {@code KeyStore.Entry} under the specified alias.
487      * The specified protection parameter is used to protect the
488      * {@code Entry}.
489      *
490      * <p> If an entry already exists for the specified alias,
491      * it is overridden.
492      *
493      * @param alias save the {@code KeyStore.Entry} under this alias
494      * @param entry the {@code Entry} to save
495      * @param protParam the {@code ProtectionParameter}
496      *          used to protect the {@code Entry},
497      *          which may be {@code null}
498      *
499      * @exception KeyStoreException if this operation fails
500      *
501      * @since 1.5
502      */
engineSetEntry(String alias, KeyStore.Entry entry, KeyStore.ProtectionParameter protParam)503     public void engineSetEntry(String alias, KeyStore.Entry entry,
504                         KeyStore.ProtectionParameter protParam)
505                 throws KeyStoreException {
506 
507         // get password
508         if (protParam != null &&
509             !(protParam instanceof KeyStore.PasswordProtection)) {
510             throw new KeyStoreException("unsupported protection parameter");
511         }
512         KeyStore.PasswordProtection pProtect = null;
513         if (protParam != null) {
514             pProtect = (KeyStore.PasswordProtection)protParam;
515         }
516 
517         char[] password = (pProtect == null) ? null : pProtect.getPassword();
518         // set entry
519         if (entry instanceof KeyStore.TrustedCertificateEntry) {
520             KeyStore.TrustedCertificateEntry tce =
521                     (KeyStore.TrustedCertificateEntry)entry;
522             engineSetCertificateEntry(alias, tce.getTrustedCertificate());
523             return;
524         } else if (entry instanceof KeyStore.PrivateKeyEntry) {
525             engineSetKeyEntry
526                 (alias,
527                 ((KeyStore.PrivateKeyEntry)entry).getPrivateKey(),
528                 password,
529                 ((KeyStore.PrivateKeyEntry)entry).getCertificateChain());
530             return;
531         } else if (entry instanceof KeyStore.SecretKeyEntry) {
532             engineSetKeyEntry
533                 (alias,
534                 ((KeyStore.SecretKeyEntry)entry).getSecretKey(),
535                 password,
536                 (Certificate[])null);
537             return;
538         }
539 
540         throw new KeyStoreException
541                 ("unsupported entry type: " + entry.getClass().getName());
542     }
543 
544     /**
545      * Determines if the keystore {@code Entry} for the specified
546      * {@code alias} is an instance or subclass of the specified
547      * {@code entryClass}.
548      *
549      * @param alias the alias name
550      * @param entryClass the entry class
551      *
552      * @return true if the keystore {@code Entry} for the specified
553      *          {@code alias} is an instance or subclass of the
554      *          specified {@code entryClass}, false otherwise
555      *
556      * @since 1.5
557      */
558     public boolean
engineEntryInstanceOf(String alias, Class<? extends KeyStore.Entry> entryClass)559         engineEntryInstanceOf(String alias,
560                               Class<? extends KeyStore.Entry> entryClass)
561     {
562         if (entryClass == KeyStore.TrustedCertificateEntry.class) {
563             return engineIsCertificateEntry(alias);
564         }
565         if (entryClass == KeyStore.PrivateKeyEntry.class) {
566             return engineIsKeyEntry(alias) &&
567                         engineGetCertificate(alias) != null;
568         }
569         if (entryClass == KeyStore.SecretKeyEntry.class) {
570             return engineIsKeyEntry(alias) &&
571                         engineGetCertificate(alias) == null;
572         }
573         return false;
574     }
575 }
576