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