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