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