1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1998, 2018, 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         engineLoad(null, param);
384     }
385 
engineLoad(InputStream stream, KeyStore.LoadStoreParameter param)386     void engineLoad(InputStream stream, KeyStore.LoadStoreParameter param)
387                 throws IOException, NoSuchAlgorithmException,
388                 CertificateException {
389 
390         if (param == null) {
391             engineLoad((InputStream)null, (char[])null);
392             return;
393         }
394 
395         if (param instanceof KeyStore.SimpleLoadStoreParameter) {
396             ProtectionParameter protection = param.getProtectionParameter();
397             char[] password;
398             if (protection instanceof PasswordProtection) {
399                 password = ((PasswordProtection)protection).getPassword();
400             } else if (protection instanceof CallbackHandlerProtection) {
401                 CallbackHandler handler =
402                     ((CallbackHandlerProtection)protection).getCallbackHandler();
403                 PasswordCallback callback =
404                     new PasswordCallback("Password: ", false);
405                 try {
406                     handler.handle(new Callback[] {callback});
407                 } catch (UnsupportedCallbackException e) {
408                     throw new NoSuchAlgorithmException
409                         ("Could not obtain password", e);
410                 }
411                 password = callback.getPassword();
412                 callback.clearPassword();
413                 if (password == null) {
414                     throw new NoSuchAlgorithmException
415                         ("No password provided");
416                 }
417             } else {
418                 throw new NoSuchAlgorithmException("ProtectionParameter must"
419                     + " be PasswordProtection or CallbackHandlerProtection");
420             }
421             engineLoad(null, password);
422             return;
423         }
424 
425         throw new UnsupportedOperationException();
426     }
427 
428     /**
429      * Gets a {@code KeyStore.Entry} for the specified alias
430      * with the specified protection parameter.
431      *
432      * @param alias get the {@code KeyStore.Entry} for this alias
433      * @param protParam the {@code ProtectionParameter}
434      *          used to protect the {@code Entry},
435      *          which may be {@code null}
436      *
437      * @return the {@code KeyStore.Entry} for the specified alias,
438      *          or {@code null} if there is no such entry
439      *
440      * @exception KeyStoreException if the operation failed
441      * @exception NoSuchAlgorithmException if the algorithm for recovering the
442      *          entry cannot be found
443      * @exception UnrecoverableEntryException if the specified
444      *          {@code protParam} were insufficient or invalid
445      * @exception UnrecoverableKeyException if the entry is a
446      *          {@code PrivateKeyEntry} or {@code SecretKeyEntry}
447      *          and the specified {@code protParam} does not contain
448      *          the information needed to recover the key (e.g. wrong password)
449      *
450      * @since 1.5
451      */
engineGetEntry(String alias, KeyStore.ProtectionParameter protParam)452     public KeyStore.Entry engineGetEntry(String alias,
453                         KeyStore.ProtectionParameter protParam)
454                 throws KeyStoreException, NoSuchAlgorithmException,
455                 UnrecoverableEntryException {
456         // Android-changed: add null check previously always done here inside engineContainsAlias
457         // if (!engineContainsAlias(alias)) {
458         if (alias == null) {
459             return null;
460         }
461 
462         // BEGIN Android-added: Figure out the type of entry once
463         // To avoid many redundant calls that for some providers like
464         // AndroidKeyStoreSpi are costly since it performs
465         // binder transactions everytime we call engineIsKeyEntry or
466         // engineContainsAlias methods and rely on the knowledge
467         // that the only two types of entries are keys or certificates.
468         boolean isCertificateEntry;
469         if (!engineIsKeyEntry(alias)){
470             if (!engineContainsAlias(alias)) {
471                 return null;
472             }
473             // If it is not a key then it has to be a certificate
474             isCertificateEntry = true;
475         } else {
476             isCertificateEntry = false;
477         }
478         // END Android-added: Figure out the type of entry once
479 
480         if (protParam == null) {
481             // Android-changed: Use cached value
482             // if (engineIsCertificateEntry(alias)) {
483             if (isCertificateEntry) {
484                 return new KeyStore.TrustedCertificateEntry
485                                 (engineGetCertificate(alias));
486             // Android-removed: Allow access to entries with no password.
487             // } else {
488             //    throw new UnrecoverableKeyException
489             //            ("requested entry requires a password");
490             }
491         }
492 
493         // Android-changed: Add protParam == null to allow access to entries with no password.
494         if ((protParam == null) || protParam instanceof KeyStore.PasswordProtection) {
495             if (isCertificateEntry) {
496                 throw new UnsupportedOperationException
497                     ("trusted certificate entries are not password-protected");
498                 // Android-changed: avoid redundant check
499                 // else if (engineIsKeyEntry(alias)) {
500             } else {
501                 // Android-changed: Allow access to entries with no password.
502                 // KeyStore.PasswordProtection pp =
503                 //         (KeyStore.PasswordProtection)protParam;
504                 // char[] password = pp.getPassword();
505                 char[] password = null;
506                 if (protParam != null) {
507                     KeyStore.PasswordProtection pp =
508                         (KeyStore.PasswordProtection)protParam;
509                     password = pp.getPassword();
510                 }
511                 Key key = engineGetKey(alias, password);
512                 if (key instanceof PrivateKey) {
513                     Certificate[] chain = engineGetCertificateChain(alias);
514                     return new KeyStore.PrivateKeyEntry((PrivateKey)key, chain);
515                 } else if (key instanceof SecretKey) {
516                     return new KeyStore.SecretKeyEntry((SecretKey)key);
517                 }
518             }
519         }
520 
521         throw new UnsupportedOperationException();
522     }
523 
524     /**
525      * Saves a {@code KeyStore.Entry} under the specified alias.
526      * The specified protection parameter is used to protect the
527      * {@code Entry}.
528      *
529      * <p> If an entry already exists for the specified alias,
530      * it is overridden.
531      *
532      * @param alias save the {@code KeyStore.Entry} under this alias
533      * @param entry the {@code Entry} to save
534      * @param protParam the {@code ProtectionParameter}
535      *          used to protect the {@code Entry},
536      *          which may be {@code null}
537      *
538      * @exception KeyStoreException if this operation fails
539      *
540      * @since 1.5
541      */
engineSetEntry(String alias, KeyStore.Entry entry, KeyStore.ProtectionParameter protParam)542     public void engineSetEntry(String alias, KeyStore.Entry entry,
543                         KeyStore.ProtectionParameter protParam)
544                 throws KeyStoreException {
545 
546         // get password
547         if (protParam != null &&
548             !(protParam instanceof KeyStore.PasswordProtection)) {
549             throw new KeyStoreException("unsupported protection parameter");
550         }
551         KeyStore.PasswordProtection pProtect = null;
552         if (protParam != null) {
553             pProtect = (KeyStore.PasswordProtection)protParam;
554         }
555 
556         // BEGIN Android-changed: Allow access to entries with no password.
557         char[] password = (pProtect == null) ? null : pProtect.getPassword();
558         // set entry
559         if (entry instanceof KeyStore.TrustedCertificateEntry) {
560             KeyStore.TrustedCertificateEntry tce =
561                     (KeyStore.TrustedCertificateEntry)entry;
562             engineSetCertificateEntry(alias, tce.getTrustedCertificate());
563             return;
564         } else if (entry instanceof KeyStore.PrivateKeyEntry) {
565             engineSetKeyEntry
566                 (alias,
567                 ((KeyStore.PrivateKeyEntry)entry).getPrivateKey(),
568                 password,
569                 ((KeyStore.PrivateKeyEntry)entry).getCertificateChain());
570             return;
571         } else if (entry instanceof KeyStore.SecretKeyEntry) {
572             engineSetKeyEntry
573                 (alias,
574                 ((KeyStore.SecretKeyEntry)entry).getSecretKey(),
575                 password,
576                 (Certificate[])null);
577             return;
578         }
579         // END Android-changed: Allow access to entries with no password.
580 
581         throw new KeyStoreException
582                 ("unsupported entry type: " + entry.getClass().getName());
583     }
584 
585     /**
586      * Determines if the keystore {@code Entry} for the specified
587      * {@code alias} is an instance or subclass of the specified
588      * {@code entryClass}.
589      *
590      * @param alias the alias name
591      * @param entryClass the entry class
592      *
593      * @return true if the keystore {@code Entry} for the specified
594      *          {@code alias} is an instance or subclass of the
595      *          specified {@code entryClass}, false otherwise
596      *
597      * @since 1.5
598      */
599     public boolean
engineEntryInstanceOf(String alias, Class<? extends KeyStore.Entry> entryClass)600         engineEntryInstanceOf(String alias,
601                               Class<? extends KeyStore.Entry> entryClass)
602     {
603         if (entryClass == KeyStore.TrustedCertificateEntry.class) {
604             return engineIsCertificateEntry(alias);
605         }
606         if (entryClass == KeyStore.PrivateKeyEntry.class) {
607             return engineIsKeyEntry(alias) &&
608                         engineGetCertificate(alias) != null;
609         }
610         if (entryClass == KeyStore.SecretKeyEntry.class) {
611             return engineIsKeyEntry(alias) &&
612                         engineGetCertificate(alias) == null;
613         }
614         return false;
615     }
616 
617     /**
618      * Probes the specified input stream to determine whether it contains a
619      * keystore that is supported by this implementation, or not.
620      *
621      * @implSpec
622      * This method returns false by default. Keystore implementations should
623      * override this method to peek at the data stream directly or to use other
624      * content detection mechanisms.
625      *
626      * @param  stream the keystore data to be probed
627      *
628      * @return true if the keystore data is supported, otherwise false
629      *
630      * @throws IOException if there is an I/O problem with the keystore data.
631      * @throws NullPointerException if stream is {@code null}.
632      *
633      * @since 9
634      */
engineProbe(InputStream stream)635     public boolean engineProbe(InputStream stream) throws IOException {
636         if (stream == null) {
637             throw new NullPointerException("input stream must not be null");
638         }
639         return false;
640     }
641 }
642