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