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