1 /* 2 * Copyright (c) 2005, 2016, 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 * Keys in the map are unique aliases (thus can differ from 193 * KeyEntry.getAlias()) 194 */ 195 private Map<String,KeyEntry> entries = new HashMap<>(); 196 197 /* 198 * The keystore name. 199 * Case is not significant. 200 */ 201 private final String storeName; 202 203 KeyStore(String storeName) { 204 // Get the compatibility mode 205 String prop = 206 AccessController.doPrivileged( 207 new GetPropertyAction(KEYSTORE_COMPATIBILITY_MODE_PROP)); 208 209 if ("false".equalsIgnoreCase(prop)) { 210 keyStoreCompatibilityMode = false; 211 } else { 212 keyStoreCompatibilityMode = true; 213 } 214 215 this.storeName = storeName; 216 } 217 218 /** 219 * Returns the key associated with the given alias. 220 * <p> 221 * A compatibility mode is supported for applications that assume 222 * a password must be supplied. It permits (but ignores) a non-null 223 * <code>password</code>. The mode is enabled by default. 224 * Set the 225 * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> 226 * system property to <code>false</code> to disable compatibility mode 227 * and reject a non-null <code>password</code>. 228 * 229 * @param alias the alias name 230 * @param password the password, which should be <code>null</code> 231 * 232 * @return the requested key, or null if the given alias does not exist 233 * or does not identify a <i>key entry</i>. 234 * 235 * @exception NoSuchAlgorithmException if the algorithm for recovering the 236 * key cannot be found, 237 * or if compatibility mode is disabled and <code>password</code> is 238 * non-null. 239 * @exception UnrecoverableKeyException if the key cannot be recovered. 240 */ 241 public java.security.Key engineGetKey(String alias, char[] password) 242 throws NoSuchAlgorithmException, UnrecoverableKeyException 243 { 244 if (alias == null) { 245 return null; 246 } 247 248 if (password != null && !keyStoreCompatibilityMode) { 249 throw new UnrecoverableKeyException("Password must be null"); 250 } 251 252 if (engineIsKeyEntry(alias) == false) 253 return null; 254 255 KeyEntry entry = entries.get(alias); 256 return (entry == null) 257 ? null 258 : entry.getPrivateKey(); 259 } 260 261 /** 262 * Returns the certificate chain associated with the given alias. 263 * 264 * @param alias the alias name 265 * 266 * @return the certificate chain (ordered with the user's certificate first 267 * and the root certificate authority last), or null if the given alias 268 * does not exist or does not contain a certificate chain (i.e., the given 269 * alias identifies either a <i>trusted certificate entry</i> or a 270 * <i>key entry</i> without a certificate chain). 271 */ 272 public Certificate[] engineGetCertificateChain(String alias) 273 { 274 if (alias == null) { 275 return null; 276 } 277 278 KeyEntry entry = entries.get(alias); 279 X509Certificate[] certChain = (entry == null) 280 ? null 281 : entry.getCertificateChain(); 282 return (certChain == null) 283 ? null 284 : certChain.clone(); 285 } 286 287 /** 288 * Returns the certificate associated with the given alias. 289 * 290 * <p>If the given alias name identifies a 291 * <i>trusted certificate entry</i>, the certificate associated with that 292 * entry is returned. If the given alias name identifies a 293 * <i>key entry</i>, the first element of the certificate chain of that 294 * entry is returned, or null if that entry does not have a certificate 295 * chain. 296 * 297 * @param alias the alias name 298 * 299 * @return the certificate, or null if the given alias does not exist or 300 * does not contain a certificate. 301 */ 302 public Certificate engineGetCertificate(String alias) 303 { 304 if (alias == null) { 305 return null; 306 } 307 308 KeyEntry entry = entries.get(alias); 309 X509Certificate[] certChain = (entry == null) 310 ? null 311 : entry.getCertificateChain(); 312 return (certChain == null || certChain.length == 0) 313 ? null 314 : certChain[0]; 315 } 316 317 /** 318 * Returns the creation date of the entry identified by the given alias. 319 * 320 * @param alias the alias name 321 * 322 * @return the creation date of this entry, or null if the given alias does 323 * not exist 324 */ 325 public Date engineGetCreationDate(String alias) { 326 if (alias == null) { 327 return null; 328 } 329 return new Date(); 330 } 331 332 /** 333 * Stores the given private key and associated certificate chain in the 334 * keystore. 335 * 336 * <p>The given java.security.PrivateKey <code>key</code> must 337 * be accompanied by a certificate chain certifying the 338 * corresponding public key. 339 * 340 * <p>If the given alias already exists, the keystore information 341 * associated with it is overridden by the given key and certificate 342 * chain. Otherwise, a new entry is created. 343 * 344 * <p> 345 * A compatibility mode is supported for applications that assume 346 * a password must be supplied. It permits (but ignores) a non-null 347 * <code>password</code>. The mode is enabled by default. 348 * Set the 349 * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> 350 * system property to <code>false</code> to disable compatibility mode 351 * and reject a non-null <code>password</code>. 352 * 353 * @param alias the alias name 354 * @param key the private key to be associated with the alias 355 * @param password the password, which should be <code>null</code> 356 * @param chain the certificate chain for the corresponding public 357 * key (only required if the given key is of type 358 * <code>java.security.PrivateKey</code>). 359 * 360 * @exception KeyStoreException if the given key is not a private key, 361 * cannot be protected, or if compatibility mode is disabled and 362 * <code>password</code> is non-null, or if this operation fails for 363 * some other reason. 364 */ 365 public void engineSetKeyEntry(String alias, java.security.Key key, 366 char[] password, Certificate[] chain) throws KeyStoreException 367 { 368 if (alias == null) { 369 throw new KeyStoreException("alias must not be null"); 370 } 371 372 if (password != null && !keyStoreCompatibilityMode) { 373 throw new KeyStoreException("Password must be null"); 374 } 375 376 if (key instanceof RSAPrivateCrtKey) { 377 378 KeyEntry entry = entries.get(alias); 379 380 X509Certificate[] xchain; 381 if (chain != null) { 382 if (chain instanceof X509Certificate[]) { 383 xchain = (X509Certificate[]) chain; 384 } else { 385 xchain = new X509Certificate[chain.length]; 386 System.arraycopy(chain, 0, xchain, 0, chain.length); 387 } 388 } else { 389 xchain = null; 390 } 391 392 if (entry == null) { 393 entry = 394 //TODO new KeyEntry(alias, key, (X509Certificate[]) chain); 395 new KeyEntry(alias, null, xchain); 396 storeWithUniqueAlias(alias, entry); 397 } 398 399 entry.setAlias(alias); 400 401 try { 402 entry.setPrivateKey((RSAPrivateCrtKey) key); 403 entry.setCertificateChain(xchain); 404 405 } catch (CertificateException ce) { 406 throw new KeyStoreException(ce); 407 408 } catch (InvalidKeyException ike) { 409 throw new KeyStoreException(ike); 410 } 411 412 } else { 413 throw new UnsupportedOperationException( 414 "Cannot assign the key to the given alias."); 415 } 416 } 417 418 /** 419 * Assigns the given key (that has already been protected) to the given 420 * alias. 421 * 422 * <p>If the protected key is of type 423 * <code>java.security.PrivateKey</code>, it must be accompanied by a 424 * certificate chain certifying the corresponding public key. If the 425 * underlying keystore implementation is of type <code>jks</code>, 426 * <code>key</code> must be encoded as an 427 * <code>EncryptedPrivateKeyInfo</code> as defined in the PKCS #8 standard. 428 * 429 * <p>If the given alias already exists, the keystore information 430 * associated with it is overridden by the given key (and possibly 431 * certificate chain). 432 * 433 * @param alias the alias name 434 * @param key the key (in protected format) to be associated with the alias 435 * @param chain the certificate chain for the corresponding public 436 * key (only useful if the protected key is of type 437 * <code>java.security.PrivateKey</code>). 438 * 439 * @exception KeyStoreException if this operation fails. 440 */ 441 public void engineSetKeyEntry(String alias, byte[] key, 442 Certificate[] chain) 443 throws KeyStoreException 444 { 445 throw new UnsupportedOperationException( 446 "Cannot assign the encoded key to the given alias."); 447 } 448 449 /** 450 * Assigns the given certificate to the given alias. 451 * 452 * <p>If the given alias already exists in this keystore and identifies a 453 * <i>trusted certificate entry</i>, the certificate associated with it is 454 * overridden by the given certificate. 455 * 456 * @param alias the alias name 457 * @param cert the certificate 458 * 459 * @exception KeyStoreException if the given alias already exists and does 460 * not identify a <i>trusted certificate entry</i>, or this operation 461 * fails for some other reason. 462 */ 463 public void engineSetCertificateEntry(String alias, Certificate cert) 464 throws KeyStoreException 465 { 466 if (alias == null) { 467 throw new KeyStoreException("alias must not be null"); 468 } 469 470 if (cert instanceof X509Certificate) { 471 472 // TODO - build CryptoAPI chain? 473 X509Certificate[] chain = 474 new X509Certificate[]{ (X509Certificate) cert }; 475 KeyEntry entry = entries.get(alias); 476 477 if (entry == null) { 478 entry = 479 new KeyEntry(alias, null, chain); 480 storeWithUniqueAlias(alias, entry); 481 } 482 483 if (entry.getPrivateKey() == null) { // trusted-cert entry 484 entry.setAlias(alias); 485 486 try { 487 entry.setCertificateChain(chain); 488 489 } catch (CertificateException ce) { 490 throw new KeyStoreException(ce); 491 } 492 } 493 494 } else { 495 throw new UnsupportedOperationException( 496 "Cannot assign the certificate to the given alias."); 497 } 498 } 499 500 /** 501 * Deletes the entry identified by the given alias from this keystore. 502 * 503 * @param alias the alias name 504 * 505 * @exception KeyStoreException if the entry cannot be removed. 506 */ 507 public void engineDeleteEntry(String alias) 508 throws KeyStoreException 509 { 510 if (alias == null) { 511 throw new KeyStoreException("alias must not be null"); 512 } 513 514 KeyEntry entry = entries.remove(alias); 515 if (entry != null) { 516 // Get end-entity certificate and remove from system cert store 517 X509Certificate[] certChain = entry.getCertificateChain(); 518 if (certChain != null) { 519 520 try { 521 522 byte[] encoding = certChain[0].getEncoded(); 523 removeCertificate(getName(), entry.getAlias(), encoding, 524 encoding.length); 525 526 } catch (CertificateException e) { 527 throw new KeyStoreException("Cannot remove entry: ", e); 528 } 529 } 530 Key privateKey = entry.getPrivateKey(); 531 if (privateKey != null) { 532 destroyKeyContainer( 533 Key.getContainerName(privateKey.getHCryptProvider())); 534 } 535 } 536 } 537 538 /** 539 * Lists all the alias names of this keystore. 540 * 541 * @return enumeration of the alias names 542 */ 543 public Enumeration<String> engineAliases() { 544 final Iterator<String> iter = entries.keySet().iterator(); 545 546 return new Enumeration<String>() 547 { 548 public boolean hasMoreElements() 549 { 550 return iter.hasNext(); 551 } 552 553 public String nextElement() 554 { 555 return iter.next(); 556 } 557 }; 558 } 559 560 /** 561 * Checks if the given alias exists in this keystore. 562 * 563 * @param alias the alias name 564 * 565 * @return true if the alias exists, false otherwise 566 */ 567 public boolean engineContainsAlias(String alias) { 568 return entries.containsKey(alias); 569 } 570 571 /** 572 * Retrieves the number of entries in this keystore. 573 * 574 * @return the number of entries in this keystore 575 */ 576 public int engineSize() { 577 return entries.size(); 578 } 579 580 /** 581 * Returns true if the entry identified by the given alias is a 582 * <i>key entry</i>, and false otherwise. 583 * 584 * @return true if the entry identified by the given alias is a 585 * <i>key entry</i>, false otherwise. 586 */ 587 public boolean engineIsKeyEntry(String alias) { 588 589 if (alias == null) { 590 return false; 591 } 592 593 KeyEntry entry = entries.get(alias); 594 return entry != null && entry.getPrivateKey() != null; 595 } 596 597 /** 598 * Returns true if the entry identified by the given alias is a 599 * <i>trusted certificate entry</i>, and false otherwise. 600 * 601 * @return true if the entry identified by the given alias is a 602 * <i>trusted certificate entry</i>, false otherwise. 603 */ 604 public boolean engineIsCertificateEntry(String alias) { 605 606 if (alias == null) { 607 return false; 608 } 609 610 KeyEntry entry = entries.get(alias); 611 return entry != null && entry.getPrivateKey() == null; 612 } 613 614 /** 615 * Returns the (alias) name of the first keystore entry whose certificate 616 * matches the given certificate. 617 * 618 * <p>This method attempts to match the given certificate with each 619 * keystore entry. If the entry being considered 620 * is a <i>trusted certificate entry</i>, the given certificate is 621 * compared to that entry's certificate. If the entry being considered is 622 * a <i>key entry</i>, the given certificate is compared to the first 623 * element of that entry's certificate chain (if a chain exists). 624 * 625 * @param cert the certificate to match with. 626 * 627 * @return the (alias) name of the first entry with matching certificate, 628 * or null if no such entry exists in this keystore. 629 */ 630 public String engineGetCertificateAlias(Certificate cert) { 631 632 for (Map.Entry<String,KeyEntry> mapEntry : entries.entrySet()) { 633 KeyEntry entry = mapEntry.getValue(); 634 if (entry.certChain != null && entry.certChain[0].equals(cert)) { 635 return entry.getAlias(); 636 } 637 } 638 639 return null; 640 } 641 642 /** 643 * engineStore is currently a no-op. 644 * Entries are stored during engineSetEntry. 645 * 646 * A compatibility mode is supported for applications that assume 647 * keystores are stream-based. It permits (but ignores) a non-null 648 * <code>stream</code> or <code>password</code>. 649 * The mode is enabled by default. 650 * Set the 651 * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> 652 * system property to <code>false</code> to disable compatibility mode 653 * and reject a non-null <code>stream</code> or <code>password</code>. 654 * 655 * @param stream the output stream, which should be <code>null</code> 656 * @param password the password, which should be <code>null</code> 657 * 658 * @exception IOException if compatibility mode is disabled and either 659 * parameter is non-null. 660 */ 661 public void engineStore(OutputStream stream, char[] password) 662 throws IOException, NoSuchAlgorithmException, CertificateException 663 { 664 if (stream != null && !keyStoreCompatibilityMode) { 665 throw new IOException("Keystore output stream must be null"); 666 } 667 668 if (password != null && !keyStoreCompatibilityMode) { 669 throw new IOException("Keystore password must be null"); 670 } 671 } 672 673 /** 674 * Loads the keystore. 675 * 676 * A compatibility mode is supported for applications that assume 677 * keystores are stream-based. It permits (but ignores) a non-null 678 * <code>stream</code> or <code>password</code>. 679 * The mode is enabled by default. 680 * Set the 681 * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> 682 * system property to <code>false</code> to disable compatibility mode 683 * and reject a non-null <code>stream</code> or <code>password</code>. 684 * 685 * @param stream the input stream, which should be <code>null</code>. 686 * @param password the password, which should be <code>null</code>. 687 * 688 * @exception IOException if there is an I/O or format problem with the 689 * keystore data. Or if compatibility mode is disabled and either 690 * parameter is non-null. 691 * @exception NoSuchAlgorithmException if the algorithm used to check 692 * the integrity of the keystore cannot be found 693 * @exception CertificateException if any of the certificates in the 694 * keystore could not be loaded 695 * @exception SecurityException if the security check for 696 * <code>SecurityPermission("authProvider.<i>name</i>")</code> does not 697 * pass, where <i>name</i> is the value returned by 698 * this provider's <code>getName</code> method. 699 */ 700 public void engineLoad(InputStream stream, char[] password) 701 throws IOException, NoSuchAlgorithmException, CertificateException 702 { 703 if (stream != null && !keyStoreCompatibilityMode) { 704 throw new IOException("Keystore input stream must be null"); 705 } 706 707 if (password != null && !keyStoreCompatibilityMode) { 708 throw new IOException("Keystore password must be null"); 709 } 710 711 /* 712 * Use the same security check as AuthProvider.login 713 */ 714 SecurityManager sm = System.getSecurityManager(); 715 if (sm != null) { 716 sm.checkPermission(new SecurityPermission( 717 "authProvider.SunMSCAPI")); 718 } 719 720 // Clear all key entries 721 entries.clear(); 722 723 try { 724 725 // Load keys and/or certificate chains 726 loadKeysOrCertificateChains(getName()); 727 728 } catch (KeyStoreException e) { 729 throw new IOException(e); 730 } 731 } 732 733 /** 734 * Stores the given entry into the map, making sure 735 * the alias, used as the key is unique. 736 * If the same alias already exists, it tries to append 737 * a suffix (1), (2), etc to it until it finds a unique 738 * value. 739 */ 740 private void storeWithUniqueAlias(String alias, KeyEntry entry) { 741 String uniqAlias = alias; 742 int uniqNum = 1; 743 744 while (true) { 745 if (entries.putIfAbsent(uniqAlias, entry) == null) { 746 break; 747 } 748 uniqAlias = alias + " (" + (uniqNum++) + ")"; 749 } 750 } 751 752 753 /** 754 * Generates a certificate chain from the collection of 755 * certificates and stores the result into a key entry. 756 * This method is called by native code in libsunmscapi. 757 */ 758 private void generateCertificateChain(String alias, 759 Collection<? extends Certificate> certCollection) 760 { 761 try 762 { 763 X509Certificate[] certChain = 764 new X509Certificate[certCollection.size()]; 765 766 int i = 0; 767 for (Iterator<? extends Certificate> iter = 768 certCollection.iterator(); iter.hasNext(); i++) 769 { 770 certChain[i] = (X509Certificate) iter.next(); 771 } 772 773 storeWithUniqueAlias(alias, 774 new KeyEntry(alias, null, certChain)); 775 } 776 catch (Throwable e) 777 { 778 // Ignore the exception and skip this entry 779 // If e is thrown, remember to deal with it in 780 // native code. 781 } 782 } 783 784 /** 785 * Generates RSA key and certificate chain from the private key handle, 786 * collection of certificates and stores the result into key entries. 787 * This method is called by native code in libsunmscapi. 788 */ 789 private void generateRSAKeyAndCertificateChain(String alias, 790 long hCryptProv, long hCryptKey, int keyLength, 791 Collection<? extends Certificate> certCollection) 792 { 793 try 794 { 795 X509Certificate[] certChain = 796 new X509Certificate[certCollection.size()]; 797 798 int i = 0; 799 for (Iterator<? extends Certificate> iter = 800 certCollection.iterator(); iter.hasNext(); i++) 801 { 802 certChain[i] = (X509Certificate) iter.next(); 803 } 804 805 storeWithUniqueAlias(alias, new KeyEntry(alias, 806 new RSAPrivateKey(new Key.NativeHandles(hCryptProv, 807 hCryptKey), keyLength), 808 certChain)); 809 } 810 catch (Throwable e) 811 { 812 // Ignore the exception and skip this entry 813 // If e is thrown, remember to deal with it in 814 // native code. 815 } 816 } 817 818 /** 819 * Generates certificates from byte data and stores into cert collection. 820 * This method is called by native code in libsunmscapi. 821 * 822 * @param data Byte data. 823 * @param certCollection Collection of certificates. 824 */ 825 private void generateCertificate(byte[] data, 826 Collection<Certificate> certCollection) { 827 try 828 { 829 ByteArrayInputStream bis = new ByteArrayInputStream(data); 830 831 // Obtain certificate factory 832 if (certificateFactory == null) { 833 certificateFactory = CertificateFactory.getInstance("X.509", "SUN"); 834 } 835 836 // Generate certificate 837 Collection<? extends Certificate> c = 838 certificateFactory.generateCertificates(bis); 839 certCollection.addAll(c); 840 } 841 catch (CertificateException e) 842 { 843 // Ignore the exception and skip this certificate 844 // If e is thrown, remember to deal with it in 845 // native code. 846 } 847 catch (Throwable te) 848 { 849 // Ignore the exception and skip this certificate 850 // If e is thrown, remember to deal with it in 851 // native code. 852 } 853 } 854 855 /** 856 * Returns the name of the keystore. 857 */ 858 private String getName() 859 { 860 return storeName; 861 } 862 863 /** 864 * Load keys and/or certificates from keystore into Collection. 865 * 866 * @param name Name of keystore. 867 */ 868 private native void loadKeysOrCertificateChains(String name) 869 throws KeyStoreException; 870 871 /** 872 * Stores a DER-encoded certificate into the certificate store 873 * 874 * @param name Name of the keystore. 875 * @param alias Name of the certificate. 876 * @param encoding DER-encoded certificate. 877 */ 878 private native void storeCertificate(String name, String alias, 879 byte[] encoding, int encodingLength, long hCryptProvider, 880 long hCryptKey) throws CertificateException, KeyStoreException; 881 882 /** 883 * Removes the certificate from 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 removeCertificate(String name, String alias, 890 byte[] encoding, int encodingLength) 891 throws CertificateException, KeyStoreException; 892 893 /** 894 * Destroys the key container. 895 * 896 * @param keyContainerName The name of the key container. 897 */ 898 private native void destroyKeyContainer(String keyContainerName) 899 throws KeyStoreException; 900 901 /** 902 * Generates a private-key BLOB from a key's components. 903 */ 904 private native byte[] generatePrivateKeyBlob( 905 int keyBitLength, 906 byte[] modulus, 907 byte[] publicExponent, 908 byte[] privateExponent, 909 byte[] primeP, 910 byte[] primeQ, 911 byte[] exponentP, 912 byte[] exponentQ, 913 byte[] crtCoefficient) throws InvalidKeyException; 914 915 private native RSAPrivateKey storePrivateKey(byte[] keyBlob, 916 String keyContainerName, int keySize) throws KeyStoreException; 917 }