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