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