1 /* 2 * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.mscapi; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.OutputStream; 32 import java.security.AccessController; 33 import java.security.InvalidKeyException; 34 import java.security.KeyStoreSpi; 35 import java.security.KeyStoreException; 36 import java.security.PrivilegedAction; 37 import java.security.UnrecoverableKeyException; 38 import java.security.NoSuchAlgorithmException; 39 import java.security.SecurityPermission; 40 import java.security.cert.X509Certificate; 41 import java.security.cert.Certificate; 42 import java.security.cert.CertificateException; 43 import java.security.cert.CertificateFactory; 44 import java.security.interfaces.RSAPrivateCrtKey; 45 import java.util.*; 46 47 /** 48 * Implementation of key store for Windows using the Microsoft Crypto API. 49 * 50 * @since 1.6 51 */ 52 abstract class KeyStore extends KeyStoreSpi { 53 54 public static final class MY extends KeyStore { 55 public MY() { 56 super("MY"); 57 } 58 } 59 60 public static final class ROOT extends KeyStore { 61 public ROOT() { 62 super("ROOT"); 63 } 64 } 65 66 class KeyEntry 67 { 68 private Key privateKey; 69 private X509Certificate[] certChain; 70 private String alias; 71 72 KeyEntry(Key key, X509Certificate[] chain) { 73 this(null, key, chain); 74 } 75 76 KeyEntry(String alias, Key key, X509Certificate[] chain) { 77 this.privateKey = key; 78 this.certChain = chain; 79 /* 80 * The default alias for both entry types is derived from a 81 * hash value intrinsic to the first certificate in the chain. 82 */ 83 if (alias == null) { 84 this.alias = Integer.toString(chain[0].hashCode()); 85 } else { 86 this.alias = alias; 87 } 88 } 89 90 /** 91 * Gets the alias for the keystore entry. 92 */ 93 String getAlias() 94 { 95 return alias; 96 } 97 98 /** 99 * Sets the alias for the keystore entry. 100 */ 101 void setAlias(String alias) 102 { 103 // TODO - set friendly name prop in cert store 104 this.alias = alias; 105 } 106 107 /** 108 * Gets the private key for the keystore entry. 109 */ 110 Key getPrivateKey() 111 { 112 return privateKey; 113 } 114 115 /** 116 * Sets the private key for the keystore entry. 117 */ 118 void setPrivateKey(RSAPrivateCrtKey key) 119 throws InvalidKeyException, KeyStoreException 120 { 121 byte[] modulusBytes = key.getModulus().toByteArray(); 122 123 // Adjust key length due to sign bit 124 int keyBitLength = (modulusBytes[0] == 0) 125 ? (modulusBytes.length - 1) * 8 126 : modulusBytes.length * 8; 127 128 byte[] keyBlob = generatePrivateKeyBlob( 129 keyBitLength, 130 modulusBytes, 131 key.getPublicExponent().toByteArray(), 132 key.getPrivateExponent().toByteArray(), 133 key.getPrimeP().toByteArray(), 134 key.getPrimeQ().toByteArray(), 135 key.getPrimeExponentP().toByteArray(), 136 key.getPrimeExponentQ().toByteArray(), 137 key.getCrtCoefficient().toByteArray()); 138 139 privateKey = storePrivateKey(Objects.requireNonNull(keyBlob), 140 "{" + UUID.randomUUID().toString() + "}", keyBitLength); 141 } 142 143 /** 144 * Gets the certificate chain for the keystore entry. 145 */ 146 X509Certificate[] getCertificateChain() 147 { 148 return certChain; 149 } 150 151 /** 152 * Sets the certificate chain for the keystore entry. 153 */ 154 void setCertificateChain(X509Certificate[] chain) 155 throws CertificateException, KeyStoreException 156 { 157 for (int i = 0; i < chain.length; i++) { 158 byte[] encoding = chain[i].getEncoded(); 159 if (i == 0 && privateKey != null) { 160 storeCertificate(getName(), alias, encoding, 161 encoding.length, privateKey.getHCryptProvider(), 162 privateKey.getHCryptKey()); 163 164 } else { 165 storeCertificate(getName(), alias, encoding, 166 encoding.length, 0L, 0L); // no private key to attach 167 } 168 } 169 certChain = chain; 170 } 171 }; 172 173 /* 174 * An X.509 certificate factory. 175 * Used to create an X.509 certificate from its DER-encoding. 176 */ 177 private CertificateFactory certificateFactory = null; 178 179 /* 180 * Compatibility mode: for applications that assume keystores are 181 * stream-based this mode tolerates (but ignores) a non-null stream 182 * or password parameter when passed to the load or store methods. 183 * The mode is enabled by default. 184 */ 185 private static final String KEYSTORE_COMPATIBILITY_MODE_PROP = 186 "sun.security.mscapi.keyStoreCompatibilityMode"; 187 private final boolean keyStoreCompatibilityMode; 188 189 /* 190 * The keystore entries. 191 */ 192 private Collection<KeyEntry> entries = new ArrayList<KeyEntry>(); 193 194 /* 195 * The keystore name. 196 * Case is not significant. 197 */ 198 private final String storeName; 199 200 KeyStore(String storeName) { 201 // Get the compatibility mode 202 String prop = AccessController.doPrivileged( 203 (PrivilegedAction<String>) () -> System.getProperty(KEYSTORE_COMPATIBILITY_MODE_PROP)); 204 205 if ("false".equalsIgnoreCase(prop)) { 206 keyStoreCompatibilityMode = false; 207 } else { 208 keyStoreCompatibilityMode = true; 209 } 210 211 this.storeName = storeName; 212 } 213 214 /** 215 * Returns the key associated with the given alias. 216 * <p> 217 * A compatibility mode is supported for applications that assume 218 * a password must be supplied. It permits (but ignores) a non-null 219 * <code>password</code>. The mode is enabled by default. 220 * Set the 221 * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> 222 * system property to <code>false</code> to disable compatibility mode 223 * and reject a non-null <code>password</code>. 224 * 225 * @param alias the alias name 226 * @param password the password, which should be <code>null</code> 227 * 228 * @return the requested key, or null if the given alias does not exist 229 * or does not identify a <i>key entry</i>. 230 * 231 * @exception NoSuchAlgorithmException if the algorithm for recovering the 232 * key cannot be found, 233 * or if compatibility mode is disabled and <code>password</code> is 234 * non-null. 235 * @exception UnrecoverableKeyException if the key cannot be recovered. 236 */ 237 public java.security.Key engineGetKey(String alias, char[] password) 238 throws NoSuchAlgorithmException, UnrecoverableKeyException 239 { 240 if (alias == null) { 241 return null; 242 } 243 244 if (password != null && !keyStoreCompatibilityMode) { 245 throw new UnrecoverableKeyException("Password must be null"); 246 } 247 248 if (engineIsKeyEntry(alias) == false) 249 return null; 250 251 for (KeyEntry entry : entries) { 252 if (alias.equals(entry.getAlias())) { 253 return entry.getPrivateKey(); 254 } 255 } 256 257 return null; 258 } 259 260 /** 261 * Returns the certificate chain associated with the given alias. 262 * 263 * @param alias the alias name 264 * 265 * @return the certificate chain (ordered with the user's certificate first 266 * and the root certificate authority last), or null if the given alias 267 * does not exist or does not contain a certificate chain (i.e., the given 268 * alias identifies either a <i>trusted certificate entry</i> or a 269 * <i>key entry</i> without a certificate chain). 270 */ 271 public Certificate[] engineGetCertificateChain(String alias) 272 { 273 if (alias == null) { 274 return null; 275 } 276 277 for (KeyEntry entry : entries) { 278 if (alias.equals(entry.getAlias())) { 279 X509Certificate[] certChain = entry.getCertificateChain(); 280 281 return certChain.clone(); 282 } 283 } 284 285 return null; 286 } 287 288 /** 289 * Returns the certificate associated with the given alias. 290 * 291 * <p>If the given alias name identifies a 292 * <i>trusted certificate entry</i>, the certificate associated with that 293 * entry is returned. If the given alias name identifies a 294 * <i>key entry</i>, the first element of the certificate chain of that 295 * entry is returned, or null if that entry does not have a certificate 296 * chain. 297 * 298 * @param alias the alias name 299 * 300 * @return the certificate, or null if the given alias does not exist or 301 * does not contain a certificate. 302 */ 303 public Certificate engineGetCertificate(String alias) 304 { 305 if (alias == null) { 306 return null; 307 } 308 309 for (KeyEntry entry : entries) { 310 if (alias.equals(entry.getAlias())) 311 { 312 X509Certificate[] certChain = entry.getCertificateChain(); 313 return certChain.length == 0 ? null : certChain[0]; 314 } 315 } 316 317 return null; 318 } 319 320 /** 321 * Returns the creation date of the entry identified by the given alias. 322 * 323 * @param alias the alias name 324 * 325 * @return the creation date of this entry, or null if the given alias does 326 * not exist 327 */ 328 public Date engineGetCreationDate(String alias) { 329 if (alias == null) { 330 return null; 331 } 332 return new Date(); 333 } 334 335 /** 336 * Stores the given private key and associated certificate chain in the 337 * keystore. 338 * 339 * <p>The given java.security.PrivateKey <code>key</code> must 340 * be accompanied by a certificate chain certifying the 341 * corresponding public key. 342 * 343 * <p>If the given alias already exists, the keystore information 344 * associated with it is overridden by the given key and certificate 345 * chain. Otherwise, a new entry is created. 346 * 347 * <p> 348 * A compatibility mode is supported for applications that assume 349 * a password must be supplied. It permits (but ignores) a non-null 350 * <code>password</code>. The mode is enabled by default. 351 * Set the 352 * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> 353 * system property to <code>false</code> to disable compatibility mode 354 * and reject a non-null <code>password</code>. 355 * 356 * @param alias the alias name 357 * @param key the private key to be associated with the alias 358 * @param password the password, which should be <code>null</code> 359 * @param chain the certificate chain for the corresponding public 360 * key (only required if the given key is of type 361 * <code>java.security.PrivateKey</code>). 362 * 363 * @exception KeyStoreException if the given key is not a private key, 364 * cannot be protected, or if compatibility mode is disabled and 365 * <code>password</code> is non-null, or if this operation fails for 366 * some other reason. 367 */ 368 public void engineSetKeyEntry(String alias, java.security.Key key, 369 char[] password, Certificate[] chain) throws KeyStoreException 370 { 371 if (alias == null) { 372 throw new KeyStoreException("alias must not be null"); 373 } 374 375 if (password != null && !keyStoreCompatibilityMode) { 376 throw new KeyStoreException("Password must be null"); 377 } 378 379 if (key instanceof RSAPrivateCrtKey) { 380 381 KeyEntry entry = null; 382 boolean found = false; 383 384 for (KeyEntry e : entries) { 385 if (alias.equals(e.getAlias())) { 386 found = true; 387 entry = e; 388 break; 389 } 390 } 391 392 X509Certificate[] xchain; 393 if (chain != null) { 394 if (chain instanceof X509Certificate[]) { 395 xchain = (X509Certificate[]) chain; 396 } else { 397 xchain = new X509Certificate[chain.length]; 398 System.arraycopy(chain, 0, xchain, 0, chain.length); 399 } 400 } else { 401 xchain = null; 402 } 403 404 if (! found) { 405 entry = 406 //TODO new KeyEntry(alias, key, (X509Certificate[]) chain); 407 new KeyEntry(alias, null, xchain); 408 entries.add(entry); 409 } 410 411 entry.setAlias(alias); 412 413 try { 414 entry.setPrivateKey((RSAPrivateCrtKey) key); 415 entry.setCertificateChain(xchain); 416 417 } catch (CertificateException ce) { 418 throw new KeyStoreException(ce); 419 420 } catch (InvalidKeyException ike) { 421 throw new KeyStoreException(ike); 422 } 423 424 } else { 425 throw new UnsupportedOperationException( 426 "Cannot assign the key to the given alias."); 427 } 428 } 429 430 /** 431 * Assigns the given key (that has already been protected) to the given 432 * alias. 433 * 434 * <p>If the protected key is of type 435 * <code>java.security.PrivateKey</code>, it must be accompanied by a 436 * certificate chain certifying the corresponding public key. If the 437 * underlying keystore implementation is of type <code>jks</code>, 438 * <code>key</code> must be encoded as an 439 * <code>EncryptedPrivateKeyInfo</code> as defined in the PKCS #8 standard. 440 * 441 * <p>If the given alias already exists, the keystore information 442 * associated with it is overridden by the given key (and possibly 443 * certificate chain). 444 * 445 * @param alias the alias name 446 * @param key the key (in protected format) to be associated with the alias 447 * @param chain the certificate chain for the corresponding public 448 * key (only useful if the protected key is of type 449 * <code>java.security.PrivateKey</code>). 450 * 451 * @exception KeyStoreException if this operation fails. 452 */ 453 public void engineSetKeyEntry(String alias, byte[] key, 454 Certificate[] chain) 455 throws KeyStoreException 456 { 457 throw new UnsupportedOperationException( 458 "Cannot assign the encoded key to the given alias."); 459 } 460 461 /** 462 * Assigns the given certificate to the given alias. 463 * 464 * <p>If the given alias already exists in this keystore and identifies a 465 * <i>trusted certificate entry</i>, the certificate associated with it is 466 * overridden by the given certificate. 467 * 468 * @param alias the alias name 469 * @param cert the certificate 470 * 471 * @exception KeyStoreException if the given alias already exists and does 472 * not identify a <i>trusted certificate entry</i>, or this operation 473 * fails for some other reason. 474 */ 475 public void engineSetCertificateEntry(String alias, Certificate cert) 476 throws KeyStoreException 477 { 478 if (alias == null) { 479 throw new KeyStoreException("alias must not be null"); 480 } 481 482 if (cert instanceof X509Certificate) { 483 484 // TODO - build CryptoAPI chain? 485 X509Certificate[] chain = 486 new X509Certificate[]{ (X509Certificate) cert }; 487 KeyEntry entry = null; 488 boolean found = false; 489 490 for (KeyEntry e : entries) { 491 if (alias.equals(e.getAlias())) { 492 found = true; 493 entry = e; 494 break; 495 } 496 } 497 498 if (! found) { 499 entry = 500 new KeyEntry(alias, null, chain); 501 entries.add(entry); 502 503 } 504 if (entry.getPrivateKey() == null) { // trusted-cert entry 505 entry.setAlias(alias); 506 507 try { 508 entry.setCertificateChain(chain); 509 510 } catch (CertificateException ce) { 511 throw new KeyStoreException(ce); 512 } 513 } 514 515 } else { 516 throw new UnsupportedOperationException( 517 "Cannot assign the certificate to the given alias."); 518 } 519 } 520 521 /** 522 * Deletes the entry identified by the given alias from this keystore. 523 * 524 * @param alias the alias name 525 * 526 * @exception KeyStoreException if the entry cannot be removed. 527 */ 528 public void engineDeleteEntry(String alias) 529 throws KeyStoreException 530 { 531 if (alias == null) { 532 throw new KeyStoreException("alias must not be null"); 533 } 534 535 for (KeyEntry entry : entries) { 536 if (alias.equals(entry.getAlias())) { 537 538 // Get end-entity certificate and remove from system cert store 539 X509Certificate[] certChain = entry.getCertificateChain(); 540 if (certChain != null) { 541 542 try { 543 544 byte[] encoding = certChain[0].getEncoded(); 545 removeCertificate(getName(), alias, encoding, 546 encoding.length); 547 548 } catch (CertificateException e) { 549 throw new KeyStoreException("Cannot remove entry: " + 550 e); 551 } 552 } 553 Key privateKey = entry.getPrivateKey(); 554 if (privateKey != null) { 555 destroyKeyContainer( 556 Key.getContainerName(privateKey.getHCryptProvider())); 557 } 558 559 entries.remove(entry); 560 break; 561 } 562 } 563 } 564 565 /** 566 * Lists all the alias names of this keystore. 567 * 568 * @return enumeration of the alias names 569 */ 570 public Enumeration<String> engineAliases() { 571 572 final Iterator<KeyEntry> iter = entries.iterator(); 573 574 return new Enumeration<String>() 575 { 576 public boolean hasMoreElements() 577 { 578 return iter.hasNext(); 579 } 580 581 public String nextElement() 582 { 583 KeyEntry entry = iter.next(); 584 return entry.getAlias(); 585 } 586 }; 587 } 588 589 /** 590 * Checks if the given alias exists in this keystore. 591 * 592 * @param alias the alias name 593 * 594 * @return true if the alias exists, false otherwise 595 */ 596 public boolean engineContainsAlias(String alias) { 597 for (Enumeration<String> enumerator = engineAliases(); 598 enumerator.hasMoreElements();) 599 { 600 String a = enumerator.nextElement(); 601 602 if (a.equals(alias)) 603 return true; 604 } 605 return false; 606 } 607 608 /** 609 * Retrieves the number of entries in this keystore. 610 * 611 * @return the number of entries in this keystore 612 */ 613 public int engineSize() { 614 return entries.size(); 615 } 616 617 /** 618 * Returns true if the entry identified by the given alias is a 619 * <i>key entry</i>, and false otherwise. 620 * 621 * @return true if the entry identified by the given alias is a 622 * <i>key entry</i>, false otherwise. 623 */ 624 public boolean engineIsKeyEntry(String alias) { 625 626 if (alias == null) { 627 return false; 628 } 629 630 for (KeyEntry entry : entries) { 631 if (alias.equals(entry.getAlias())) { 632 return entry.getPrivateKey() != null; 633 } 634 } 635 636 return false; 637 } 638 639 /** 640 * Returns true if the entry identified by the given alias is a 641 * <i>trusted certificate entry</i>, and false otherwise. 642 * 643 * @return true if the entry identified by the given alias is a 644 * <i>trusted certificate entry</i>, false otherwise. 645 */ 646 public boolean engineIsCertificateEntry(String alias) 647 { 648 for (KeyEntry entry : entries) { 649 if (alias.equals(entry.getAlias())) { 650 return entry.getPrivateKey() == null; 651 } 652 } 653 654 return false; 655 } 656 657 /** 658 * Returns the (alias) name of the first keystore entry whose certificate 659 * matches the given certificate. 660 * 661 * <p>This method attempts to match the given certificate with each 662 * keystore entry. If the entry being considered 663 * is a <i>trusted certificate entry</i>, the given certificate is 664 * compared to that entry's certificate. If the entry being considered is 665 * a <i>key entry</i>, the given certificate is compared to the first 666 * element of that entry's certificate chain (if a chain exists). 667 * 668 * @param cert the certificate to match with. 669 * 670 * @return the (alias) name of the first entry with matching certificate, 671 * or null if no such entry exists in this keystore. 672 */ 673 public String engineGetCertificateAlias(Certificate cert) 674 { 675 for (KeyEntry entry : entries) { 676 if (entry.certChain != null && entry.certChain[0].equals(cert)) { 677 return entry.getAlias(); 678 } 679 } 680 681 return null; 682 } 683 684 /** 685 * engineStore is currently a no-op. 686 * Entries are stored during engineSetEntry. 687 * 688 * A compatibility mode is supported for applications that assume 689 * keystores are stream-based. It permits (but ignores) a non-null 690 * <code>stream</code> or <code>password</code>. 691 * The mode is enabled by default. 692 * Set the 693 * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> 694 * system property to <code>false</code> to disable compatibility mode 695 * and reject a non-null <code>stream</code> or <code>password</code>. 696 * 697 * @param stream the output stream, which should be <code>null</code> 698 * @param password the password, which should be <code>null</code> 699 * 700 * @exception IOException if compatibility mode is disabled and either 701 * parameter is non-null. 702 */ 703 public void engineStore(OutputStream stream, char[] password) 704 throws IOException, NoSuchAlgorithmException, CertificateException 705 { 706 if (stream != null && !keyStoreCompatibilityMode) { 707 throw new IOException("Keystore output stream must be null"); 708 } 709 710 if (password != null && !keyStoreCompatibilityMode) { 711 throw new IOException("Keystore password must be null"); 712 } 713 } 714 715 /** 716 * Loads the keystore. 717 * 718 * A compatibility mode is supported for applications that assume 719 * keystores are stream-based. It permits (but ignores) a non-null 720 * <code>stream</code> or <code>password</code>. 721 * The mode is enabled by default. 722 * Set the 723 * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> 724 * system property to <code>false</code> to disable compatibility mode 725 * and reject a non-null <code>stream</code> or <code>password</code>. 726 * 727 * @param stream the input stream, which should be <code>null</code>. 728 * @param password the password, which should be <code>null</code>. 729 * 730 * @exception IOException if there is an I/O or format problem with the 731 * keystore data. Or if compatibility mode is disabled and either 732 * parameter is non-null. 733 * @exception NoSuchAlgorithmException if the algorithm used to check 734 * the integrity of the keystore cannot be found 735 * @exception CertificateException if any of the certificates in the 736 * keystore could not be loaded 737 * @exception SecurityException if the security check for 738 * <code>SecurityPermission("authProvider.<i>name</i>")</code> does not 739 * pass, where <i>name</i> is the value returned by 740 * this provider's <code>getName</code> method. 741 */ 742 public void engineLoad(InputStream stream, char[] password) 743 throws IOException, NoSuchAlgorithmException, CertificateException 744 { 745 if (stream != null && !keyStoreCompatibilityMode) { 746 throw new IOException("Keystore input stream must be null"); 747 } 748 749 if (password != null && !keyStoreCompatibilityMode) { 750 throw new IOException("Keystore password must be null"); 751 } 752 753 /* 754 * Use the same security check as AuthProvider.login 755 */ 756 SecurityManager sm = System.getSecurityManager(); 757 if (sm != null) { 758 sm.checkPermission(new SecurityPermission( 759 "authProvider.SunMSCAPI")); 760 } 761 762 // Clear all key entries 763 entries.clear(); 764 765 try { 766 767 // Load keys and/or certificate chains 768 loadKeysOrCertificateChains(getName(), entries); 769 770 } catch (KeyStoreException e) { 771 throw new IOException(e); 772 } 773 } 774 775 /** 776 * Generates a certificate chain from the collection of 777 * certificates and stores the result into a key entry. 778 */ 779 private void generateCertificateChain(String alias, 780 Collection<? extends Certificate> certCollection, 781 Collection<KeyEntry> entries) 782 { 783 try 784 { 785 X509Certificate[] certChain = 786 new X509Certificate[certCollection.size()]; 787 788 int i = 0; 789 for (Iterator<? extends Certificate> iter = 790 certCollection.iterator(); iter.hasNext(); i++) 791 { 792 certChain[i] = (X509Certificate) iter.next(); 793 } 794 795 KeyEntry entry = new KeyEntry(alias, null, certChain); 796 797 // Add cert chain 798 entries.add(entry); 799 } 800 catch (Throwable e) 801 { 802 // Ignore the exception and skip this entry 803 // TODO - throw CertificateException? 804 } 805 } 806 807 /** 808 * Generates RSA key and certificate chain from the private key handle, 809 * collection of certificates and stores the result into key entries. 810 */ 811 private void generateRSAKeyAndCertificateChain(String alias, 812 long hCryptProv, long hCryptKey, int keyLength, 813 Collection<? extends Certificate> certCollection, 814 Collection<KeyEntry> entries) 815 { 816 try 817 { 818 X509Certificate[] certChain = 819 new X509Certificate[certCollection.size()]; 820 821 int i = 0; 822 for (Iterator<? extends Certificate> iter = 823 certCollection.iterator(); iter.hasNext(); i++) 824 { 825 certChain[i] = (X509Certificate) iter.next(); 826 } 827 828 KeyEntry entry = new KeyEntry(alias, new RSAPrivateKey(hCryptProv, 829 hCryptKey, keyLength), certChain); 830 831 // Add cert chain 832 entries.add(entry); 833 } 834 catch (Throwable e) 835 { 836 // Ignore the exception and skip this entry 837 // TODO - throw CertificateException? 838 } 839 } 840 841 /** 842 * Generates certificates from byte data and stores into cert collection. 843 * 844 * @param data Byte data. 845 * @param certCollection Collection of certificates. 846 */ 847 private void generateCertificate(byte[] data, 848 Collection<Certificate> certCollection) { 849 try 850 { 851 ByteArrayInputStream bis = new ByteArrayInputStream(data); 852 853 // Obtain certificate factory 854 if (certificateFactory == null) { 855 certificateFactory = CertificateFactory.getInstance("X.509", "SUN"); 856 } 857 858 // Generate certificate 859 Collection<? extends Certificate> c = 860 certificateFactory.generateCertificates(bis); 861 certCollection.addAll(c); 862 } 863 catch (CertificateException e) 864 { 865 // Ignore the exception and skip this certificate 866 // TODO - throw CertificateException? 867 } 868 catch (Throwable te) 869 { 870 // Ignore the exception and skip this certificate 871 // TODO - throw CertificateException? 872 } 873 } 874 875 /** 876 * Returns the name of the keystore. 877 */ 878 private String getName() 879 { 880 return storeName; 881 } 882 883 /** 884 * Load keys and/or certificates from keystore into Collection. 885 * 886 * @param name Name of keystore. 887 * @param entries Collection of key/certificate. 888 */ 889 private native void loadKeysOrCertificateChains(String name, 890 Collection<KeyEntry> entries) throws KeyStoreException; 891 892 /** 893 * Stores a DER-encoded certificate into the certificate store 894 * 895 * @param name Name of the keystore. 896 * @param alias Name of the certificate. 897 * @param encoding DER-encoded certificate. 898 */ 899 private native void storeCertificate(String name, String alias, 900 byte[] encoding, int encodingLength, long hCryptProvider, 901 long hCryptKey) throws CertificateException, KeyStoreException; 902 903 /** 904 * Removes the certificate from the certificate store 905 * 906 * @param name Name of the keystore. 907 * @param alias Name of the certificate. 908 * @param encoding DER-encoded certificate. 909 */ 910 private native void removeCertificate(String name, String alias, 911 byte[] encoding, int encodingLength) 912 throws CertificateException, KeyStoreException; 913 914 /** 915 * Destroys the key container. 916 * 917 * @param keyContainerName The name of the key container. 918 */ 919 private native void destroyKeyContainer(String keyContainerName) 920 throws KeyStoreException; 921 922 /** 923 * Generates a private-key BLOB from a key's components. 924 */ 925 private native byte[] generatePrivateKeyBlob( 926 int keyBitLength, 927 byte[] modulus, 928 byte[] publicExponent, 929 byte[] privateExponent, 930 byte[] primeP, 931 byte[] primeQ, 932 byte[] exponentP, 933 byte[] exponentQ, 934 byte[] crtCoefficient) throws InvalidKeyException; 935 936 private native RSAPrivateKey storePrivateKey(byte[] keyBlob, 937 String keyContainerName, int keySize) throws KeyStoreException; 938 }