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 if (! found) { 393 entry = 394 //TODO new KeyEntry(alias, key, (X509Certificate[]) chain); 395 new KeyEntry(alias, null, (X509Certificate[]) chain); 396 entries.add(entry); 397 } 398 399 entry.setAlias(alias); 400 401 try { 402 entry.setPrivateKey((RSAPrivateCrtKey) key); 403 entry.setCertificateChain((X509Certificate[]) chain); 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 = null; 476 boolean found = false; 477 478 for (KeyEntry e : entries) { 479 if (alias.equals(e.getAlias())) { 480 found = true; 481 entry = e; 482 break; 483 } 484 } 485 486 if (! found) { 487 entry = 488 new KeyEntry(alias, null, chain); 489 entries.add(entry); 490 491 } 492 if (entry.getPrivateKey() == null) { // trusted-cert entry 493 entry.setAlias(alias); 494 495 try { 496 entry.setCertificateChain(chain); 497 498 } catch (CertificateException ce) { 499 throw new KeyStoreException(ce); 500 } 501 } 502 503 } else { 504 throw new UnsupportedOperationException( 505 "Cannot assign the certificate to the given alias."); 506 } 507 } 508 509 /** 510 * Deletes the entry identified by the given alias from this keystore. 511 * 512 * @param alias the alias name 513 * 514 * @exception KeyStoreException if the entry cannot be removed. 515 */ 516 public void engineDeleteEntry(String alias) 517 throws KeyStoreException 518 { 519 if (alias == null) { 520 throw new KeyStoreException("alias must not be null"); 521 } 522 523 for (KeyEntry entry : entries) { 524 if (alias.equals(entry.getAlias())) { 525 526 // Get end-entity certificate and remove from system cert store 527 X509Certificate[] certChain = entry.getCertificateChain(); 528 if (certChain != null) { 529 530 try { 531 532 byte[] encoding = certChain[0].getEncoded(); 533 removeCertificate(getName(), alias, encoding, 534 encoding.length); 535 536 } catch (CertificateException e) { 537 throw new KeyStoreException("Cannot remove entry: " + 538 e); 539 } 540 } 541 Key privateKey = entry.getPrivateKey(); 542 if (privateKey != null) { 543 destroyKeyContainer( 544 Key.getContainerName(privateKey.getHCryptProvider())); 545 } 546 547 entries.remove(entry); 548 break; 549 } 550 } 551 } 552 553 /** 554 * Lists all the alias names of this keystore. 555 * 556 * @return enumeration of the alias names 557 */ 558 public Enumeration<String> engineAliases() { 559 560 final Iterator<KeyEntry> iter = entries.iterator(); 561 562 return new Enumeration<String>() 563 { 564 public boolean hasMoreElements() 565 { 566 return iter.hasNext(); 567 } 568 569 public String nextElement() 570 { 571 KeyEntry entry = iter.next(); 572 return entry.getAlias(); 573 } 574 }; 575 } 576 577 /** 578 * Checks if the given alias exists in this keystore. 579 * 580 * @param alias the alias name 581 * 582 * @return true if the alias exists, false otherwise 583 */ 584 public boolean engineContainsAlias(String alias) { 585 for (Enumeration<String> enumerator = engineAliases(); 586 enumerator.hasMoreElements();) 587 { 588 String a = enumerator.nextElement(); 589 590 if (a.equals(alias)) 591 return true; 592 } 593 return false; 594 } 595 596 /** 597 * Retrieves the number of entries in this keystore. 598 * 599 * @return the number of entries in this keystore 600 */ 601 public int engineSize() { 602 return entries.size(); 603 } 604 605 /** 606 * Returns true if the entry identified by the given alias is a 607 * <i>key entry</i>, and false otherwise. 608 * 609 * @return true if the entry identified by the given alias is a 610 * <i>key entry</i>, false otherwise. 611 */ 612 public boolean engineIsKeyEntry(String alias) { 613 614 if (alias == null) { 615 return false; 616 } 617 618 for (KeyEntry entry : entries) { 619 if (alias.equals(entry.getAlias())) { 620 return entry.getPrivateKey() != null; 621 } 622 } 623 624 return false; 625 } 626 627 /** 628 * Returns true if the entry identified by the given alias is a 629 * <i>trusted certificate entry</i>, and false otherwise. 630 * 631 * @return true if the entry identified by the given alias is a 632 * <i>trusted certificate entry</i>, false otherwise. 633 */ 634 public boolean engineIsCertificateEntry(String alias) 635 { 636 for (KeyEntry entry : entries) { 637 if (alias.equals(entry.getAlias())) { 638 return entry.getPrivateKey() == null; 639 } 640 } 641 642 return false; 643 } 644 645 /** 646 * Returns the (alias) name of the first keystore entry whose certificate 647 * matches the given certificate. 648 * 649 * <p>This method attempts to match the given certificate with each 650 * keystore entry. If the entry being considered 651 * is a <i>trusted certificate entry</i>, the given certificate is 652 * compared to that entry's certificate. If the entry being considered is 653 * a <i>key entry</i>, the given certificate is compared to the first 654 * element of that entry's certificate chain (if a chain exists). 655 * 656 * @param cert the certificate to match with. 657 * 658 * @return the (alias) name of the first entry with matching certificate, 659 * or null if no such entry exists in this keystore. 660 */ 661 public String engineGetCertificateAlias(Certificate cert) 662 { 663 for (KeyEntry entry : entries) { 664 if (entry.certChain != null && entry.certChain[0].equals(cert)) { 665 return entry.getAlias(); 666 } 667 } 668 669 return null; 670 } 671 672 /** 673 * engineStore is currently a no-op. 674 * Entries are stored during engineSetEntry. 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 output stream, which should be <code>null</code> 686 * @param password the password, which should be <code>null</code> 687 * 688 * @exception IOException if compatibility mode is disabled and either 689 * parameter is non-null. 690 */ 691 public void engineStore(OutputStream stream, char[] password) 692 throws IOException, NoSuchAlgorithmException, CertificateException 693 { 694 if (stream != null && !keyStoreCompatibilityMode) { 695 throw new IOException("Keystore output stream must be null"); 696 } 697 698 if (password != null && !keyStoreCompatibilityMode) { 699 throw new IOException("Keystore password must be null"); 700 } 701 } 702 703 /** 704 * Loads the keystore. 705 * 706 * A compatibility mode is supported for applications that assume 707 * keystores are stream-based. It permits (but ignores) a non-null 708 * <code>stream</code> or <code>password</code>. 709 * The mode is enabled by default. 710 * Set the 711 * <code>sun.security.mscapi.keyStoreCompatibilityMode</code> 712 * system property to <code>false</code> to disable compatibility mode 713 * and reject a non-null <code>stream</code> or <code>password</code>. 714 * 715 * @param stream the input stream, which should be <code>null</code>. 716 * @param password the password, which should be <code>null</code>. 717 * 718 * @exception IOException if there is an I/O or format problem with the 719 * keystore data. Or if compatibility mode is disabled and either 720 * parameter is non-null. 721 * @exception NoSuchAlgorithmException if the algorithm used to check 722 * the integrity of the keystore cannot be found 723 * @exception CertificateException if any of the certificates in the 724 * keystore could not be loaded 725 * @exception SecurityException if the security check for 726 * <code>SecurityPermission("authProvider.<i>name</i>")</code> does not 727 * pass, where <i>name</i> is the value returned by 728 * this provider's <code>getName</code> method. 729 */ 730 public void engineLoad(InputStream stream, char[] password) 731 throws IOException, NoSuchAlgorithmException, CertificateException 732 { 733 if (stream != null && !keyStoreCompatibilityMode) { 734 throw new IOException("Keystore input stream must be null"); 735 } 736 737 if (password != null && !keyStoreCompatibilityMode) { 738 throw new IOException("Keystore password must be null"); 739 } 740 741 /* 742 * Use the same security check as AuthProvider.login 743 */ 744 SecurityManager sm = System.getSecurityManager(); 745 if (sm != null) { 746 sm.checkPermission(new SecurityPermission( 747 "authProvider.SunMSCAPI")); 748 } 749 750 // Clear all key entries 751 entries.clear(); 752 753 try { 754 755 // Load keys and/or certificate chains 756 loadKeysOrCertificateChains(getName(), entries); 757 758 } catch (KeyStoreException e) { 759 throw new IOException(e); 760 } 761 } 762 763 /** 764 * Generates a certificate chain from the collection of 765 * certificates and stores the result into a key entry. 766 */ 767 private void generateCertificateChain(String alias, 768 Collection<? extends Certificate> certCollection, 769 Collection<KeyEntry> entries) 770 { 771 try 772 { 773 X509Certificate[] certChain = 774 new X509Certificate[certCollection.size()]; 775 776 int i = 0; 777 for (Iterator<? extends Certificate> iter = 778 certCollection.iterator(); iter.hasNext(); i++) 779 { 780 certChain[i] = (X509Certificate) iter.next(); 781 } 782 783 KeyEntry entry = new KeyEntry(alias, null, certChain); 784 785 // Add cert chain 786 entries.add(entry); 787 } 788 catch (Throwable e) 789 { 790 // Ignore the exception and skip this entry 791 // TODO - throw CertificateException? 792 } 793 } 794 795 /** 796 * Generates RSA key and certificate chain from the private key handle, 797 * collection of certificates and stores the result into key entries. 798 */ 799 private void generateRSAKeyAndCertificateChain(String alias, 800 long hCryptProv, long hCryptKey, int keyLength, 801 Collection<? extends Certificate> certCollection, 802 Collection<KeyEntry> entries) 803 { 804 try 805 { 806 X509Certificate[] certChain = 807 new X509Certificate[certCollection.size()]; 808 809 int i = 0; 810 for (Iterator<? extends Certificate> iter = 811 certCollection.iterator(); iter.hasNext(); i++) 812 { 813 certChain[i] = (X509Certificate) iter.next(); 814 } 815 816 KeyEntry entry = new KeyEntry(alias, new RSAPrivateKey(hCryptProv, 817 hCryptKey, keyLength), certChain); 818 819 // Add cert chain 820 entries.add(entry); 821 } 822 catch (Throwable e) 823 { 824 // Ignore the exception and skip this entry 825 // TODO - throw CertificateException? 826 } 827 } 828 829 /** 830 * Generates certificates from byte data and stores into cert collection. 831 * 832 * @param data Byte data. 833 * @param certCollection Collection of certificates. 834 */ 835 private void generateCertificate(byte[] data, 836 Collection<Certificate> certCollection) { 837 try 838 { 839 ByteArrayInputStream bis = new ByteArrayInputStream(data); 840 841 // Obtain certificate factory 842 if (certificateFactory == null) { 843 certificateFactory = CertificateFactory.getInstance("X.509", "SUN"); 844 } 845 846 // Generate certificate 847 Collection<? extends Certificate> c = 848 certificateFactory.generateCertificates(bis); 849 certCollection.addAll(c); 850 } 851 catch (CertificateException e) 852 { 853 // Ignore the exception and skip this certificate 854 // TODO - throw CertificateException? 855 } 856 catch (Throwable te) 857 { 858 // Ignore the exception and skip this certificate 859 // TODO - throw CertificateException? 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 * @param entries Collection of key/certificate. 876 */ 877 private native void loadKeysOrCertificateChains(String name, 878 Collection<KeyEntry> entries) throws KeyStoreException; 879 880 /** 881 * Stores a DER-encoded certificate into the certificate store 882 * 883 * @param name Name of the keystore. 884 * @param alias Name of the certificate. 885 * @param encoding DER-encoded certificate. 886 */ 887 private native void storeCertificate(String name, String alias, 888 byte[] encoding, int encodingLength, long hCryptProvider, 889 long hCryptKey) throws CertificateException, KeyStoreException; 890 891 /** 892 * Removes the certificate from the certificate store 893 * 894 * @param name Name of the keystore. 895 * @param alias Name of the certificate. 896 * @param encoding DER-encoded certificate. 897 */ 898 private native void removeCertificate(String name, String alias, 899 byte[] encoding, int encodingLength) 900 throws CertificateException, KeyStoreException; 901 902 /** 903 * Destroys the key container. 904 * 905 * @param keyContainerName The name of the key container. 906 */ 907 private native void destroyKeyContainer(String keyContainerName) 908 throws KeyStoreException; 909 910 /** 911 * Generates a private-key BLOB from a key's components. 912 */ 913 private native byte[] generatePrivateKeyBlob( 914 int keyBitLength, 915 byte[] modulus, 916 byte[] publicExponent, 917 byte[] privateExponent, 918 byte[] primeP, 919 byte[] primeQ, 920 byte[] exponentP, 921 byte[] exponentQ, 922 byte[] crtCoefficient) throws InvalidKeyException; 923 924 private native RSAPrivateKey storePrivateKey(byte[] keyBlob, 925 String keyContainerName, int keySize) throws KeyStoreException; 926 }