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