001 /*
002 * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.security;
027
028 import java.io.*;
029 import java.util.*;
030
031 import java.security.KeyStore.*;
032 import java.security.cert.Certificate;
033 import java.security.cert.CertificateException;
034
035 import javax.crypto.SecretKey;
036
037 import javax.security.auth.callback.*;
038
039 /**
040 * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
041 * for the <code>KeyStore</code> class.
042 * All the abstract methods in this class must be implemented by each
043 * cryptographic service provider who wishes to supply the implementation
044 * of a keystore for a particular keystore type.
045 *
046 * @author Jan Luehe
047 *
048 * @version 1.28, 05/05/07
049 *
050 * @see KeyStore
051 *
052 * @since 1.2
053 */
054
055 public abstract class KeyStoreSpi {
056
057 /**
058 * Returns the key associated with the given alias, using the given
059 * password to recover it. The key must have been associated with
060 * the alias by a call to <code>setKeyEntry</code>,
061 * or by a call to <code>setEntry</code> with a
062 * <code>PrivateKeyEntry</code> or <code>SecretKeyEntry</code>.
063 *
064 * @param alias the alias name
065 * @param password the password for recovering the key
066 *
067 * @return the requested key, or null if the given alias does not exist
068 * or does not identify a key-related entry.
069 *
070 * @exception NoSuchAlgorithmException if the algorithm for recovering the
071 * key cannot be found
072 * @exception UnrecoverableKeyException if the key cannot be recovered
073 * (e.g., the given password is wrong).
074 */
075 public abstract Key engineGetKey(String alias, char[] password)
076 throws NoSuchAlgorithmException, UnrecoverableKeyException;
077
078 /**
079 * Returns the certificate chain associated with the given alias.
080 * The certificate chain must have been associated with the alias
081 * by a call to <code>setKeyEntry</code>,
082 * or by a call to <code>setEntry</code> with a
083 * <code>PrivateKeyEntry</code>.
084 *
085 * @param alias the alias name
086 *
087 * @return the certificate chain (ordered with the user's certificate first
088 * and the root certificate authority last), or null if the given alias
089 * does not exist or does not contain a certificate chain
090 */
091 public abstract Certificate[] engineGetCertificateChain(String alias);
092
093 /**
094 * Returns the certificate associated with the given alias.
095 *
096 * <p> If the given alias name identifies an entry
097 * created by a call to <code>setCertificateEntry</code>,
098 * or created by a call to <code>setEntry</code> with a
099 * <code>TrustedCertificateEntry</code>,
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</code>,
104 * or created by a call to <code>setEntry</code> with a
105 * <code>PrivateKeyEntry</code>,
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 */
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 */
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</code>,
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</code>).
144 *
145 * @exception KeyStoreException if the given key cannot be protected, or
146 * this operation fails for some other reason
147 */
148 public abstract void engineSetKeyEntry(String alias, Key key,
149 char[] password, 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</code>,
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</code>).
170 *
171 * @exception KeyStoreException if this operation fails.
172 */
173 public abstract void engineSetKeyEntry(String alias, byte[] key,
174 Certificate[] chain) throws KeyStoreException;
175
176 /**
177 * Assigns the given certificate to the given alias.
178 *
179 * <p> If the given alias identifies an existing entry
180 * created by a call to <code>setCertificateEntry</code>,
181 * or created by a call to <code>setEntry</code> with a
182 * <code>TrustedCertificateEntry</code>,
183 * the trusted certificate in the existing entry
184 * is overridden by the given certificate.
185 *
186 * @param alias the alias name
187 * @param cert the certificate
188 *
189 * @exception KeyStoreException if the given alias already exists and does
190 * not identify an entry containing a trusted certificate,
191 * or this operation fails for some other reason.
192 */
193 public abstract void engineSetCertificateEntry(String alias,
194 Certificate cert) throws KeyStoreException;
195
196 /**
197 * Deletes the entry identified by the given alias from this keystore.
198 *
199 * @param alias the alias name
200 *
201 * @exception KeyStoreException if the entry cannot be removed.
202 */
203 public abstract void engineDeleteEntry(String alias)
204 throws KeyStoreException;
205
206 /**
207 * Lists all the alias names of this keystore.
208 *
209 * @return enumeration of the alias names
210 */
211 public abstract Enumeration<String> engineAliases();
212
213 /**
214 * Checks if the given alias exists in this keystore.
215 *
216 * @param alias the alias name
217 *
218 * @return true if the alias exists, false otherwise
219 */
220 public abstract boolean engineContainsAlias(String alias);
221
222 /**
223 * Retrieves the number of entries in this keystore.
224 *
225 * @return the number of entries in this keystore
226 */
227 public abstract int engineSize();
228
229 /**
230 * Returns true if the entry identified by the given alias
231 * was created by a call to <code>setKeyEntry</code>,
232 * or created by a call to <code>setEntry</code> with a
233 * <code>PrivateKeyEntry</code> or a <code>SecretKeyEntry</code>.
234 *
235 * @param alias the alias for the keystore entry to be checked
236 *
237 * @return true if the entry identified by the given alias is a
238 * key-related, false otherwise.
239 */
240 public abstract boolean engineIsKeyEntry(String alias);
241
242 /**
243 * Returns true if the entry identified by the given alias
244 * was created by a call to <code>setCertificateEntry</code>,
245 * or created by a call to <code>setEntry</code> with a
246 * <code>TrustedCertificateEntry</code>.
247 *
248 * @param alias the alias for the keystore entry to be checked
249 *
250 * @return true if the entry identified by the given alias contains a
251 * trusted certificate, false otherwise.
252 */
253 public abstract boolean engineIsCertificateEntry(String alias);
254
255 /**
256 * Returns the (alias) name of the first keystore entry whose certificate
257 * matches the given certificate.
258 *
259 * <p>This method attempts to match the given certificate with each
260 * keystore entry. If the entry being considered was
261 * created by a call to <code>setCertificateEntry</code>,
262 * or created by a call to <code>setEntry</code> with a
263 * <code>TrustedCertificateEntry</code>,
264 * then the given certificate is compared to that entry's certificate.
265 *
266 * <p> If the entry being considered was
267 * created by a call to <code>setKeyEntry</code>,
268 * or created by a call to <code>setEntry</code> with a
269 * <code>PrivateKeyEntry</code>,
270 * then the given certificate is compared to the first
271 * element of that entry's certificate chain.
272 *
273 * @param cert the certificate to match with.
274 *
275 * @return the alias name of the first entry with matching certificate,
276 * or null if no such entry exists in this keystore.
277 */
278 public abstract String engineGetCertificateAlias(Certificate cert);
279
280 /**
281 * Stores this keystore to the given output stream, and protects its
282 * integrity with the given password.
283 *
284 * @param stream the output stream to which this keystore is written.
285 * @param password the password to generate the keystore integrity check
286 *
287 * @exception IOException if there was an I/O problem with data
288 * @exception NoSuchAlgorithmException if the appropriate data integrity
289 * algorithm could not be found
290 * @exception CertificateException if any of the certificates included in
291 * the keystore data could not be stored
292 */
293 public abstract void engineStore(OutputStream stream,
294 char[] password) throws IOException,
295 NoSuchAlgorithmException, CertificateException;
296
297 /**
298 * Stores this keystore using the given
299 * <code>KeyStore.LoadStoreParmeter</code>.
300 *
301 * @param param the <code>KeyStore.LoadStoreParmeter</code>
302 * that specifies how to store the keystore,
303 * which may be <code>null</code>
304 *
305 * @exception IllegalArgumentException if the given
306 * <code>KeyStore.LoadStoreParmeter</code>
307 * input is not recognized
308 * @exception IOException if there was an I/O problem with data
309 * @exception NoSuchAlgorithmException if the appropriate data integrity
310 * algorithm could not be found
311 * @exception CertificateException if any of the certificates included in
312 * the keystore data could not be stored
313 *
314 * @since 1.5
315 */
316 public void engineStore(KeyStore.LoadStoreParameter param)
317 throws IOException, NoSuchAlgorithmException,
318 CertificateException {
319 throw new UnsupportedOperationException();
320 }
321
322 /**
323 * Loads the keystore from the given input stream.
324 *
325 * <p>A password may be given to unlock the keystore
326 * (e.g. the keystore resides on a hardware token device),
327 * or to check the integrity of the keystore data.
328 * If a password is not given for integrity checking,
329 * then integrity checking is not performed.
330 *
331 * @param stream the input stream from which the keystore is loaded,
332 * or <code>null</code>
333 * @param password the password used to check the integrity of
334 * the keystore, the password used to unlock the keystore,
335 * or <code>null</code>
336 *
337 * @exception IOException if there is an I/O or format problem with the
338 * keystore data, if a password is required but not given,
339 * or if the given password was incorrect. If the error is due to a
340 * wrong password, the {@link Throwable#getCause cause} of the
341 * <code>IOException</code> should be an
342 * <code>UnrecoverableKeyException</code>
343 * @exception NoSuchAlgorithmException if the algorithm used to check
344 * the integrity of the keystore cannot be found
345 * @exception CertificateException if any of the certificates in the
346 * keystore could not be loaded
347 */
348 public abstract void engineLoad(InputStream stream, char[] password)
349 throws IOException, NoSuchAlgorithmException,
350 CertificateException;
351
352 /**
353 * Loads the keystore using the given
354 * <code>KeyStore.LoadStoreParameter</code>.
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</code>
360 * that specifies how to load the keystore,
361 * which may be <code>null</code>
362 *
363 * @exception IllegalArgumentException if the given
364 * <code>KeyStore.LoadStoreParameter</code>
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</code> (e.g. wrong password)
369 * the {@link Throwable#getCause cause} of the
370 * <code>IOException</code> should be an
371 * <code>UnrecoverableKeyException</code>
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 */
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
390 .getProtectionParameter();
391 char[] password;
392 if (protection instanceof PasswordProtection) {
393 password = ((PasswordProtection) protection)
394 .getPassword();
395 } else if (protection instanceof CallbackHandlerProtection) {
396 CallbackHandler handler = ((CallbackHandlerProtection) protection)
397 .getCallbackHandler();
398 PasswordCallback callback = new PasswordCallback(
399 "Password: ", false);
400 try {
401 handler.handle(new Callback[] { callback });
402 } catch (UnsupportedCallbackException e) {
403 throw new NoSuchAlgorithmException(
404 "Could not obtain password", e);
405 }
406 password = callback.getPassword();
407 callback.clearPassword();
408 if (password == null) {
409 throw new NoSuchAlgorithmException(
410 "No password provided");
411 }
412 } else {
413 throw new NoSuchAlgorithmException(
414 "ProtectionParameter must"
415 + " be PasswordProtection or CallbackHandlerProtection");
416 }
417 engineLoad(null, password);
418 return;
419 }
420
421 throw new UnsupportedOperationException();
422 }
423
424 /**
425 * Gets a <code>KeyStore.Entry</code> for the specified alias
426 * with the specified protection parameter.
427 *
428 * @param alias get the <code>KeyStore.Entry</code> for this alias
429 * @param protParam the <code>ProtectionParameter</code>
430 * used to protect the <code>Entry</code>,
431 * which may be <code>null</code>
432 *
433 * @return the <code>KeyStore.Entry</code> for the specified alias,
434 * or <code>null</code> if there is no such entry
435 *
436 * @exception KeyStoreException if the operation failed
437 * @exception NoSuchAlgorithmException if the algorithm for recovering the
438 * entry cannot be found
439 * @exception UnrecoverableEntryException if the specified
440 * <code>protParam</code> were insufficient or invalid
441 * @exception UnrecoverableKeyException if the entry is a
442 * <code>PrivateKeyEntry</code> or <code>SecretKeyEntry</code>
443 * and the specified <code>protParam</code> does not contain
444 * the information needed to recover the key (e.g. wrong password)
445 *
446 * @since 1.5
447 */
448 public KeyStore.Entry engineGetEntry(String alias,
449 KeyStore.ProtectionParameter protParam)
450 throws KeyStoreException, NoSuchAlgorithmException,
451 UnrecoverableEntryException {
452
453 if (!engineContainsAlias(alias)) {
454 return null;
455 }
456
457 if (protParam == null) {
458 if (engineIsCertificateEntry(alias)) {
459 return new KeyStore.TrustedCertificateEntry(
460 engineGetCertificate(alias));
461 } else {
462 throw new UnrecoverableKeyException(
463 "requested entry requires a password");
464 }
465 }
466
467 if (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 KeyStore.PasswordProtection pp = (KeyStore.PasswordProtection) protParam;
473 char[] password = pp.getPassword();
474
475 Key key = engineGetKey(alias, password);
476 if (key instanceof PrivateKey) {
477 Certificate[] chain = engineGetCertificateChain(alias);
478 return new KeyStore.PrivateKeyEntry(
479 (PrivateKey) key, chain);
480 } else if (key instanceof SecretKey) {
481 return new KeyStore.SecretKeyEntry((SecretKey) key);
482 }
483 }
484 }
485
486 throw new UnsupportedOperationException();
487 }
488
489 /**
490 * Saves a <code>KeyStore.Entry</code> under the specified alias.
491 * The specified protection parameter is used to protect the
492 * <code>Entry</code>.
493 *
494 * <p> If an entry already exists for the specified alias,
495 * it is overridden.
496 *
497 * @param alias save the <code>KeyStore.Entry</code> under this alias
498 * @param entry the <code>Entry</code> to save
499 * @param protParam the <code>ProtectionParameter</code>
500 * used to protect the <code>Entry</code>,
501 * which may be <code>null</code>
502 *
503 * @exception KeyStoreException if this operation fails
504 *
505 * @since 1.5
506 */
507 public void engineSetEntry(String alias, KeyStore.Entry entry,
508 KeyStore.ProtectionParameter protParam)
509 throws KeyStoreException {
510
511 // get password
512 if (protParam != null
513 && !(protParam instanceof KeyStore.PasswordProtection)) {
514 throw new KeyStoreException(
515 "unsupported protection parameter");
516 }
517 KeyStore.PasswordProtection pProtect = null;
518 if (protParam != null) {
519 pProtect = (KeyStore.PasswordProtection) protParam;
520 }
521
522 // set entry
523 if (entry instanceof KeyStore.TrustedCertificateEntry) {
524 if (protParam != null && pProtect.getPassword() != null) {
525 // pre-1.5 style setCertificateEntry did not allow password
526 throw new KeyStoreException(
527 "trusted certificate entries are not password-protected");
528 } else {
529 KeyStore.TrustedCertificateEntry tce = (KeyStore.TrustedCertificateEntry) entry;
530 engineSetCertificateEntry(alias, tce
531 .getTrustedCertificate());
532 return;
533 }
534 } else if (entry instanceof KeyStore.PrivateKeyEntry) {
535 if (pProtect == null || pProtect.getPassword() == null) {
536 // pre-1.5 style setKeyEntry required password
537 throw new KeyStoreException(
538 "non-null password required to create PrivateKeyEntry");
539 } else {
540 engineSetKeyEntry(alias,
541 ((KeyStore.PrivateKeyEntry) entry)
542 .getPrivateKey(), pProtect
543 .getPassword(),
544 ((KeyStore.PrivateKeyEntry) entry)
545 .getCertificateChain());
546 return;
547 }
548 } else if (entry instanceof KeyStore.SecretKeyEntry) {
549 if (pProtect == null || pProtect.getPassword() == null) {
550 // pre-1.5 style setKeyEntry required password
551 throw new KeyStoreException(
552 "non-null password required to create SecretKeyEntry");
553 } else {
554 engineSetKeyEntry(alias,
555 ((KeyStore.SecretKeyEntry) entry)
556 .getSecretKey(),
557 pProtect.getPassword(), (Certificate[]) null);
558 return;
559 }
560 }
561
562 throw new KeyStoreException("unsupported entry type: "
563 + entry.getClass().getName());
564 }
565
566 /**
567 * Determines if the keystore <code>Entry</code> for the specified
568 * <code>alias</code> is an instance or subclass of the specified
569 * <code>entryClass</code>.
570 *
571 * @param alias the alias name
572 * @param entryClass the entry class
573 *
574 * @return true if the keystore <code>Entry</code> for the specified
575 * <code>alias</code> is an instance or subclass of the
576 * specified <code>entryClass</code>, false otherwise
577 *
578 * @since 1.5
579 */
580 public boolean engineEntryInstanceOf(String alias,
581 Class<? extends KeyStore.Entry> entryClass) {
582 if (entryClass == KeyStore.TrustedCertificateEntry.class) {
583 return engineIsCertificateEntry(alias);
584 }
585 if (entryClass == KeyStore.PrivateKeyEntry.class) {
586 return engineIsKeyEntry(alias)
587 && engineGetCertificate(alias) != null;
588 }
589 if (entryClass == KeyStore.SecretKeyEntry.class) {
590 return engineIsKeyEntry(alias)
591 && engineGetCertificate(alias) == null;
592 }
593 return false;
594 }
595 }
|