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