KeyStore.java revision d21d78fd49a2d798218e8c8aefbddb26a0e71bbb
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.security; 19 20import java.io.File; 21import java.io.FileInputStream; 22import java.io.IOException; 23import java.io.InputStream; 24import java.io.OutputStream; 25import java.security.cert.Certificate; 26import java.security.cert.CertificateException; 27import java.security.cert.X509Certificate; 28import java.util.Arrays; 29import java.util.Date; 30import java.util.Enumeration; 31 32import javax.crypto.SecretKey; 33import javax.security.auth.DestroyFailedException; 34import javax.security.auth.Destroyable; 35import javax.security.auth.callback.CallbackHandler; 36 37import org.apache.harmony.security.fortress.Engine; 38import org.apache.harmony.security.internal.nls.Messages; 39 40 41/** 42 * {@code KeyStore} is responsible for maintaining cryptographic keys and their 43 * owners. 44 * <p> 45 * The type of the system key store can be changed by setting the {@code 46 * 'keystore.type'} property in the file named {@code 47 * JAVA_HOME/lib/security/java.security}. 48 * 49 * @see Certificate 50 * @see PrivateKey 51 */ 52public class KeyStore { 53 54 // Store KeyStore SERVICE name 55 private static final String SERVICE = "KeyStore"; 56 57 // Used to access common engine functionality 58 private static Engine engine = new Engine(SERVICE); 59 60 // Store KeyStore property name 61 private static final String PROPERTYNAME = "keystore.type"; 62 63 // Store default KeyStore type 64 private static final String DEFAULT_KEYSTORE_TYPE = "jks"; 65 66 // Message to report about non-initialized key store object 67 // BEGIN android-changed 68 private static String NOTINITKEYSTORE; 69 // END android-changed 70 71 // Store KeyStore state (initialized or not) 72 private boolean isInit; 73 74 // Store used KeyStoreSpi 75 private final KeyStoreSpi implSpi; 76 77 // Store used provider 78 private final Provider provider; 79 80 // Store used type 81 private final String type; 82 83 /** 84 * Constructs a new instance of {@code KeyStore} with the given arguments. 85 * 86 * @param keyStoreSpi 87 * the concrete key store. 88 * @param provider 89 * the provider. 90 * @param type 91 * the type of the {@code KeyStore} to be constructed. 92 */ 93 protected KeyStore(KeyStoreSpi keyStoreSpi, Provider provider, String type) { 94 this.type = type; 95 this.provider = provider; 96 this.implSpi = keyStoreSpi; 97 isInit = false; 98 } 99 100 // BEGIN android-added 101 /** 102 * Throws the standard "keystore not initialized" exception. 103 */ 104 private static void throwNotInitialized() throws KeyStoreException { 105 if (NOTINITKEYSTORE == null) { 106 NOTINITKEYSTORE = Messages.getString("security.4F"); 107 } 108 throw new KeyStoreException(NOTINITKEYSTORE); 109 } 110 // END android-added 111 112 /** 113 * Returns a new instance of {@code KeyStore} with the specified type. 114 * 115 * @param type 116 * the type of the returned {@code KeyStore}. 117 * @return a new instance of {@code KeyStore} with the specified type. 118 * @throws KeyStoreException 119 * if an error occurred during the creation of the new {@code 120 * KeyStore}. 121 * @throws NullPointerException 122 * if {@code type} is {@code null}. 123 * @see #getDefaultType 124 */ 125 public static KeyStore getInstance(String type) throws KeyStoreException { 126 if (type == null) { 127 throw new NullPointerException(Messages.getString("security.07")); 128 } 129 synchronized (engine) { 130 try { 131 engine.getInstance(type, null); 132 return new KeyStore((KeyStoreSpi) engine.spi, engine.provider, type); 133 } catch (NoSuchAlgorithmException e) { 134 throw new KeyStoreException(e.getMessage()); 135 } 136 } 137 } 138 139 /** 140 * Returns a new instance of {@code KeyStore} from the specified provider 141 * with the given type. 142 * 143 * @param type 144 * the type of the returned {@code KeyStore}. 145 * @param provider 146 * name of the provider of the {@code KeyStore}. 147 * @return a new instance of {@code KeyStore} from the specified provider 148 * with the given type. 149 * @throws KeyStoreException 150 * if an error occurred during the creation of the new {@code 151 * KeyStore}. 152 * @throws NoSuchProviderException 153 * if the specified provider is not available. 154 * @throws IllegalArgumentException 155 * if {@code provider} is {@code null} or the empty string. 156 * @throws NullPointerException 157 * if {@code type} is {@code null} (instead of 158 * NoSuchAlgorithmException) as in 1.4 release 159 * @see #getDefaultType 160 */ 161 public static KeyStore getInstance(String type, String provider) 162 throws KeyStoreException, NoSuchProviderException { 163 if ((provider == null) || (provider.length() == 0)) { 164 throw new IllegalArgumentException(Messages.getString("security.02")); 165 } 166 Provider impProvider = Security.getProvider(provider); 167 if (impProvider == null) { 168 throw new NoSuchProviderException(provider); 169 } 170 try { 171 return getInstance(type, impProvider); 172 } catch (Exception e) { 173 throw new KeyStoreException(e.getMessage(), e); 174 } 175 } 176 177 /** 178 * Returns a new instance of {@code KeyStore} from the specified provider 179 * with the given type. 180 * 181 * @param type 182 * the type of the returned {@code KeyStore}. 183 * @param provider 184 * the provider of the {@code KeyStore}. 185 * @return a new instance of {@code KeyStore} from the specified provider 186 * with the given type. 187 * @throws KeyStoreException 188 * if an error occurred during the creation of the new {@code 189 * KeyStore}. 190 * @throws IllegalArgumentException 191 * if {@code provider} is {@code null} or the empty string. 192 * @throws NullPointerException 193 * if {@code type} is {@code null} (instead of 194 * NoSuchAlgorithmException) as in 1.4 release 195 * @see #getDefaultType 196 */ 197 public static KeyStore getInstance(String type, Provider provider) 198 throws KeyStoreException { 199 // check parameters 200 if (provider == null) { 201 throw new IllegalArgumentException(Messages.getString("security.04")); 202 } 203 if (type == null) { 204 throw new NullPointerException(Messages.getString("security.07")); 205 } 206 // return KeyStore instance 207 synchronized (engine) { 208 try { 209 engine.getInstance(type, provider, null); 210 return new KeyStore((KeyStoreSpi) engine.spi, provider, type); 211 } catch (Exception e) { 212 // override exception 213 throw new KeyStoreException(e.getMessage()); 214 } 215 } 216 } 217 218 /** 219 * Returns the default type for {@code KeyStore} instances. 220 * <p> 221 * The default is specified in the {@code 'keystore.type'} property in the 222 * file named {@code JAVA_HOME/lib/security/java.security}. If this property 223 * is not set, {@code "jks"} will be used. 224 * 225 * @return the default type for {@code KeyStore} instances 226 */ 227 public static final String getDefaultType() { 228 String dt = AccessController.doPrivileged( 229 new PrivilegedAction<String>() { 230 public String run() { 231 return Security.getProperty(PROPERTYNAME); 232 } 233 } 234 ); 235 return (dt == null ? DEFAULT_KEYSTORE_TYPE : dt); 236 } 237 238 /** 239 * Returns the provider associated with this {@code KeyStore}. 240 * 241 * @return the provider associated with this {@code KeyStore}. 242 */ 243 public final Provider getProvider() { 244 return provider; 245 } 246 247 /** 248 * Returns the type of this {@code KeyStore}. 249 * 250 * @return the type of this {@code KeyStore}. 251 */ 252 public final String getType() { 253 return type; 254 } 255 256 /** 257 * Returns the key with the given alias, using the password to recover the 258 * key from the store. 259 * 260 * @param alias 261 * the alias for the entry. 262 * @param password 263 * the password used to recover the key. 264 * @return the key with the specified alias, or {@code null} if the 265 * specified alias is not bound to an entry. 266 * @throws KeyStoreException 267 * if this {@code KeyStore} is not initialized. 268 * @throws NoSuchAlgorithmException 269 * if the algorithm for recovering the key is not available. 270 * @throws UnrecoverableKeyException 271 * if the key can not be recovered. 272 */ 273 public final Key getKey(String alias, char[] password) 274 throws KeyStoreException, NoSuchAlgorithmException, 275 UnrecoverableKeyException { 276 if (!isInit) { 277 // BEGIN android-changed 278 throwNotInitialized(); 279 // END android-changed 280 } 281 return implSpi.engineGetKey(alias, password); 282 } 283 284 /** 285 * Returns the certificate chain for the entry with the given alias. 286 * 287 * @param alias 288 * the alias for the entry. 289 * @return the certificate chain for the entry with the given alias, or 290 * {@code null} if the specified alias is not bound to an entry. 291 * @throws KeyStoreException 292 * if this {@code KeyStore} is not initialized. 293 */ 294 public final Certificate[] getCertificateChain(String alias) 295 throws KeyStoreException { 296 if (!isInit) { 297 // BEGIN android-changed 298 throwNotInitialized(); 299 // END android-changed 300 } 301 return implSpi.engineGetCertificateChain(alias); 302 } 303 304 /** 305 * Returns the trusted certificate for the entry with the given alias. 306 * 307 * @param alias 308 * the alias for the entry. 309 * @return the trusted certificate for the entry with the given alias, or 310 * {@code null} if the specified alias is not bound to an entry. 311 * @throws KeyStoreException 312 * if this {@code KeyStore} is not initialized. 313 */ 314 public final Certificate getCertificate(String alias) 315 throws KeyStoreException { 316 if (!isInit) { 317 // BEGIN android-changed 318 throwNotInitialized(); 319 // END android-changed 320 } 321 return implSpi.engineGetCertificate(alias); 322 } 323 324 /** 325 * Returns the creation date of the entry with the given alias. 326 * 327 * @param alias 328 * the alias for the entry. 329 * @return the creation date, or {@code null} if the specified alias is not 330 * bound to an entry. 331 * @throws KeyStoreException 332 * if this {@code KeyStore} is not initialized. 333 */ 334 public final Date getCreationDate(String alias) throws KeyStoreException { 335 if (!isInit) { 336 // BEGIN android-changed 337 throwNotInitialized(); 338 // END android-changed 339 } 340 return implSpi.engineGetCreationDate(alias); 341 } 342 343 /** 344 * Associates the given alias with the key, password and certificate chain. 345 * <p> 346 * If the specified alias already exists, it will be reassigned. 347 * 348 * @param alias 349 * the alias for the key. 350 * @param key 351 * the key. 352 * @param password 353 * the password. 354 * @param chain 355 * the certificate chain. 356 * @throws KeyStoreException 357 * if this {@code KeyStore} is not initialized. 358 * @throws IllegalArgumentException 359 * if {@code key} is a {@code PrivateKey} and {@code chain} does 360 * not contain any certificates. 361 * @throws NullPointerException 362 * if {@code alias} is {@code null}. 363 */ 364 public final void setKeyEntry(String alias, Key key, char[] password, 365 Certificate[] chain) throws KeyStoreException { 366 if (!isInit) { 367 // BEGIN android-changed 368 throwNotInitialized(); 369 // END android-changed 370 } 371 372 // Certificate chain is required for PrivateKey 373 if (null != key && key instanceof PrivateKey 374 && (chain == null || chain.length == 0)) { 375 throw new IllegalArgumentException(Messages 376 .getString("security.52")); 377 } 378 implSpi.engineSetKeyEntry(alias, key, password, chain); 379 } 380 381 /** 382 * Associates the given alias with a key and a certificate chain. 383 * <p> 384 * If the specified alias already exists, it will be reassigned. 385 * <p> 386 * If this {@code KeyStore} is of type {@code "jks"}, {@code key} must be 387 * encoded conform to the PKS#8 standard as an 388 * {@link javax.crypto.EncryptedPrivateKeyInfo}. 389 * 390 * @param alias 391 * the alias for the key. 392 * @param key 393 * the key in an encoded format. 394 * @param chain 395 * the certificate chain. 396 * @throws KeyStoreException 397 * if this {@code KeyStore} is not initialized or if {@code key} 398 * is null. 399 * @throws IllegalArgumentException 400 * if {@code key} is a {@code PrivateKey} and {@code chain} 401 * does. 402 * @throws NullPointerException 403 * if {@code alias} is {@code null}. 404 */ 405 public final void setKeyEntry(String alias, byte[] key, Certificate[] chain) 406 throws KeyStoreException { 407 if (!isInit) { 408 // BEGIN android-changed 409 throwNotInitialized(); 410 // END android-changed 411 } 412 implSpi.engineSetKeyEntry(alias, key, chain); 413 } 414 415 /** 416 * Associates the given alias with a certificate. 417 * <p> 418 * If the specified alias already exists, it will be reassigned. 419 * 420 * @param alias 421 * the alias for the certificate. 422 * @param cert 423 * the certificate. 424 * @throws KeyStoreException 425 * if this {@code KeyStore} is not initialized, or an existing 426 * alias is not associated to an entry containing a trusted 427 * certificate, or this method fails for any other reason. 428 * @throws NullPointerException 429 * if {@code alias} is {@code null}. 430 */ 431 public final void setCertificateEntry(String alias, Certificate cert) 432 throws KeyStoreException { 433 if (!isInit) { 434 // BEGIN android-changed 435 throwNotInitialized(); 436 // END android-changed 437 } 438 implSpi.engineSetCertificateEntry(alias, cert); 439 } 440 441 /** 442 * Deletes the entry identified with the given alias from this {@code 443 * KeyStore}. 444 * 445 * @param alias 446 * the alias for the entry. 447 * @throws KeyStoreException 448 * if this {@code KeyStore} is not initialized, or if the entry 449 * can not be deleted. 450 * @throws NullPointerException 451 * if {@code alias} is {@code null}. 452 */ 453 public final void deleteEntry(String alias) throws KeyStoreException { 454 if (!isInit) { 455 // BEGIN android-changed 456 throwNotInitialized(); 457 // END android-changed 458 } 459 if (alias == null) { 460 throw new NullPointerException(Messages.getString("security.3F")); 461 } 462 implSpi.engineDeleteEntry(alias); 463 } 464 465 /** 466 * Returns an {@code Enumeration} over all alias names stored in this 467 * {@code KeyStore}. 468 * 469 * @return an {@code Enumeration} over all alias names stored in this 470 * {@code KeyStore}. 471 * @throws KeyStoreException 472 * if this {@code KeyStore} is not initialized. 473 */ 474 public final Enumeration<String> aliases() throws KeyStoreException { 475 if (!isInit) { 476 // BEGIN android-changed 477 throwNotInitialized(); 478 // END android-changed 479 } 480 return implSpi.engineAliases(); 481 } 482 483 /** 484 * Indicates whether the given alias is present in this {@code KeyStore}. 485 * 486 * @param alias 487 * the alias of an entry. 488 * @return {@code true} if the alias exists, {@code false} otherwise. 489 * @throws KeyStoreException 490 * if this {@code KeyStore} is not initialized. 491 * @throws NullPointerException 492 * if {@code alias} is {@code null}. 493 */ 494 public final boolean containsAlias(String alias) throws KeyStoreException { 495 if (!isInit) { 496 // BEGIN android-changed 497 throwNotInitialized(); 498 // END android-changed 499 } 500 if (alias == null) { 501 throw new NullPointerException(Messages.getString("security.3F")); 502 } 503 return implSpi.engineContainsAlias(alias); 504 } 505 506 /** 507 * Returns the number of entries stored in this {@code KeyStore}. 508 * 509 * @return the number of entries stored in this {@code KeyStore}. 510 * @throws KeyStoreException 511 * if this {@code KeyStore} is not initialized. 512 */ 513 public final int size() throws KeyStoreException { 514 if (!isInit) { 515 // BEGIN android-changed 516 throwNotInitialized(); 517 // END android-changed 518 } 519 return implSpi.engineSize(); 520 } 521 522 /** 523 * Indicates whether the specified alias is associated with either a 524 * {@link PrivateKeyEntry} or a {@link SecretKeyEntry}. 525 * 526 * @param alias 527 * the alias of an entry. 528 * @return {@code true} if the given alias is associated with a key entry. 529 * @throws KeyStoreException 530 * if this {@code KeyStore} is not initialized. 531 * @throws NullPointerException 532 * if {@code alias} is {@code null}. 533 */ 534 public final boolean isKeyEntry(String alias) throws KeyStoreException { 535 if (!isInit) { 536 // BEGIN android-changed 537 throwNotInitialized(); 538 // END android-changed 539 } 540 if (alias == null) { 541 throw new NullPointerException(Messages.getString("security.3F")); 542 } 543 return implSpi.engineIsKeyEntry(alias); 544 } 545 546 /** 547 * Indicates whether the specified alias is associated with a 548 * {@link TrustedCertificateEntry}. 549 * 550 * @param alias 551 * the alias of an entry. 552 * @return {@code true} if the given alias is associated with a certificate 553 * entry. 554 * @throws KeyStoreException 555 * if this {@code KeyStore} is not initialized. 556 * @throws NullPointerException 557 * if {@code alias} is {@code null}. 558 */ 559 public final boolean isCertificateEntry(String alias) 560 throws KeyStoreException { 561 if (!isInit) { 562 // BEGIN android-changed 563 throwNotInitialized(); 564 // END android-changed 565 } 566 if (alias == null) { 567 throw new NullPointerException(Messages.getString("security.3F")); 568 } 569 return implSpi.engineIsCertificateEntry(alias); 570 } 571 572 /** 573 * Returns the alias associated with the first entry whose certificate 574 * matches the specified certificate. 575 * 576 * @param cert 577 * the certificate to find the associated entry's alias for. 578 * @return the alias or {@code null} if no entry with the specified 579 * certificate can be found. 580 * @throws KeyStoreException 581 * if this {@code KeyStore} is not initialized. 582 */ 583 public final String getCertificateAlias(Certificate cert) 584 throws KeyStoreException { 585 if (!isInit) { 586 // BEGIN android-changed 587 throwNotInitialized(); 588 // END android-changed 589 } 590 return implSpi.engineGetCertificateAlias(cert); 591 } 592 593 /** 594 * Writes this {@code KeyStore} to the specified {@code OutputStream}. The 595 * data written to the {@code OutputStream} is protected by the specified 596 * password. 597 * 598 * @param stream 599 * the {@code OutputStream} to write the store's data to. 600 * @param password 601 * the password to protect the data. 602 * @throws KeyStoreException 603 * if this {@code KeyStore} is not initialized. 604 * @throws IOException 605 * if a problem occurred while writing to the stream. 606 * @throws NoSuchAlgorithmException 607 * if the required algorithm is not available. 608 * @throws CertificateException 609 * if an exception occurred while storing the certificates of 610 * this {@code KeyStore}. 611 */ 612 public final void store(OutputStream stream, char[] password) 613 throws KeyStoreException, IOException, NoSuchAlgorithmException, 614 CertificateException { 615 if (!isInit) { 616 // BEGIN android-changed 617 throwNotInitialized(); 618 // END android-changed 619 } 620 621 //Just delegate stream and password to implSpi 622 implSpi.engineStore(stream, password); 623 } 624 625 /** 626 * Stores this {@code KeyStore} using the specified {@code 627 * LoadStoreParameter}. 628 * 629 * @param param 630 * the {@code LoadStoreParameter} that specifies how to store 631 * this {@code KeyStore}, maybe {@code null}. 632 * @throws KeyStoreException 633 * if this {@code KeyStore} is not initialized. 634 * @throws IOException 635 * if a problem occurred while writing to the stream. 636 * @throws NoSuchAlgorithmException 637 * if the required algorithm is not available. 638 * @throws CertificateException 639 * if an exception occurred while storing the certificates of 640 * this {@code KeyStore}. 641 * @throws IllegalArgumentException 642 * if the given {@link LoadStoreParameter} is not recognized. 643 */ 644 public final void store(LoadStoreParameter param) throws KeyStoreException, 645 IOException, NoSuchAlgorithmException, CertificateException { 646 if (!isInit) { 647 // BEGIN android-changed 648 throwNotInitialized(); 649 // END android-changed 650 } 651 implSpi.engineStore(param); 652 } 653 654 /** 655 * Initializes this {@code KeyStore} from the provided {@code InputStream}. 656 * Pass {@code null} as the {@code stream} argument to initialize an empty 657 * {@code KeyStore} or to initialize a {@code KeyStore} which does not rely 658 * on an {@code InputStream}. This {@code KeyStore} utilizes the given 659 * password to verify the stored data. 660 * 661 * @param stream 662 * the {@code InputStream} to load this {@code KeyStore}'s data 663 * from or {@code null}. 664 * @param password 665 * the password to verify the stored data, maybe {@code null}. 666 * @throws IOException 667 * if a problem occurred while reading from the stream. 668 * @throws NoSuchAlgorithmException 669 * if the required algorithm is not available. 670 * @throws CertificateException 671 * if an exception occurred while loading the certificates of 672 * this {@code KeyStore}. 673 */ 674 public final void load(InputStream stream, char[] password) 675 throws IOException, NoSuchAlgorithmException, CertificateException { 676 implSpi.engineLoad(stream, password); 677 isInit = true; 678 } 679 680 /** 681 * Loads this {@code KeyStore} using the specified {@code 682 * LoadStoreParameter}. 683 * 684 * @param param 685 * the {@code LoadStoreParameter} that specifies how to load this 686 * {@code KeyStore}, maybe {@code null}. 687 * @throws IOException 688 * if a problem occurred while reading from the stream. 689 * @throws NoSuchAlgorithmException 690 * if the required algorithm is not available. 691 * @throws CertificateException 692 * if an exception occurred while loading the certificates of 693 * this {@code KeyStore}. 694 * @throws IllegalArgumentException 695 * if the given {@link LoadStoreParameter} is not recognized. 696 */ 697 public final void load(LoadStoreParameter param) throws IOException, 698 NoSuchAlgorithmException, CertificateException { 699 implSpi.engineLoad(param); 700 isInit = true; 701 } 702 703 /** 704 * Returns the {@code Entry} with the given alias, using the specified 705 * {@code ProtectionParameter}. 706 * 707 * @param alias 708 * the alias of the requested entry. 709 * @param param 710 * the {@code ProtectionParameter} used to protect the requested 711 * entry, maybe {@code null}. 712 * @return he {@code Entry} with the given alias, using the specified 713 * {@code ProtectionParameter}. 714 * @throws NoSuchAlgorithmException 715 * if the required algorithm is not available. 716 * @throws UnrecoverableEntryException 717 * if the entry can not be recovered. 718 * @throws KeyStoreException 719 * if this {@code KeyStore} is not initialized. 720 * @throws NullPointerException 721 * if {@code alias} is {@code null}. 722 */ 723 public final Entry getEntry(String alias, ProtectionParameter param) 724 throws NoSuchAlgorithmException, UnrecoverableEntryException, 725 KeyStoreException { 726 if (alias == null) { 727 throw new NullPointerException(Messages.getString("security.3F")); 728 } 729 if (!isInit) { 730 // BEGIN android-changed 731 throwNotInitialized(); 732 // END android-changed 733 } 734 return implSpi.engineGetEntry(alias, param); 735 } 736 737 /** 738 * Stores the given {@code Entry} in this {@code KeyStore} and associates 739 * the entry with the given {@code alias}. The entry is protected by the 740 * specified {@code ProtectionParameter}. 741 * <p> 742 * If the specified alias already exists, it will be reassigned. 743 * 744 * @param alias 745 * the alias for the entry. 746 * @param entry 747 * the entry to store. 748 * @param param 749 * the {@code ProtectionParameter} to protect the entry. 750 * @throws KeyStoreException 751 * if this {@code KeyStore} is not initialized. 752 * @throws NullPointerException 753 * if {@code alias} is {@code null} or {@code entry} is {@code 754 * null}. 755 */ 756 public final void setEntry(String alias, Entry entry, 757 ProtectionParameter param) throws KeyStoreException { 758 if (!isInit) { 759 // BEGIN android-changed 760 throwNotInitialized(); 761 // END android-changed 762 } 763 if (alias == null) { 764 throw new NullPointerException(Messages.getString("security.3F")); 765 } 766 if (entry == null) { 767 throw new NullPointerException(Messages.getString("security.39")); 768 } 769 implSpi.engineSetEntry(alias, entry, param); 770 } 771 772 /** 773 * Indicates whether the entry for the given alias is assignable to the 774 * provided {@code Class}. 775 * 776 * @param alias 777 * the alias for the entry. 778 * @param entryClass 779 * the type of the entry. 780 * @return {@code true} if the {@code Entry} for the alias is assignable to 781 * the specified {@code entryClass}. 782 * @throws KeyStoreException 783 * if this {@code KeyStore} is not initialized. 784 */ 785 public final boolean entryInstanceOf(String alias, 786 Class<? extends KeyStore.Entry> entryClass) 787 throws KeyStoreException { 788 if (alias == null) { 789 throw new NullPointerException(Messages.getString("security.3F")); 790 } 791 if (entryClass == null) { 792 throw new NullPointerException(Messages.getString("security.40")); 793 } 794 795 if (!isInit) { 796 // BEGIN android-changed 797 throwNotInitialized(); 798 // END android-changed 799 } 800 return implSpi.engineEntryInstanceOf(alias, entryClass); 801 } 802 803 /** 804 * {@code Builder} is used to construct new instances of {@code KeyStore}. 805 */ 806 public abstract static class Builder { 807 /** 808 * Constructs a new instance of {@code Builder}. 809 */ 810 protected Builder() { 811 } 812 813 /** 814 * Returns the {@code KeyStore} created by this {@code Builder}. 815 * 816 * @return the {@code KeyStore} created by this {@code Builder}. 817 * @throws KeyStoreException 818 * if an error occurred during construction. 819 */ 820 public abstract KeyStore getKeyStore() throws KeyStoreException; 821 822 /** 823 * Returns the {@code ProtectionParameter} to be used when a {@code 824 * Entry} with the specified alias is requested. Before this method is 825 * invoked, {@link #getKeyStore()} must be called. 826 * 827 * @param alias 828 * the alias for the entry. 829 * @return the {@code ProtectionParameter} to be used when a {@code 830 * Entry} with the specified alias is requested. 831 * @throws KeyStoreException 832 * if an error occurred during the lookup for the protection 833 * parameter. 834 * @throws IllegalStateException 835 * if {@link #getKeyStore()} is not called prior the 836 * invocation of this method. 837 * @throws NullPointerException 838 * if {@code alias} is {@code null}. 839 */ 840 public abstract ProtectionParameter getProtectionParameter(String alias) 841 throws KeyStoreException; 842 843 /** 844 * Returns a new {@code Builder} that holds the given {@code KeyStore} 845 * and the given {@code ProtectionParameter}. 846 * 847 * @param keyStore 848 * the {@code KeyStore} to be held. 849 * @param protectionParameter 850 * the {@code ProtectionParameter} to be held. 851 * @return a new instance of {@code Builder} that holds the specified 852 * {@code KeyStore} and the specified {@code 853 * ProtectionParameter}. 854 * @throws NullPointerException 855 * if {@code keyStore} or {@code protectionParameter} is 856 * {@code null}. 857 * @throws IllegalArgumentException 858 * if the given {@code KeyStore} is not initialized. 859 */ 860 public static Builder newInstance(KeyStore keyStore, 861 ProtectionParameter protectionParameter) { 862 if (keyStore == null) { 863 throw new NullPointerException(Messages.getString("security.41")); 864 } 865 if (protectionParameter == null) { 866 throw new NullPointerException(Messages.getString("security.42")); 867 } 868 869 if (!keyStore.isInit) { 870 throw new IllegalArgumentException(NOTINITKEYSTORE); 871 } 872 return new BuilderImpl(keyStore, protectionParameter, 873 null, null, null, null); 874 } 875 876 /** 877 * Returns a new {@code Builder} that creates a new {@code KeyStore} 878 * based on the provided arguments. 879 * <p> 880 * If {@code provider} is {@code null}, all installed providers are 881 * searched, otherwise the key store from the specified provider is 882 * used. 883 * 884 * @param type 885 * the type of the {@code KeyStore} to be constructed. 886 * @param provider 887 * the provider of the {@code KeyStore} to be constructed, 888 * maybe {@code null}. 889 * @param file 890 * the {@code File} that contains the data for the {@code 891 * KeyStore}. 892 * @param protectionParameter 893 * the {@code ProtectionParameter} used to protect the stored 894 * keys. 895 * @return a new {@code Builder} that creates a new {@code KeyStore} 896 * based on the provided arguments. 897 * @throws NullPointerException 898 * if {@code type, protectionParameter} or {@code file} is 899 * {@code null}. 900 * @throws IllegalArgumentException 901 * {@code protectionParameter} not an instance of either 902 * {@code PasswordProtection} or {@code 903 * CallbackHandlerProtection}, {@code file} is not a file or 904 * does not exist at all. 905 */ 906 public static Builder newInstance(String type, Provider provider, 907 File file, ProtectionParameter protectionParameter) { 908 // check null parameters 909 if (type == null) { 910 throw new NullPointerException(Messages.getString("security.07")); 911 } 912 if (protectionParameter == null) { 913 throw new NullPointerException(Messages.getString("security.42")); 914 } 915 if (file == null) { 916 throw new NullPointerException(Messages.getString("security.43")); 917 } 918 // protection parameter should be PasswordProtection or 919 // CallbackHandlerProtection 920 if (!(protectionParameter instanceof PasswordProtection) 921 && !(protectionParameter instanceof CallbackHandlerProtection)) { 922 throw new IllegalArgumentException(Messages.getString("security.35")); 923 } 924 // check file parameter 925 if (!file.exists()) { 926 throw new IllegalArgumentException(Messages.getString("security.44", file.getName())); 927 } 928 if (!file.isFile()) { 929 throw new IllegalArgumentException(Messages.getString("security.45", file.getName())); 930 } 931 // create new instance 932 return new BuilderImpl(null, protectionParameter, file, 933 type, provider, AccessController.getContext()); 934 } 935 936 /** 937 * Returns a new {@code Builder} that creates a new {@code KeyStore} 938 * based on the provided arguments. 939 * <p> 940 * If {@code provider} is {@code null}, all installed providers are 941 * searched, otherwise the key store from the specified provider is 942 * used. 943 * 944 * @param type 945 * the type of the {@code KeyStore} to be constructed. 946 * @param provider 947 * the provider of the {@code KeyStore} to be constructed, 948 * maybe {@code null}. 949 * @param protectionParameter 950 * the {@code ProtectionParameter} used to protect the stored 951 * keys. 952 * @return a new {@code Builder} that creates a new {@code KeyStore} 953 * based on the provided arguments. 954 * @throws NullPointerException 955 * if {@code type} or {@code protectionParameter} is {@code 956 * null}. 957 * @throws IllegalArgumentException 958 * {@code protectionParameter} not an instance of either 959 * {@code PasswordProtection} or {@code 960 * CallbackHandlerProtection}, {@code file} is not a file or 961 * does not exist at all. 962 */ 963 public static Builder newInstance(String type, Provider provider, 964 ProtectionParameter protectionParameter) { 965 if (type == null) { 966 throw new NullPointerException(Messages.getString("security.07")); 967 } 968 if (protectionParameter == null) { 969 throw new NullPointerException(Messages.getString("security.42")); 970 } 971 return new BuilderImpl(null, protectionParameter, null, 972 type, provider, AccessController.getContext()); 973 } 974 975 /* 976 * This class is implementation of abstract class KeyStore.Builder 977 * 978 * @author Vera Petrashkova 979 * 980 */ 981 private static class BuilderImpl extends Builder { 982 // Store used KeyStore 983 private KeyStore keyStore; 984 985 // Store used ProtectionParameter 986 private ProtectionParameter protParameter; 987 988 // Store used KeyStore type 989 private final String typeForKeyStore; 990 991 // Store used KeyStore provider 992 private final Provider providerForKeyStore; 993 994 // Store used file for KeyStore loading 995 private final File fileForLoad; 996 997 // Store getKeyStore method was invoked or not for KeyStoreBuilder 998 private boolean isGetKeyStore = false; 999 1000 // Store last Exception in getKeyStore() 1001 private KeyStoreException lastException; 1002 1003 // Store AccessControlContext which is used in getKeyStore() method 1004 private final AccessControlContext accControlContext; 1005 1006 // 1007 // Constructor BuilderImpl initializes private fields: keyStore, 1008 // protParameter, typeForKeyStore providerForKeyStore fileForLoad, 1009 // isGetKeyStore 1010 // 1011 BuilderImpl(KeyStore ks, ProtectionParameter pp, File file, 1012 String type, Provider provider, AccessControlContext context) { 1013 super(); 1014 keyStore = ks; 1015 protParameter = pp; 1016 fileForLoad = file; 1017 typeForKeyStore = type; 1018 providerForKeyStore = provider; 1019 isGetKeyStore = false; 1020 lastException = null; 1021 accControlContext = context; 1022 } 1023 1024 // 1025 // Implementation of abstract getKeyStore() method If 1026 // KeyStoreBuilder encapsulates KeyStore object then this object is 1027 // returned 1028 // 1029 // If KeyStoreBuilder encapsulates KeyStore type and provider then 1030 // KeyStore is created using these parameters. If KeyStoreBuilder 1031 // encapsulates file and ProtectionParameter then KeyStore data are 1032 // loaded from FileInputStream that is created on file. If file is 1033 // not defined then KeyStore object is initialized with null 1034 // InputStream and null password. 1035 // 1036 // Result KeyStore object is returned. 1037 // 1038 @Override 1039 public synchronized KeyStore getKeyStore() throws KeyStoreException { 1040 // If KeyStore was created but in final block some exception was 1041 // thrown 1042 // then it was stored in lastException variable and will be 1043 // thrown 1044 // all subsequent calls of this method. 1045 if (lastException != null) { 1046 throw lastException; 1047 } 1048 if (keyStore != null) { 1049 isGetKeyStore = true; 1050 return keyStore; 1051 } 1052 1053 try { 1054 final KeyStore ks; 1055 final char[] passwd; 1056 1057 // get KeyStore instance using type or type and provider 1058 ks = (providerForKeyStore == null ? KeyStore 1059 .getInstance(typeForKeyStore) : KeyStore 1060 .getInstance(typeForKeyStore, providerForKeyStore)); 1061 // protection parameter should be PasswordProtection 1062 // or CallbackHandlerProtection 1063 if (protParameter instanceof PasswordProtection) { 1064 passwd = ((PasswordProtection) protParameter) 1065 .getPassword(); 1066 } else if (protParameter instanceof CallbackHandlerProtection) { 1067 passwd = KeyStoreSpi 1068 .getPasswordFromCallBack(protParameter); 1069 } else { 1070 throw new KeyStoreException(Messages.getString("security.35")); 1071 } 1072 1073 // load KeyStore from file 1074 AccessController.doPrivileged( 1075 new PrivilegedExceptionAction<Object>() { 1076 public Object run() throws Exception { 1077 if (fileForLoad != null) { 1078 FileInputStream fis = null; 1079 try { 1080 fis = new FileInputStream(fileForLoad); 1081 ks.load(fis, passwd); 1082 } finally { 1083 // close file input stream 1084 if( fis != null ) { 1085 fis.close(); 1086 } 1087 } 1088 } else { 1089 ks.load(new TmpLSParameter( 1090 protParameter)); 1091 } 1092 return null; 1093 } 1094 }, accControlContext); 1095 1096 1097 isGetKeyStore = true; 1098 return ks; 1099 } catch (KeyStoreException e) { 1100 // Store exception 1101 throw lastException = e; 1102 } catch (Exception e) { 1103 // Override exception 1104 throw lastException = new KeyStoreException(e); 1105 } 1106 } 1107 1108 // 1109 // This is implementation of abstract method 1110 // getProtectionParameter(String alias) 1111 // 1112 // Return: ProtectionParameter to get Entry which was saved in 1113 // KeyStore with defined alias 1114 // 1115 @Override 1116 public synchronized ProtectionParameter getProtectionParameter( 1117 String alias) throws KeyStoreException { 1118 if (alias == null) { 1119 throw new NullPointerException(Messages.getString("security.3F")); 1120 } 1121 if (!isGetKeyStore) { 1122 throw new IllegalStateException(Messages.getString("security.46")); 1123 } 1124 return protParameter; 1125 } 1126 } 1127 1128 /* 1129 * Implementation of LoadStoreParameter interface 1130 */ 1131 private static class TmpLSParameter implements LoadStoreParameter { 1132 1133 // Store used protection parameter 1134 private final ProtectionParameter protPar; 1135 1136 /** 1137 * Creates TmpLoadStoreParameter object 1138 * @param protPar protection parameter 1139 */ 1140 public TmpLSParameter(ProtectionParameter protPar) { 1141 this.protPar = protPar; 1142 } 1143 1144 /** 1145 * This method returns protection parameter 1146 */ 1147 public ProtectionParameter getProtectionParameter() { 1148 return protPar; 1149 } 1150 } 1151 } 1152 1153 /** 1154 * {@code CallbackHandlerProtection} is a {@code ProtectionParameter} that 1155 * encapsulates a {@link CallbackHandler}. 1156 */ 1157 public static class CallbackHandlerProtection implements 1158 ProtectionParameter { 1159 // Store CallbackHandler 1160 private final CallbackHandler callbackHandler; 1161 1162 /** 1163 * Constructs a new instance of {@code CallbackHandlerProtection} with 1164 * the {@code CallbackHandler}. 1165 * 1166 * @param handler 1167 * the {@code CallbackHandler}. 1168 * @throws NullPointerException 1169 * if {@code handler} is {@code null}. 1170 */ 1171 public CallbackHandlerProtection(CallbackHandler handler) { 1172 if (handler == null) { 1173 throw new NullPointerException(Messages.getString("security.47")); 1174 } 1175 this.callbackHandler = handler; 1176 } 1177 1178 /** 1179 * Returns the {@code CallbackHandler}. 1180 * 1181 * @return the {@code CallbackHandler}. 1182 */ 1183 public CallbackHandler getCallbackHandler() { 1184 return callbackHandler; 1185 } 1186 } 1187 1188 /** 1189 * {@code Entry} is the common marker interface for a {@code KeyStore} 1190 * entry. 1191 */ 1192 public static interface Entry { 1193 } 1194 1195 /** 1196 * {@code LoadStoreParameter} represents a parameter that specifies how a 1197 * {@code KeyStore} can be loaded and stored. 1198 * 1199 * @see KeyStore#load(LoadStoreParameter) 1200 * @see KeyStore#store(LoadStoreParameter) 1201 */ 1202 public static interface LoadStoreParameter { 1203 /** 1204 * Returns the {@code ProtectionParameter} which is used to protect data 1205 * in the {@code KeyStore}. 1206 * 1207 * @return the {@code ProtectionParameter} which is used to protect data 1208 * in the {@code KeyStore}, maybe {@code null}. 1209 */ 1210 public ProtectionParameter getProtectionParameter(); 1211 } 1212 1213 /** 1214 * {@code PasswordProtection} is a {@code ProtectionParameter} that protects 1215 * a {@code KeyStore} using a password. 1216 */ 1217 public static class PasswordProtection implements ProtectionParameter, 1218 Destroyable { 1219 1220 // Store password 1221 private char[] password; 1222 1223 private boolean isDestroyed = false; 1224 1225 /** 1226 * Constructs a new instance of {@code PasswordProtection} with a 1227 * password. A copy of the password is stored in the new {@code 1228 * PasswordProtection} object. 1229 * 1230 * @param password 1231 * the password, maybe {@code null}. 1232 */ 1233 public PasswordProtection(char[] password) { 1234 if (password != null) { 1235 this.password = password.clone(); 1236 } 1237 } 1238 1239 /** 1240 * Returns the password. 1241 * 1242 * @return the password. 1243 * @throws IllegalStateException 1244 * if the password has been destroyed. 1245 */ 1246 public synchronized char[] getPassword() { 1247 if (isDestroyed) { 1248 throw new IllegalStateException(Messages.getString("security.36")); 1249 } 1250 return password; 1251 } 1252 1253 /** 1254 * Destroys / invalidates the password. 1255 * 1256 * @throws DestroyFailedException 1257 * if the password could not be invalidated. 1258 */ 1259 public synchronized void destroy() throws DestroyFailedException { 1260 isDestroyed = true; 1261 if (password != null) { 1262 Arrays.fill(password, '\u0000'); 1263 password = null; 1264 } 1265 } 1266 1267 /** 1268 * Indicates whether the password is invalidated. 1269 * 1270 * @return {@code true} if the password is invalidated, {@code false} 1271 * otherwise. 1272 */ 1273 public synchronized boolean isDestroyed() { 1274 return isDestroyed; 1275 } 1276 } 1277 1278 /** 1279 * {@code ProtectionParameter} is a marker interface for protection 1280 * parameters. A protection parameter is used to protect the content of a 1281 * {@code KeyStore}. 1282 */ 1283 public static interface ProtectionParameter { 1284 } 1285 1286 /** 1287 * {@code PrivateKeyEntry} represents a {@code KeyStore} entry that 1288 * holds a private key. 1289 */ 1290 public static final class PrivateKeyEntry implements Entry { 1291 // Store Certificate chain 1292 private Certificate[] chain; 1293 1294 // Store PrivateKey 1295 private PrivateKey privateKey; 1296 1297 /** 1298 * Constructs a new instance of {@code PrivateKeyEntry} with the given 1299 * {@code PrivateKey} and the provided certificate chain. 1300 * 1301 * @param privateKey 1302 * the private key. 1303 * @param chain 1304 * the ordered certificate chain with the certificate 1305 * corresponding to the private key at index 0. 1306 * @throws NullPointerException 1307 * if {@code privateKey} or {@code chain} is {@code null}. 1308 * @throws IllegalArgumentException 1309 * if {@code chain.length == 0}, the algorithm of the 1310 * private key does not match the algorithm of the public 1311 * key of the first certificate or the certificates are not 1312 * all of the same type. 1313 */ 1314 public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) { 1315 if (privateKey == null) { 1316 throw new NullPointerException(Messages.getString("security.48")); 1317 } 1318 if (chain == null) { 1319 throw new NullPointerException(Messages.getString("security.49")); 1320 } 1321 1322 if (chain.length == 0) { 1323 throw new IllegalArgumentException(Messages.getString("security.4A")); 1324 } 1325 // Match algorithm of private key and algorithm of public key from 1326 // the end certificate 1327 String s = chain[0].getType(); 1328 if (!(chain[0].getPublicKey().getAlgorithm()).equals(privateKey 1329 .getAlgorithm())) { 1330 throw new IllegalArgumentException(Messages.getString("security.4B")); 1331 } 1332 // Match certificate types 1333 for (int i = 1; i < chain.length; i++) { 1334 if (!s.equals(chain[i].getType())) { 1335 throw new IllegalArgumentException( 1336 Messages.getString("security.4C")); 1337 } 1338 } 1339 // clone chain - this.chain = (Certificate[])chain.clone(); 1340 boolean isAllX509Certificates = true; 1341 // assert chain length > 0 1342 for(Certificate cert: chain){ 1343 if(!(cert instanceof X509Certificate)){ 1344 isAllX509Certificates = false; 1345 break; 1346 } 1347 } 1348 1349 if(isAllX509Certificates){ 1350 this.chain = new X509Certificate[chain.length]; 1351 } 1352 else{ 1353 this.chain = new Certificate[chain.length]; 1354 } 1355 System.arraycopy(chain, 0, this.chain, 0, chain.length); 1356 this.privateKey = privateKey; 1357 } 1358 1359 /** 1360 * Returns the private key. 1361 * 1362 * @return the private key. 1363 */ 1364 public PrivateKey getPrivateKey() { 1365 return privateKey; 1366 } 1367 1368 /** 1369 * Returns the certificate chain. 1370 * 1371 * @return the certificate chain. 1372 */ 1373 public Certificate[] getCertificateChain() { 1374 return chain.clone(); 1375 } 1376 1377 /** 1378 * Returns the certificate corresponding to the private key. 1379 * 1380 * @return the certificate corresponding to the private key. 1381 */ 1382 public Certificate getCertificate() { 1383 return chain[0]; 1384 } 1385 1386 /** 1387 * Returns a string containing a concise, human-readable description of 1388 * this {@code PrivateKeyEntry}. 1389 * 1390 * @return a printable representation for this {@code PrivateKeyEntry}. 1391 */ 1392 @Override 1393 public String toString() { 1394 StringBuilder sb = new StringBuilder( 1395 "PrivateKeyEntry: number of elements in certificate chain is "); 1396 sb.append(Integer.toString(chain.length)); 1397 sb.append("\n"); 1398 for (int i = 0; i < chain.length; i++) { 1399 sb.append(chain[i].toString()); 1400 sb.append("\n"); 1401 } 1402 return sb.toString(); 1403 } 1404 } 1405 1406 /** 1407 * {@code SecretKeyEntry} represents a {@code KeyStore} entry that 1408 * holds a secret key. 1409 */ 1410 public static final class SecretKeyEntry implements Entry { 1411 1412 // Store SecretKey 1413 private final SecretKey secretKey; 1414 1415 /** 1416 * Constructs a new instance of {@code SecretKeyEntry} with the given 1417 * {@code SecretKey}. 1418 * 1419 * @param secretKey 1420 * the secret key. 1421 * @throws NullPointerException 1422 * if {@code secretKey} is {@code null}. 1423 */ 1424 public SecretKeyEntry(SecretKey secretKey) { 1425 if (secretKey == null) { 1426 throw new NullPointerException(Messages.getString("security.4D")); 1427 } 1428 this.secretKey = secretKey; 1429 } 1430 1431 /** 1432 * Returns the secret key. 1433 * 1434 * @return the secret key. 1435 */ 1436 public SecretKey getSecretKey() { 1437 return secretKey; 1438 } 1439 1440 /** 1441 * Returns a string containing a concise, human-readable description of 1442 * this {@code SecretKeyEntry}. 1443 * 1444 * @return a printable representation for this {@code 1445 * SecretKeyEntry}. 1446 */ 1447 @Override 1448 public String toString() { 1449 StringBuilder sb = new StringBuilder("SecretKeyEntry: algorithm - "); 1450 sb.append(secretKey.getAlgorithm()); 1451 return sb.toString(); 1452 } 1453 } 1454 1455 /** 1456 * {@code TrustedCertificateEntry} represents a {@code KeyStore} entry that 1457 * holds a trusted certificate. 1458 */ 1459 public static final class TrustedCertificateEntry implements Entry { 1460 1461 // Store trusted Certificate 1462 private final Certificate trustCertificate; 1463 1464 /** 1465 * Constructs a new instance of {@code TrustedCertificateEntry} with the 1466 * given {@code Certificate}. 1467 * 1468 * @param trustCertificate 1469 * the trusted certificate. 1470 * @throws NullPointerException 1471 * if {@code trustCertificate} is {@code null}. 1472 */ 1473 public TrustedCertificateEntry(Certificate trustCertificate) { 1474 if (trustCertificate == null) { 1475 throw new NullPointerException(Messages.getString("security.4E")); 1476 } 1477 this.trustCertificate = trustCertificate; 1478 } 1479 1480 /** 1481 * Returns the trusted certificate. 1482 * 1483 * @return the trusted certificate. 1484 */ 1485 public Certificate getTrustedCertificate() { 1486 return trustCertificate; 1487 } 1488 1489 /** 1490 * Returns a string containing a concise, human-readable description of 1491 * this {@code TrustedCertificateEntry}. 1492 * 1493 * @return a printable representation for this {@code 1494 * TrustedCertificateEntry}. 1495 */ 1496 @Override 1497 public String toString() { 1498 return "Trusted certificate entry:\n" + trustCertificate; 1499 } 1500 } 1501} 1502