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 }