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 18 package java.security; 19 20 import java.io.File; 21 import java.io.FileInputStream; 22 import java.io.IOException; 23 import java.io.InputStream; 24 import java.io.OutputStream; 25 import java.security.cert.Certificate; 26 import java.security.cert.CertificateException; 27 import java.security.cert.X509Certificate; 28 import java.util.Arrays; 29 import java.util.Date; 30 import java.util.Enumeration; 31 import javax.crypto.SecretKey; 32 import javax.security.auth.DestroyFailedException; 33 import javax.security.auth.Destroyable; 34 import javax.security.auth.callback.CallbackHandler; 35 import libcore.io.IoUtils; 36 import 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 */ 49 public 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); 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); 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); 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 keyStore = ks; 914 protParameter = pp; 915 fileForLoad = file; 916 typeForKeyStore = type; 917 providerForKeyStore = provider; 918 isGetKeyStore = false; 919 lastException = null; 920 } 921 922 /** 923 * Implementation of abstract getKeyStore() method If 924 * KeyStoreBuilder encapsulates KeyStore object then this object is 925 * returned 926 * 927 * If KeyStoreBuilder encapsulates KeyStore type and provider then 928 * KeyStore is created using these parameters. If KeyStoreBuilder 929 * encapsulates file and ProtectionParameter then KeyStore data are 930 * loaded from FileInputStream that is created on file. If file is 931 * not defined then KeyStore object is initialized with null 932 * InputStream and null password. 933 * 934 * Result KeyStore object is returned. 935 */ 936 @Override 937 public synchronized KeyStore getKeyStore() throws KeyStoreException { 938 // If KeyStore was created but in final block some exception was 939 // thrown 940 // then it was stored in lastException variable and will be 941 // thrown 942 // all subsequent calls of this method. 943 if (lastException != null) { 944 throw lastException; 945 } 946 if (keyStore != null) { 947 isGetKeyStore = true; 948 return keyStore; 949 } 950 951 try { 952 // get KeyStore instance using type or type and provider 953 final KeyStore ks = (providerForKeyStore == null ? KeyStore 954 .getInstance(typeForKeyStore) : KeyStore 955 .getInstance(typeForKeyStore, providerForKeyStore)); 956 // protection parameter should be PasswordProtection 957 // or CallbackHandlerProtection 958 final char[] passwd; 959 if (protParameter instanceof PasswordProtection) { 960 passwd = ((PasswordProtection) protParameter) 961 .getPassword(); 962 } else if (protParameter instanceof CallbackHandlerProtection) { 963 passwd = KeyStoreSpi 964 .getPasswordFromCallBack(protParameter); 965 } else { 966 throw new KeyStoreException("protectionParameter is neither " 967 + "PasswordProtection nor CallbackHandlerProtection instance"); 968 } 969 970 // load KeyStore from file 971 if (fileForLoad != null) { 972 FileInputStream fis = null; 973 try { 974 fis = new FileInputStream(fileForLoad); 975 ks.load(fis, passwd); 976 } finally { 977 IoUtils.closeQuietly(fis); 978 } 979 } else { 980 ks.load(new TmpLSParameter(protParameter)); 981 } 982 983 isGetKeyStore = true; 984 return ks; 985 } catch (KeyStoreException e) { 986 // Store exception 987 throw lastException = e; 988 } catch (Exception e) { 989 // Override exception 990 throw lastException = new KeyStoreException(e); 991 } 992 } 993 994 /** 995 * This is implementation of abstract method 996 * getProtectionParameter(String alias) 997 * 998 * Return: ProtectionParameter to get Entry which was saved in 999 * KeyStore with defined alias 1000 */ 1001 @Override 1002 public synchronized ProtectionParameter getProtectionParameter( 1003 String alias) throws KeyStoreException { 1004 if (alias == null) { 1005 throw new NullPointerException("alias == null"); 1006 } 1007 if (!isGetKeyStore) { 1008 throw new IllegalStateException("getKeyStore() was not invoked"); 1009 } 1010 return protParameter; 1011 } 1012 } 1013 1014 /* 1015 * Implementation of LoadStoreParameter interface 1016 */ 1017 private static class TmpLSParameter implements LoadStoreParameter { 1018 1019 // Store used protection parameter 1020 private final ProtectionParameter protPar; 1021 1022 /** 1023 * Creates TmpLoadStoreParameter object 1024 * @param protPar protection parameter 1025 */ 1026 public TmpLSParameter(ProtectionParameter protPar) { 1027 this.protPar = protPar; 1028 } 1029 1030 /** 1031 * This method returns protection parameter 1032 */ 1033 public ProtectionParameter getProtectionParameter() { 1034 return protPar; 1035 } 1036 } 1037 } 1038 1039 /** 1040 * {@code CallbackHandlerProtection} is a {@code ProtectionParameter} that 1041 * encapsulates a {@link CallbackHandler}. 1042 */ 1043 public static class CallbackHandlerProtection implements 1044 ProtectionParameter { 1045 // Store CallbackHandler 1046 private final CallbackHandler callbackHandler; 1047 1048 /** 1049 * Constructs a new instance of {@code CallbackHandlerProtection} with 1050 * the {@code CallbackHandler}. 1051 * 1052 * @param handler 1053 * the {@code CallbackHandler}. 1054 * @throws NullPointerException 1055 * if {@code handler} is {@code null}. 1056 */ 1057 public CallbackHandlerProtection(CallbackHandler handler) { 1058 if (handler == null) { 1059 throw new NullPointerException("handler == null"); 1060 } 1061 this.callbackHandler = handler; 1062 } 1063 1064 /** 1065 * Returns the {@code CallbackHandler}. 1066 * 1067 * @return the {@code CallbackHandler}. 1068 */ 1069 public CallbackHandler getCallbackHandler() { 1070 return callbackHandler; 1071 } 1072 } 1073 1074 /** 1075 * {@code Entry} is the common marker interface for a {@code KeyStore} 1076 * entry. 1077 */ 1078 public static interface Entry { 1079 } 1080 1081 /** 1082 * {@code LoadStoreParameter} represents a parameter that specifies how a 1083 * {@code KeyStore} can be loaded and stored. 1084 * 1085 * @see KeyStore#load(LoadStoreParameter) 1086 * @see KeyStore#store(LoadStoreParameter) 1087 */ 1088 public static interface LoadStoreParameter { 1089 /** 1090 * Returns the {@code ProtectionParameter} which is used to protect data 1091 * in the {@code KeyStore}. 1092 * 1093 * @return the {@code ProtectionParameter} which is used to protect data 1094 * in the {@code KeyStore}, maybe {@code null}. 1095 */ 1096 public ProtectionParameter getProtectionParameter(); 1097 } 1098 1099 /** 1100 * {@code PasswordProtection} is a {@code ProtectionParameter} that protects 1101 * a {@code KeyStore} using a password. 1102 */ 1103 public static class PasswordProtection implements ProtectionParameter, 1104 Destroyable { 1105 1106 // Store password 1107 private char[] password; 1108 1109 private boolean isDestroyed = false; 1110 1111 /** 1112 * Constructs a new instance of {@code PasswordProtection} with a 1113 * password. A copy of the password is stored in the new {@code 1114 * PasswordProtection} object. 1115 * 1116 * @param password 1117 * the password, maybe {@code null}. 1118 */ 1119 public PasswordProtection(char[] password) { 1120 if (password != null) { 1121 this.password = password.clone(); 1122 } 1123 } 1124 1125 /** 1126 * Returns the password. 1127 * 1128 * @return the password. 1129 * @throws IllegalStateException 1130 * if the password has been destroyed. 1131 */ 1132 public synchronized char[] getPassword() { 1133 if (isDestroyed) { 1134 throw new IllegalStateException("Password was destroyed"); 1135 } 1136 return password; 1137 } 1138 1139 /** 1140 * Destroys / invalidates the password. 1141 * 1142 * @throws DestroyFailedException 1143 * if the password could not be invalidated. 1144 */ 1145 public synchronized void destroy() throws DestroyFailedException { 1146 isDestroyed = true; 1147 if (password != null) { 1148 Arrays.fill(password, '\u0000'); 1149 password = null; 1150 } 1151 } 1152 1153 /** 1154 * Indicates whether the password is invalidated. 1155 * 1156 * @return {@code true} if the password is invalidated, {@code false} 1157 * otherwise. 1158 */ 1159 public synchronized boolean isDestroyed() { 1160 return isDestroyed; 1161 } 1162 } 1163 1164 /** 1165 * {@code ProtectionParameter} is a marker interface for protection 1166 * parameters. A protection parameter is used to protect the content of a 1167 * {@code KeyStore}. 1168 */ 1169 public static interface ProtectionParameter { 1170 } 1171 1172 /** 1173 * {@code PrivateKeyEntry} represents a {@code KeyStore} entry that 1174 * holds a private key. 1175 */ 1176 public static final class PrivateKeyEntry implements Entry { 1177 // Store Certificate chain 1178 private Certificate[] chain; 1179 1180 // Store PrivateKey 1181 private PrivateKey privateKey; 1182 1183 /** 1184 * Constructs a new instance of {@code PrivateKeyEntry} with the given 1185 * {@code PrivateKey} and the provided certificate chain. 1186 * 1187 * @param privateKey 1188 * the private key. 1189 * @param chain 1190 * the ordered certificate chain with the certificate 1191 * corresponding to the private key at index 0. 1192 * @throws NullPointerException 1193 * if {@code privateKey} or {@code chain} is {@code null}. 1194 * @throws IllegalArgumentException 1195 * if {@code chain.length == 0}, the algorithm of the 1196 * private key does not match the algorithm of the public 1197 * key of the first certificate or the certificates are not 1198 * all of the same type. 1199 */ 1200 public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) { 1201 if (privateKey == null) { 1202 throw new NullPointerException("privateKey == null"); 1203 } 1204 if (chain == null) { 1205 throw new NullPointerException("chain == null"); 1206 } 1207 1208 if (chain.length == 0) { 1209 throw new IllegalArgumentException("chain.length == 0"); 1210 } 1211 // Match algorithm of private key and algorithm of public key from 1212 // the end certificate 1213 String s = chain[0].getType(); 1214 if (!(chain[0].getPublicKey().getAlgorithm()).equals(privateKey.getAlgorithm())) { 1215 throw new IllegalArgumentException("Algorithm of private key does not match " 1216 + "algorithm of public key in end certificate of entry " 1217 + "(with index number: 0)"); 1218 } 1219 // Match certificate types 1220 for (int i = 1; i < chain.length; i++) { 1221 if (!s.equals(chain[i].getType())) { 1222 throw new IllegalArgumentException("Certificates from the given chain have " 1223 + "different types"); 1224 } 1225 } 1226 // clone chain - this.chain = (Certificate[])chain.clone(); 1227 boolean isAllX509Certificates = true; 1228 // assert chain length > 0 1229 for (Certificate cert: chain) { 1230 if (!(cert instanceof X509Certificate)) { 1231 isAllX509Certificates = false; 1232 break; 1233 } 1234 } 1235 1236 if(isAllX509Certificates){ 1237 this.chain = new X509Certificate[chain.length]; 1238 } else { 1239 this.chain = new Certificate[chain.length]; 1240 } 1241 System.arraycopy(chain, 0, this.chain, 0, chain.length); 1242 this.privateKey = privateKey; 1243 } 1244 1245 /** 1246 * Returns the private key. 1247 * 1248 * @return the private key. 1249 */ 1250 public PrivateKey getPrivateKey() { 1251 return privateKey; 1252 } 1253 1254 /** 1255 * Returns the certificate chain. 1256 * 1257 * @return the certificate chain. 1258 */ 1259 public Certificate[] getCertificateChain() { 1260 return chain.clone(); 1261 } 1262 1263 /** 1264 * Returns the certificate corresponding to the private key. 1265 * 1266 * @return the certificate corresponding to the private key. 1267 */ 1268 public Certificate getCertificate() { 1269 return chain[0]; 1270 } 1271 1272 /** 1273 * Returns a string containing a concise, human-readable description of 1274 * this {@code PrivateKeyEntry}. 1275 * 1276 * @return a printable representation for this {@code PrivateKeyEntry}. 1277 */ 1278 @Override 1279 public String toString() { 1280 StringBuilder sb = new StringBuilder( 1281 "PrivateKeyEntry: number of elements in certificate chain is "); 1282 sb.append(Integer.toString(chain.length)); 1283 sb.append("\n"); 1284 for (int i = 0; i < chain.length; i++) { 1285 sb.append(chain[i].toString()); 1286 sb.append("\n"); 1287 } 1288 return sb.toString(); 1289 } 1290 } 1291 1292 /** 1293 * {@code SecretKeyEntry} represents a {@code KeyStore} entry that 1294 * holds a secret key. 1295 */ 1296 public static final class SecretKeyEntry implements Entry { 1297 1298 // Store SecretKey 1299 private final SecretKey secretKey; 1300 1301 /** 1302 * Constructs a new instance of {@code SecretKeyEntry} with the given 1303 * {@code SecretKey}. 1304 * 1305 * @param secretKey 1306 * the secret key. 1307 * @throws NullPointerException 1308 * if {@code secretKey} is {@code null}. 1309 */ 1310 public SecretKeyEntry(SecretKey secretKey) { 1311 if (secretKey == null) { 1312 throw new NullPointerException("secretKey == null"); 1313 } 1314 this.secretKey = secretKey; 1315 } 1316 1317 /** 1318 * Returns the secret key. 1319 * 1320 * @return the secret key. 1321 */ 1322 public SecretKey getSecretKey() { 1323 return secretKey; 1324 } 1325 1326 /** 1327 * Returns a string containing a concise, human-readable description of 1328 * this {@code SecretKeyEntry}. 1329 * 1330 * @return a printable representation for this {@code 1331 * SecretKeyEntry}. 1332 */ 1333 @Override 1334 public String toString() { 1335 StringBuilder sb = new StringBuilder("SecretKeyEntry: algorithm - "); 1336 sb.append(secretKey.getAlgorithm()); 1337 return sb.toString(); 1338 } 1339 } 1340 1341 /** 1342 * {@code TrustedCertificateEntry} represents a {@code KeyStore} entry that 1343 * holds a trusted certificate. 1344 */ 1345 public static final class TrustedCertificateEntry implements Entry { 1346 1347 // Store trusted Certificate 1348 private final Certificate trustCertificate; 1349 1350 /** 1351 * Constructs a new instance of {@code TrustedCertificateEntry} with the 1352 * given {@code Certificate}. 1353 * 1354 * @param trustCertificate 1355 * the trusted certificate. 1356 * @throws NullPointerException 1357 * if {@code trustCertificate} is {@code null}. 1358 */ 1359 public TrustedCertificateEntry(Certificate trustCertificate) { 1360 if (trustCertificate == null) { 1361 throw new NullPointerException("trustCertificate == null"); 1362 } 1363 this.trustCertificate = trustCertificate; 1364 } 1365 1366 /** 1367 * Returns the trusted certificate. 1368 * 1369 * @return the trusted certificate. 1370 */ 1371 public Certificate getTrustedCertificate() { 1372 return trustCertificate; 1373 } 1374 1375 /** 1376 * Returns a string containing a concise, human-readable description of 1377 * this {@code TrustedCertificateEntry}. 1378 * 1379 * @return a printable representation for this {@code 1380 * TrustedCertificateEntry}. 1381 */ 1382 @Override 1383 public String toString() { 1384 return "Trusted certificate entry:\n" + trustCertificate; 1385 } 1386 } 1387 } 1388