1 /*
   2  * Copyright (c) 2003, 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.pkcs11;
  27 
  28 import java.io.*;
  29 import java.util.*;
  30 
  31 import java.security.*;
  32 import java.security.interfaces.*;
  33 
  34 import javax.crypto.interfaces.*;
  35 
  36 import javax.security.auth.Subject;
  37 import javax.security.auth.login.LoginException;
  38 import javax.security.auth.login.FailedLoginException;
  39 import javax.security.auth.callback.Callback;
  40 import javax.security.auth.callback.CallbackHandler;
  41 import javax.security.auth.callback.ConfirmationCallback;
  42 import javax.security.auth.callback.PasswordCallback;
  43 import javax.security.auth.callback.TextOutputCallback;
  44 
  45 import sun.misc.ManagedLocalsThread;
  46 import sun.security.util.Debug;
  47 import sun.security.util.ResourcesMgr;
  48 
  49 import sun.security.pkcs11.Secmod.*;
  50 
  51 import sun.security.pkcs11.wrapper.*;
  52 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
  53 
  54 /**
  55  * PKCS#11 provider main class.
  56  *
  57  * @author  Andreas Sterbenz
  58  * @since   1.5
  59  */
  60 public final class SunPKCS11 extends AuthProvider {
  61 
  62     private static final long serialVersionUID = -1354835039035306505L;
  63 
  64     static final Debug debug = Debug.getInstance("sunpkcs11");
  65 
  66     private static int dummyConfigId;
  67 
  68     // the PKCS11 object through which we make the native calls
  69     final PKCS11 p11;
  70 
  71     // name of the configuration file
  72     private final String configName;
  73 
  74     // configuration information
  75     final Config config;
  76 
  77     // id of the PKCS#11 slot we are using
  78     final long slotID;
  79 
  80     private CallbackHandler pHandler;
  81     private final Object LOCK_HANDLER = new Object();
  82 
  83     final boolean removable;
  84 
  85     final Module nssModule;
  86 
  87     final boolean nssUseSecmodTrust;
  88 
  89     private volatile Token token;
  90 
  91     private TokenPoller poller;
  92 
  93     Token getToken() {
  94         return token;
  95     }
  96 
  97     public SunPKCS11() {
  98         super("SunPKCS11-Dummy", 1.9d, "SunPKCS11-Dummy");
  99         throw new ProviderException
 100             ("SunPKCS11 requires configuration file argument");
 101     }
 102 
 103     public SunPKCS11(String configName) {
 104         this(checkNull(configName), null);
 105     }
 106 
 107     public SunPKCS11(InputStream configStream) {
 108         this(getDummyConfigName(), checkNull(configStream));
 109     }
 110 
 111     private static <T> T checkNull(T obj) {
 112         if (obj == null) {
 113             throw new NullPointerException();
 114         }
 115         return obj;
 116     }
 117 
 118     private static synchronized String getDummyConfigName() {
 119         int id = ++dummyConfigId;
 120         return "---DummyConfig-" + id + "---";
 121     }
 122 
 123     /**
 124      * @deprecated use new SunPKCS11(String) or new SunPKCS11(InputStream)
 125      *         instead
 126      */
 127     @Deprecated
 128     public SunPKCS11(String configName, InputStream configStream) {
 129         super("SunPKCS11-" +
 130             Config.getConfig(configName, configStream).getName(),
 131             1.9d, Config.getConfig(configName, configStream).getDescription());
 132         this.configName = configName;
 133         this.config = Config.removeConfig(configName);
 134 
 135         if (debug != null) {
 136             System.out.println("SunPKCS11 loading " + configName);
 137         }
 138 
 139         String library = config.getLibrary();
 140         String functionList = config.getFunctionList();
 141         long slotID = config.getSlotID();
 142         int slotListIndex = config.getSlotListIndex();
 143 
 144         boolean useSecmod = config.getNssUseSecmod();
 145         boolean nssUseSecmodTrust = config.getNssUseSecmodTrust();
 146         Module nssModule = null;
 147 
 148         //
 149         // Initialization via Secmod. The way this works is as follows:
 150         // SunPKCS11 is either in normal mode or in NSS Secmod mode.
 151         // Secmod is activated by specifying one or more of the following
 152         // options in the config file:
 153         // nssUseSecmod, nssSecmodDirectory, nssLibrary, nssModule
 154         //
 155         // XXX add more explanation here
 156         //
 157         // If we are in Secmod mode and configured to use either the
 158         // nssKeyStore or the nssTrustAnchors module, we automatically
 159         // switch to using the NSS trust attributes for trusted certs
 160         // (KeyStore).
 161         //
 162 
 163         if (useSecmod) {
 164             // note: Config ensures library/slot/slotListIndex not specified
 165             // in secmod mode.
 166             Secmod secmod = Secmod.getInstance();
 167             DbMode nssDbMode = config.getNssDbMode();
 168             try {
 169                 String nssLibraryDirectory = config.getNssLibraryDirectory();
 170                 String nssSecmodDirectory = config.getNssSecmodDirectory();
 171                 boolean nssOptimizeSpace = config.getNssOptimizeSpace();
 172 
 173                 if (secmod.isInitialized()) {
 174                     if (nssSecmodDirectory != null) {
 175                         String s = secmod.getConfigDir();
 176                         if ((s != null) &&
 177                                 (s.equals(nssSecmodDirectory) == false)) {
 178                             throw new ProviderException("Secmod directory "
 179                                 + nssSecmodDirectory
 180                                 + " invalid, NSS already initialized with "
 181                                 + s);
 182                         }
 183                     }
 184                     if (nssLibraryDirectory != null) {
 185                         String s = secmod.getLibDir();
 186                         if ((s != null) &&
 187                                 (s.equals(nssLibraryDirectory) == false)) {
 188                             throw new ProviderException("NSS library directory "
 189                                 + nssLibraryDirectory
 190                                 + " invalid, NSS already initialized with "
 191                                 + s);
 192                         }
 193                     }
 194                 } else {
 195                     if (nssDbMode != DbMode.NO_DB) {
 196                         if (nssSecmodDirectory == null) {
 197                             throw new ProviderException(
 198                                 "Secmod not initialized and "
 199                                  + "nssSecmodDirectory not specified");
 200                         }
 201                     } else {
 202                         if (nssSecmodDirectory != null) {
 203                             throw new ProviderException(
 204                                 "nssSecmodDirectory must not be "
 205                                 + "specified in noDb mode");
 206                         }
 207                     }
 208                     secmod.initialize(nssDbMode, nssSecmodDirectory,
 209                         nssLibraryDirectory, nssOptimizeSpace);
 210                 }
 211             } catch (IOException e) {
 212                 // XXX which exception to throw
 213                 throw new ProviderException("Could not initialize NSS", e);
 214             }
 215             List<Module> modules = secmod.getModules();
 216             if (config.getShowInfo()) {
 217                 System.out.println("NSS modules: " + modules);
 218             }
 219 
 220             String moduleName = config.getNssModule();
 221             if (moduleName == null) {
 222                 nssModule = secmod.getModule(ModuleType.FIPS);
 223                 if (nssModule != null) {
 224                     moduleName = "fips";
 225                 } else {
 226                     moduleName = (nssDbMode == DbMode.NO_DB) ?
 227                         "crypto" : "keystore";
 228                 }
 229             }
 230             if (moduleName.equals("fips")) {
 231                 nssModule = secmod.getModule(ModuleType.FIPS);
 232                 nssUseSecmodTrust = true;
 233                 functionList = "FC_GetFunctionList";
 234             } else if (moduleName.equals("keystore")) {
 235                 nssModule = secmod.getModule(ModuleType.KEYSTORE);
 236                 nssUseSecmodTrust = true;
 237             } else if (moduleName.equals("crypto")) {
 238                 nssModule = secmod.getModule(ModuleType.CRYPTO);
 239             } else if (moduleName.equals("trustanchors")) {
 240                 // XXX should the option be called trustanchor or trustanchors??
 241                 nssModule = secmod.getModule(ModuleType.TRUSTANCHOR);
 242                 nssUseSecmodTrust = true;
 243             } else if (moduleName.startsWith("external-")) {
 244                 int moduleIndex;
 245                 try {
 246                     moduleIndex = Integer.parseInt
 247                             (moduleName.substring("external-".length()));
 248                 } catch (NumberFormatException e) {
 249                     moduleIndex = -1;
 250                 }
 251                 if (moduleIndex < 1) {
 252                     throw new ProviderException
 253                             ("Invalid external module: " + moduleName);
 254                 }
 255                 int k = 0;
 256                 for (Module module : modules) {
 257                     if (module.getType() == ModuleType.EXTERNAL) {
 258                         if (++k == moduleIndex) {
 259                             nssModule = module;
 260                             break;
 261                         }
 262                     }
 263                 }
 264                 if (nssModule == null) {
 265                     throw new ProviderException("Invalid module " + moduleName
 266                         + ": only " + k + " external NSS modules available");
 267                 }
 268             } else {
 269                 throw new ProviderException(
 270                     "Unknown NSS module: " + moduleName);
 271             }
 272             if (nssModule == null) {
 273                 throw new ProviderException(
 274                     "NSS module not available: " + moduleName);
 275             }
 276             if (nssModule.hasInitializedProvider()) {
 277                 throw new ProviderException("Secmod module already configured");
 278             }
 279             library = nssModule.libraryName;
 280             slotListIndex = nssModule.slot;
 281         }
 282         this.nssUseSecmodTrust = nssUseSecmodTrust;
 283         this.nssModule = nssModule;
 284 
 285         File libraryFile = new File(library);
 286         // if the filename is a simple filename without path
 287         // (e.g. "libpkcs11.so"), it may refer to a library somewhere on the
 288         // OS library search path. Omit the test for file existance as that
 289         // only looks in the current directory.
 290         if (libraryFile.getName().equals(library) == false) {
 291             if (new File(library).isFile() == false) {
 292                 String msg = "Library " + library + " does not exist";
 293                 if (config.getHandleStartupErrors() == Config.ERR_HALT) {
 294                     throw new ProviderException(msg);
 295                 } else {
 296                     throw new UnsupportedOperationException(msg);
 297                 }
 298             }
 299         }
 300 
 301         try {
 302             if (debug != null) {
 303                 debug.println("Initializing PKCS#11 library " + library);
 304             }
 305             CK_C_INITIALIZE_ARGS initArgs = new CK_C_INITIALIZE_ARGS();
 306             String nssArgs = config.getNssArgs();
 307             if (nssArgs != null) {
 308                 initArgs.pReserved = nssArgs;
 309             }
 310             // request multithreaded access first
 311             initArgs.flags = CKF_OS_LOCKING_OK;
 312             PKCS11 tmpPKCS11;
 313             try {
 314                 tmpPKCS11 = PKCS11.getInstance(
 315                     library, functionList, initArgs,
 316                     config.getOmitInitialize());
 317             } catch (PKCS11Exception e) {
 318                 if (debug != null) {
 319                     debug.println("Multi-threaded initialization failed: " + e);
 320                 }
 321                 if (config.getAllowSingleThreadedModules() == false) {
 322                     throw e;
 323                 }
 324                 // fall back to single threaded access
 325                 if (nssArgs == null) {
 326                     // if possible, use null initArgs for better compatibility
 327                     initArgs = null;
 328                 } else {
 329                     initArgs.flags = 0;
 330                 }
 331                 tmpPKCS11 = PKCS11.getInstance(library,
 332                     functionList, initArgs, config.getOmitInitialize());
 333             }
 334             p11 = tmpPKCS11;
 335 
 336             CK_INFO p11Info = p11.C_GetInfo();
 337             if (p11Info.cryptokiVersion.major < 2) {
 338                 throw new ProviderException("Only PKCS#11 v2.0 and later "
 339                 + "supported, library version is v" + p11Info.cryptokiVersion);
 340             }
 341             boolean showInfo = config.getShowInfo();
 342             if (showInfo) {
 343                 System.out.println("Information for provider " + getName());
 344                 System.out.println("Library info:");
 345                 System.out.println(p11Info);
 346             }
 347 
 348             if ((slotID < 0) || showInfo) {
 349                 long[] slots = p11.C_GetSlotList(false);
 350                 if (showInfo) {
 351                     System.out.println("All slots: " + toString(slots));
 352                     slots = p11.C_GetSlotList(true);
 353                     System.out.println("Slots with tokens: " + toString(slots));
 354                 }
 355                 if (slotID < 0) {
 356                     if ((slotListIndex < 0)
 357                             || (slotListIndex >= slots.length)) {
 358                         throw new ProviderException("slotListIndex is "
 359                             + slotListIndex
 360                             + " but token only has " + slots.length + " slots");
 361                     }
 362                     slotID = slots[slotListIndex];
 363                 }
 364             }
 365             this.slotID = slotID;
 366             CK_SLOT_INFO slotInfo = p11.C_GetSlotInfo(slotID);
 367             removable = (slotInfo.flags & CKF_REMOVABLE_DEVICE) != 0;
 368             initToken(slotInfo);
 369             if (nssModule != null) {
 370                 nssModule.setProvider(this);
 371             }
 372         } catch (Exception e) {
 373             if (config.getHandleStartupErrors() == Config.ERR_IGNORE_ALL) {
 374                 throw new UnsupportedOperationException
 375                         ("Initialization failed", e);
 376             } else {
 377                 throw new ProviderException
 378                         ("Initialization failed", e);
 379             }
 380         }
 381     }
 382 
 383     private static String toString(long[] longs) {
 384         if (longs.length == 0) {
 385             return "(none)";
 386         }
 387         StringBuilder sb = new StringBuilder();
 388         sb.append(longs[0]);
 389         for (int i = 1; i < longs.length; i++) {
 390             sb.append(", ");
 391             sb.append(longs[i]);
 392         }
 393         return sb.toString();
 394     }
 395 
 396     public boolean equals(Object obj) {
 397         return this == obj;
 398     }
 399 
 400     public int hashCode() {
 401         return System.identityHashCode(this);
 402     }
 403 
 404     private static String[] s(String ...aliases) {
 405         return aliases;
 406     }
 407 
 408     private static final class Descriptor {
 409         final String type;
 410         final String algorithm;
 411         final String className;
 412         final String[] aliases;
 413         final int[] mechanisms;
 414 
 415         private Descriptor(String type, String algorithm, String className,
 416                 String[] aliases, int[] mechanisms) {
 417             this.type = type;
 418             this.algorithm = algorithm;
 419             this.className = className;
 420             this.aliases = aliases;
 421             this.mechanisms = mechanisms;
 422         }
 423         private P11Service service(Token token, int mechanism) {
 424             return new P11Service
 425                 (token, type, algorithm, className, aliases, mechanism);
 426         }
 427         public String toString() {
 428             return type + "." + algorithm;
 429         }
 430     }
 431 
 432     // Map from mechanism to List of Descriptors that should be
 433     // registered if the mechanism is supported
 434     private final static Map<Integer,List<Descriptor>> descriptors =
 435         new HashMap<Integer,List<Descriptor>>();
 436 
 437     private static int[] m(long m1) {
 438         return new int[] {(int)m1};
 439     }
 440 
 441     private static int[] m(long m1, long m2) {
 442         return new int[] {(int)m1, (int)m2};
 443     }
 444 
 445     private static int[] m(long m1, long m2, long m3) {
 446         return new int[] {(int)m1, (int)m2, (int)m3};
 447     }
 448 
 449     private static int[] m(long m1, long m2, long m3, long m4) {
 450         return new int[] {(int)m1, (int)m2, (int)m3, (int)m4};
 451     }
 452 
 453     private static void d(String type, String algorithm, String className,
 454             int[] m) {
 455         register(new Descriptor(type, algorithm, className, null, m));
 456     }
 457 
 458     private static void d(String type, String algorithm, String className,
 459             String[] aliases, int[] m) {
 460         register(new Descriptor(type, algorithm, className, aliases, m));
 461     }
 462 
 463     private static void register(Descriptor d) {
 464         for (int i = 0; i < d.mechanisms.length; i++) {
 465             int m = d.mechanisms[i];
 466             Integer key = Integer.valueOf(m);
 467             List<Descriptor> list = descriptors.get(key);
 468             if (list == null) {
 469                 list = new ArrayList<Descriptor>();
 470                 descriptors.put(key, list);
 471             }
 472             list.add(d);
 473         }
 474     }
 475 
 476     private final static String MD  = "MessageDigest";
 477 
 478     private final static String SIG = "Signature";
 479 
 480     private final static String KPG = "KeyPairGenerator";
 481 
 482     private final static String KG  = "KeyGenerator";
 483 
 484     private final static String AGP = "AlgorithmParameters";
 485 
 486     private final static String KF  = "KeyFactory";
 487 
 488     private final static String SKF = "SecretKeyFactory";
 489 
 490     private final static String CIP = "Cipher";
 491 
 492     private final static String MAC = "Mac";
 493 
 494     private final static String KA  = "KeyAgreement";
 495 
 496     private final static String KS  = "KeyStore";
 497 
 498     private final static String SR  = "SecureRandom";
 499 
 500     static {
 501         // names of all the implementation classes
 502         // use local variables, only used here
 503         String P11Digest           = "sun.security.pkcs11.P11Digest";
 504         String P11MAC              = "sun.security.pkcs11.P11MAC";
 505         String P11KeyPairGenerator = "sun.security.pkcs11.P11KeyPairGenerator";
 506         String P11KeyGenerator     = "sun.security.pkcs11.P11KeyGenerator";
 507         String P11RSAKeyFactory    = "sun.security.pkcs11.P11RSAKeyFactory";
 508         String P11DSAKeyFactory    = "sun.security.pkcs11.P11DSAKeyFactory";
 509         String P11DHKeyFactory     = "sun.security.pkcs11.P11DHKeyFactory";
 510         String P11KeyAgreement     = "sun.security.pkcs11.P11KeyAgreement";
 511         String P11SecretKeyFactory = "sun.security.pkcs11.P11SecretKeyFactory";
 512         String P11Cipher           = "sun.security.pkcs11.P11Cipher";
 513         String P11RSACipher        = "sun.security.pkcs11.P11RSACipher";
 514         String P11Signature        = "sun.security.pkcs11.P11Signature";
 515 
 516         // XXX register all aliases
 517 
 518         d(MD, "MD2",            P11Digest,
 519                 m(CKM_MD2));
 520         d(MD, "MD5",            P11Digest,
 521                 m(CKM_MD5));
 522         d(MD, "SHA1",           P11Digest,
 523                 s("SHA", "SHA-1", "1.3.14.3.2.26", "OID.1.3.14.3.2.26"),
 524                 m(CKM_SHA_1));
 525 
 526         d(MD, "SHA-224",        P11Digest,
 527                 s("2.16.840.1.101.3.4.2.4", "OID.2.16.840.1.101.3.4.2.4"),
 528                 m(CKM_SHA224));
 529         d(MD, "SHA-256",        P11Digest,
 530                 s("2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1"),
 531                 m(CKM_SHA256));
 532         d(MD, "SHA-384",        P11Digest,
 533                 s("2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2"),
 534                 m(CKM_SHA384));
 535         d(MD, "SHA-512",        P11Digest,
 536                 s("2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3"),
 537                 m(CKM_SHA512));
 538 
 539         d(MAC, "HmacMD5",       P11MAC,
 540                 m(CKM_MD5_HMAC));
 541         d(MAC, "HmacSHA1",      P11MAC,
 542                 s("1.2.840.113549.2.7", "OID.1.2.840.113549.2.7"),
 543                 m(CKM_SHA_1_HMAC));
 544         d(MAC, "HmacSHA224",    P11MAC,
 545                 s("1.2.840.113549.2.8", "OID.1.2.840.113549.2.8"),
 546                 m(CKM_SHA224_HMAC));
 547         d(MAC, "HmacSHA256",    P11MAC,
 548                 s("1.2.840.113549.2.9", "OID.1.2.840.113549.2.9"),
 549                 m(CKM_SHA256_HMAC));
 550         d(MAC, "HmacSHA384",    P11MAC,
 551                 s("1.2.840.113549.2.10", "OID.1.2.840.113549.2.10"),
 552                 m(CKM_SHA384_HMAC));
 553         d(MAC, "HmacSHA512",    P11MAC,
 554                 s("1.2.840.113549.2.11", "OID.1.2.840.113549.2.11"),
 555                 m(CKM_SHA512_HMAC));
 556         d(MAC, "SslMacMD5",     P11MAC,
 557                 m(CKM_SSL3_MD5_MAC));
 558         d(MAC, "SslMacSHA1",    P11MAC,
 559                 m(CKM_SSL3_SHA1_MAC));
 560 
 561         d(KPG, "RSA",           P11KeyPairGenerator,
 562                 m(CKM_RSA_PKCS_KEY_PAIR_GEN));
 563         d(KPG, "DSA",           P11KeyPairGenerator,
 564                 s("1.3.14.3.2.12", "1.2.840.10040.4.1", "OID.1.2.840.10040.4.1"),
 565                 m(CKM_DSA_KEY_PAIR_GEN));
 566         d(KPG, "DH",            P11KeyPairGenerator,    s("DiffieHellman"),
 567                 m(CKM_DH_PKCS_KEY_PAIR_GEN));
 568         d(KPG, "EC",            P11KeyPairGenerator,
 569                 m(CKM_EC_KEY_PAIR_GEN));
 570 
 571         d(KG,  "ARCFOUR",       P11KeyGenerator,        s("RC4"),
 572                 m(CKM_RC4_KEY_GEN));
 573         d(KG,  "DES",           P11KeyGenerator,
 574                 m(CKM_DES_KEY_GEN));
 575         d(KG,  "DESede",        P11KeyGenerator,
 576                 m(CKM_DES3_KEY_GEN, CKM_DES2_KEY_GEN));
 577         d(KG,  "AES",           P11KeyGenerator,
 578                 m(CKM_AES_KEY_GEN));
 579         d(KG,  "Blowfish",      P11KeyGenerator,
 580                 m(CKM_BLOWFISH_KEY_GEN));
 581 
 582         // register (Secret)KeyFactories if there are any mechanisms
 583         // for a particular algorithm that we support
 584         d(KF, "RSA",            P11RSAKeyFactory,
 585                 m(CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS, CKM_RSA_X_509));
 586         d(KF, "DSA",            P11DSAKeyFactory,
 587                 s("1.3.14.3.2.12", "1.2.840.10040.4.1", "OID.1.2.840.10040.4.1"),
 588                 m(CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1));
 589         d(KF, "DH",             P11DHKeyFactory,        s("DiffieHellman"),
 590                 m(CKM_DH_PKCS_KEY_PAIR_GEN, CKM_DH_PKCS_DERIVE));
 591         d(KF, "EC",             P11DHKeyFactory,
 592                 m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE,
 593                     CKM_ECDSA, CKM_ECDSA_SHA1));
 594 
 595         // AlgorithmParameters for EC.
 596         // Only needed until we have an EC implementation in the SUN provider.
 597         d(AGP, "EC",            "sun.security.util.ECParameters",
 598                                                 s("1.2.840.10045.2.1"),
 599                 m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE,
 600                     CKM_ECDSA, CKM_ECDSA_SHA1));
 601 
 602         d(KA, "DH",             P11KeyAgreement,        s("DiffieHellman"),
 603                 m(CKM_DH_PKCS_DERIVE));
 604         d(KA, "ECDH",           "sun.security.pkcs11.P11ECDHKeyAgreement",
 605                 m(CKM_ECDH1_DERIVE));
 606 
 607         d(SKF, "ARCFOUR",       P11SecretKeyFactory,    s("RC4"),
 608                 m(CKM_RC4));
 609         d(SKF, "DES",           P11SecretKeyFactory,
 610                 m(CKM_DES_CBC));
 611         d(SKF, "DESede",        P11SecretKeyFactory,
 612                 m(CKM_DES3_CBC));
 613         d(SKF, "AES",           P11SecretKeyFactory,
 614                 s("2.16.840.1.101.3.4.1", "OID.2.16.840.1.101.3.4.1"),
 615                 m(CKM_AES_CBC));
 616         d(SKF, "Blowfish",      P11SecretKeyFactory,
 617                 m(CKM_BLOWFISH_CBC));
 618 
 619         // XXX attributes for Ciphers (supported modes, padding)
 620         d(CIP, "ARCFOUR",                       P11Cipher,      s("RC4"),
 621                 m(CKM_RC4));
 622         d(CIP, "DES/CBC/NoPadding",             P11Cipher,
 623                 m(CKM_DES_CBC));
 624         d(CIP, "DES/CBC/PKCS5Padding",          P11Cipher,
 625                 m(CKM_DES_CBC_PAD, CKM_DES_CBC));
 626         d(CIP, "DES/ECB/NoPadding",             P11Cipher,
 627                 m(CKM_DES_ECB));
 628         d(CIP, "DES/ECB/PKCS5Padding",          P11Cipher,      s("DES"),
 629                 m(CKM_DES_ECB));
 630 
 631         d(CIP, "DESede/CBC/NoPadding",          P11Cipher,
 632                 m(CKM_DES3_CBC));
 633         d(CIP, "DESede/CBC/PKCS5Padding",       P11Cipher,
 634                 m(CKM_DES3_CBC_PAD, CKM_DES3_CBC));
 635         d(CIP, "DESede/ECB/NoPadding",          P11Cipher,
 636                 m(CKM_DES3_ECB));
 637         d(CIP, "DESede/ECB/PKCS5Padding",       P11Cipher,      s("DESede"),
 638                 m(CKM_DES3_ECB));
 639         d(CIP, "AES/CBC/NoPadding",             P11Cipher,
 640                 m(CKM_AES_CBC));
 641         d(CIP, "AES_128/CBC/NoPadding",          P11Cipher,
 642                 s("2.16.840.1.101.3.4.1.2", "OID.2.16.840.1.101.3.4.1.2"),
 643                 m(CKM_AES_CBC));
 644         d(CIP, "AES_192/CBC/NoPadding",          P11Cipher,
 645                 s("2.16.840.1.101.3.4.1.22", "OID.2.16.840.1.101.3.4.1.22"),
 646                 m(CKM_AES_CBC));
 647         d(CIP, "AES_256/CBC/NoPadding",          P11Cipher,
 648                 s("2.16.840.1.101.3.4.1.42", "OID.2.16.840.1.101.3.4.1.42"),
 649                 m(CKM_AES_CBC));
 650         d(CIP, "AES/CBC/PKCS5Padding",          P11Cipher,
 651                 m(CKM_AES_CBC_PAD, CKM_AES_CBC));
 652         d(CIP, "AES/ECB/NoPadding",             P11Cipher,
 653                 m(CKM_AES_ECB));
 654         d(CIP, "AES_128/ECB/NoPadding",          P11Cipher,
 655                 s("2.16.840.1.101.3.4.1.1", "OID.2.16.840.1.101.3.4.1.1"),
 656                 m(CKM_AES_ECB));
 657         d(CIP, "AES_192/ECB/NoPadding",          P11Cipher,
 658                 s("2.16.840.1.101.3.4.1.21", "OID.2.16.840.1.101.3.4.1.21"),
 659                 m(CKM_AES_ECB));
 660         d(CIP, "AES_256/ECB/NoPadding",          P11Cipher,
 661                 s("2.16.840.1.101.3.4.1.41", "OID.2.16.840.1.101.3.4.1.41"),
 662                 m(CKM_AES_ECB));
 663         d(CIP, "AES/ECB/PKCS5Padding",          P11Cipher,      s("AES"),
 664                 m(CKM_AES_ECB));
 665         d(CIP, "AES/CTR/NoPadding",             P11Cipher,
 666                 m(CKM_AES_CTR));
 667         d(CIP, "Blowfish/CBC/NoPadding",        P11Cipher,
 668                 m(CKM_BLOWFISH_CBC));
 669         d(CIP, "Blowfish/CBC/PKCS5Padding",     P11Cipher,
 670                 m(CKM_BLOWFISH_CBC));
 671 
 672         // XXX RSA_X_509, RSA_OAEP not yet supported
 673         d(CIP, "RSA/ECB/PKCS1Padding",          P11RSACipher,   s("RSA"),
 674                 m(CKM_RSA_PKCS));
 675         d(CIP, "RSA/ECB/NoPadding",             P11RSACipher,
 676                 m(CKM_RSA_X_509));
 677 
 678         d(SIG, "RawDSA",        P11Signature,   s("NONEwithDSA"),
 679                 m(CKM_DSA));
 680         d(SIG, "DSA",           P11Signature,
 681                 s("SHA1withDSA", "1.3.14.3.2.13", "1.3.14.3.2.27",
 682                   "1.2.840.10040.4.3", "OID.1.2.840.10040.4.3"),
 683                 m(CKM_DSA_SHA1, CKM_DSA));
 684         d(SIG, "RawDSAinP1363Format",   P11Signature,
 685                 s("NONEwithDSAinP1363Format"),
 686                 m(CKM_DSA));
 687         d(SIG, "DSAinP1363Format",      P11Signature,
 688                 s("SHA1withDSAinP1363Format"),
 689                 m(CKM_DSA_SHA1, CKM_DSA));
 690         d(SIG, "NONEwithECDSA", P11Signature,
 691                 m(CKM_ECDSA));
 692         d(SIG, "SHA1withECDSA", P11Signature,
 693                 s("ECDSA", "1.2.840.10045.4.1", "OID.1.2.840.10045.4.1"),
 694                 m(CKM_ECDSA_SHA1, CKM_ECDSA));
 695         d(SIG, "SHA224withECDSA",       P11Signature,
 696                 s("1.2.840.10045.4.3.1", "OID.1.2.840.10045.4.3.1"),
 697                 m(CKM_ECDSA));
 698         d(SIG, "SHA256withECDSA",       P11Signature,
 699                 s("1.2.840.10045.4.3.2", "OID.1.2.840.10045.4.3.2"),
 700                 m(CKM_ECDSA));
 701         d(SIG, "SHA384withECDSA",       P11Signature,
 702                 s("1.2.840.10045.4.3.3", "OID.1.2.840.10045.4.3.3"),
 703                 m(CKM_ECDSA));
 704         d(SIG, "SHA512withECDSA",       P11Signature,
 705                 s("1.2.840.10045.4.3.4", "OID.1.2.840.10045.4.3.4"),
 706                 m(CKM_ECDSA));
 707         d(SIG, "NONEwithECDSAinP1363Format",   P11Signature,
 708                 m(CKM_ECDSA));
 709         d(SIG, "SHA1withECDSAinP1363Format",   P11Signature,
 710                 m(CKM_ECDSA_SHA1, CKM_ECDSA));
 711         d(SIG, "SHA224withECDSAinP1363Format", P11Signature,
 712                 m(CKM_ECDSA));
 713         d(SIG, "SHA256withECDSAinP1363Format", P11Signature,
 714                 m(CKM_ECDSA));
 715         d(SIG, "SHA384withECDSAinP1363Format", P11Signature,
 716                 m(CKM_ECDSA));
 717         d(SIG, "SHA512withECDSAinP1363Format", P11Signature,
 718                 m(CKM_ECDSA));
 719         d(SIG, "MD2withRSA",    P11Signature,
 720                 s("1.2.840.113549.1.1.2", "OID.1.2.840.113549.1.1.2"),
 721                 m(CKM_MD2_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
 722         d(SIG, "MD5withRSA",    P11Signature,
 723                 s("1.2.840.113549.1.1.4", "OID.1.2.840.113549.1.1.4"),
 724                 m(CKM_MD5_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
 725         d(SIG, "SHA1withRSA",   P11Signature,
 726                 s("1.2.840.113549.1.1.5", "OID.1.2.840.113549.1.1.5",
 727                   "1.3.14.3.2.29"),
 728                 m(CKM_SHA1_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
 729         d(SIG, "SHA224withRSA", P11Signature,
 730                 s("1.2.840.113549.1.1.14", "OID.1.2.840.113549.1.1.14"),
 731                 m(CKM_SHA224_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
 732         d(SIG, "SHA256withRSA", P11Signature,
 733                 s("1.2.840.113549.1.1.11", "OID.1.2.840.113549.1.1.11"),
 734                 m(CKM_SHA256_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
 735         d(SIG, "SHA384withRSA", P11Signature,
 736                 s("1.2.840.113549.1.1.12", "OID.1.2.840.113549.1.1.12"),
 737                 m(CKM_SHA384_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
 738         d(SIG, "SHA512withRSA", P11Signature,
 739                 s("1.2.840.113549.1.1.13", "OID.1.2.840.113549.1.1.13"),
 740                 m(CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
 741 
 742         /*
 743          * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the
 744          * PRF calculations.  As of 2010, there is no PKCS11-level
 745          * support for TLS 1.2 PRF calculations, and no known OS's have
 746          * an internal variant we could use.  Therefore for TLS 1.2, we
 747          * are updating JSSE to request different provider algorithms
 748          * (e.g. "SunTls12Prf"), and currently only SunJCE has these
 749          * TLS 1.2 algorithms.
 750          *
 751          * If we reused the names such as "SunTlsPrf", the PKCS11
 752          * providers would need be updated to fail correctly when
 753          * presented with the wrong version number (via
 754          * Provider.Service.supportsParameters()), and we would also
 755          * need to add the appropriate supportsParamters() checks into
 756          * KeyGenerators (not currently there).
 757          *
 758          * In the future, if PKCS11 support is added, we will restructure
 759          * this.
 760          */
 761         d(KG, "SunTlsRsaPremasterSecret",
 762                     "sun.security.pkcs11.P11TlsRsaPremasterSecretGenerator",
 763                 m(CKM_SSL3_PRE_MASTER_KEY_GEN, CKM_TLS_PRE_MASTER_KEY_GEN));
 764         d(KG, "SunTlsMasterSecret",
 765                     "sun.security.pkcs11.P11TlsMasterSecretGenerator",
 766                 m(CKM_SSL3_MASTER_KEY_DERIVE, CKM_TLS_MASTER_KEY_DERIVE,
 767                     CKM_SSL3_MASTER_KEY_DERIVE_DH,
 768                     CKM_TLS_MASTER_KEY_DERIVE_DH));
 769         d(KG, "SunTlsKeyMaterial",
 770                     "sun.security.pkcs11.P11TlsKeyMaterialGenerator",
 771                 m(CKM_SSL3_KEY_AND_MAC_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE));
 772         d(KG, "SunTlsPrf", "sun.security.pkcs11.P11TlsPrfGenerator",
 773                 m(CKM_TLS_PRF, CKM_NSS_TLS_PRF_GENERAL));
 774     }
 775 
 776     // background thread that periodically checks for token insertion
 777     // if no token is present. We need to do that in a separate thread because
 778     // the insertion check may block for quite a long time on some tokens.
 779     private static class TokenPoller implements Runnable {
 780         private final SunPKCS11 provider;
 781         private volatile boolean enabled;
 782         private TokenPoller(SunPKCS11 provider) {
 783             this.provider = provider;
 784             enabled = true;
 785         }
 786         public void run() {
 787             int interval = provider.config.getInsertionCheckInterval();
 788             while (enabled) {
 789                 try {
 790                     Thread.sleep(interval);
 791                 } catch (InterruptedException e) {
 792                     break;
 793                 }
 794                 if (enabled == false) {
 795                     break;
 796                 }
 797                 try {
 798                     provider.initToken(null);
 799                 } catch (PKCS11Exception e) {
 800                     // ignore
 801                 }
 802             }
 803         }
 804         void disable() {
 805             enabled = false;
 806         }
 807     }
 808 
 809     // create the poller thread, if not already active
 810     private void createPoller() {
 811         if (poller != null) {
 812             return;
 813         }
 814         TokenPoller poller = new TokenPoller(this);
 815         Thread t = new ManagedLocalsThread(poller, "Poller " + getName());
 816         t.setDaemon(true);
 817         t.setPriority(Thread.MIN_PRIORITY);
 818         t.start();
 819         this.poller = poller;
 820     }
 821 
 822     // destroy the poller thread, if active
 823     private void destroyPoller() {
 824         if (poller != null) {
 825             poller.disable();
 826             poller = null;
 827         }
 828     }
 829 
 830     private boolean hasValidToken() {
 831         /* Commented out to work with Solaris softtoken impl which
 832            returns 0-value flags, e.g. both REMOVABLE_DEVICE and
 833            TOKEN_PRESENT are false, when it can't access the token.
 834         if (removable == false) {
 835             return true;
 836         }
 837         */
 838         Token token = this.token;
 839         return (token != null) && token.isValid();
 840     }
 841 
 842     // destroy the token. Called if we detect that it has been removed
 843     synchronized void uninitToken(Token token) {
 844         if (this.token != token) {
 845             // mismatch, our token must already be destroyed
 846             return;
 847         }
 848         destroyPoller();
 849         this.token = null;
 850         // unregister all algorithms
 851         AccessController.doPrivileged(new PrivilegedAction<Object>() {
 852             public Object run() {
 853                 clear();
 854                 return null;
 855             }
 856         });
 857         createPoller();
 858     }
 859 
 860     // test if a token is present and initialize this provider for it if so.
 861     // does nothing if no token is found
 862     // called from constructor and by poller
 863     private void initToken(CK_SLOT_INFO slotInfo) throws PKCS11Exception {
 864         if (slotInfo == null) {
 865             slotInfo = p11.C_GetSlotInfo(slotID);
 866         }
 867         if (removable && (slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
 868             createPoller();
 869             return;
 870         }
 871         destroyPoller();
 872         boolean showInfo = config.getShowInfo();
 873         if (showInfo) {
 874             System.out.println("Slot info for slot " + slotID + ":");
 875             System.out.println(slotInfo);
 876         }
 877         final Token token = new Token(this);
 878         if (showInfo) {
 879             System.out.println
 880                 ("Token info for token in slot " + slotID + ":");
 881             System.out.println(token.tokenInfo);
 882         }
 883         long[] supportedMechanisms = p11.C_GetMechanismList(slotID);
 884 
 885         // Create a map from the various Descriptors to the "most
 886         // preferred" mechanism that was defined during the
 887         // static initialization.  For example, DES/CBC/PKCS5Padding
 888         // could be mapped to CKM_DES_CBC_PAD or CKM_DES_CBC.  Prefer
 889         // the earliest entry.  When asked for "DES/CBC/PKCS5Padding", we
 890         // return a CKM_DES_CBC_PAD.
 891         final Map<Descriptor,Integer> supportedAlgs =
 892                                         new HashMap<Descriptor,Integer>();
 893         for (int i = 0; i < supportedMechanisms.length; i++) {
 894             long longMech = supportedMechanisms[i];
 895             boolean isEnabled = config.isEnabled(longMech);
 896             if (showInfo) {
 897                 CK_MECHANISM_INFO mechInfo =
 898                         p11.C_GetMechanismInfo(slotID, longMech);
 899                 System.out.println("Mechanism " +
 900                         Functions.getMechanismName(longMech) + ":");
 901                 if (isEnabled == false) {
 902                     System.out.println("DISABLED in configuration");
 903                 }
 904                 System.out.println(mechInfo);
 905             }
 906             if (isEnabled == false) {
 907                 continue;
 908             }
 909             // we do not know of mechs with the upper 32 bits set
 910             if (longMech >>> 32 != 0) {
 911                 continue;
 912             }
 913             int mech = (int)longMech;
 914             Integer integerMech = Integer.valueOf(mech);
 915             List<Descriptor> ds = descriptors.get(integerMech);
 916             if (ds == null) {
 917                 continue;
 918             }
 919             for (Descriptor d : ds) {
 920                 Integer oldMech = supportedAlgs.get(d);
 921                 if (oldMech == null) {
 922                     supportedAlgs.put(d, integerMech);
 923                     continue;
 924                 }
 925                 // See if there is something "more preferred"
 926                 // than what we currently have in the supportedAlgs
 927                 // map.
 928                 int intOldMech = oldMech.intValue();
 929                 for (int j = 0; j < d.mechanisms.length; j++) {
 930                     int nextMech = d.mechanisms[j];
 931                     if (mech == nextMech) {
 932                         supportedAlgs.put(d, integerMech);
 933                         break;
 934                     } else if (intOldMech == nextMech) {
 935                         break;
 936                     }
 937                 }
 938             }
 939 
 940         }
 941 
 942         // register algorithms in provider
 943         AccessController.doPrivileged(new PrivilegedAction<Object>() {
 944             public Object run() {
 945                 for (Map.Entry<Descriptor,Integer> entry
 946                         : supportedAlgs.entrySet()) {
 947                     Descriptor d = entry.getKey();
 948                     int mechanism = entry.getValue().intValue();
 949                     Service s = d.service(token, mechanism);
 950                     putService(s);
 951                 }
 952                 if (((token.tokenInfo.flags & CKF_RNG) != 0)
 953                         && config.isEnabled(PCKM_SECURERANDOM)
 954                         && !token.sessionManager.lowMaxSessions()) {
 955                     // do not register SecureRandom if the token does
 956                     // not support many sessions. if we did, we might
 957                     // run out of sessions in the middle of a
 958                     // nextBytes() call where we cannot fail over.
 959                     putService(new P11Service(token, SR, "PKCS11",
 960                         "sun.security.pkcs11.P11SecureRandom", null,
 961                         PCKM_SECURERANDOM));
 962                 }
 963                 if (config.isEnabled(PCKM_KEYSTORE)) {
 964                     putService(new P11Service(token, KS, "PKCS11",
 965                         "sun.security.pkcs11.P11KeyStore",
 966                         s("PKCS11-" + config.getName()),
 967                         PCKM_KEYSTORE));
 968                 }
 969                 return null;
 970             }
 971         });
 972 
 973         this.token = token;
 974     }
 975 
 976     private static final class P11Service extends Service {
 977 
 978         private final Token token;
 979 
 980         private final long mechanism;
 981 
 982         P11Service(Token token, String type, String algorithm,
 983                 String className, String[] al, long mechanism) {
 984             super(token.provider, type, algorithm, className, toList(al), null);
 985             this.token = token;
 986             this.mechanism = mechanism & 0xFFFFFFFFL;
 987         }
 988 
 989         private static List<String> toList(String[] aliases) {
 990             return (aliases == null) ? null : Arrays.asList(aliases);
 991         }
 992 
 993         public Object newInstance(Object param)
 994                 throws NoSuchAlgorithmException {
 995             if (token.isValid() == false) {
 996                 throw new NoSuchAlgorithmException("Token has been removed");
 997             }
 998             try {
 999                 return newInstance0(param);
1000             } catch (PKCS11Exception e) {
1001                 throw new NoSuchAlgorithmException(e);
1002             }
1003         }
1004 
1005         public Object newInstance0(Object param) throws
1006                 PKCS11Exception, NoSuchAlgorithmException {
1007             String algorithm = getAlgorithm();
1008             String type = getType();
1009             if (type == MD) {
1010                 return new P11Digest(token, algorithm, mechanism);
1011             } else if (type == CIP) {
1012                 if (algorithm.startsWith("RSA")) {
1013                     return new P11RSACipher(token, algorithm, mechanism);
1014                 } else {
1015                     return new P11Cipher(token, algorithm, mechanism);
1016                 }
1017             } else if (type == SIG) {
1018                 return new P11Signature(token, algorithm, mechanism);
1019             } else if (type == MAC) {
1020                 return new P11Mac(token, algorithm, mechanism);
1021             } else if (type == KPG) {
1022                 return new P11KeyPairGenerator(token, algorithm, mechanism);
1023             } else if (type == KA) {
1024                 if (algorithm.equals("ECDH")) {
1025                     return new P11ECDHKeyAgreement(token, algorithm, mechanism);
1026                 } else {
1027                     return new P11KeyAgreement(token, algorithm, mechanism);
1028                 }
1029             } else if (type == KF) {
1030                 return token.getKeyFactory(algorithm);
1031             } else if (type == SKF) {
1032                 return new P11SecretKeyFactory(token, algorithm);
1033             } else if (type == KG) {
1034                 // reference equality
1035                 if (algorithm == "SunTlsRsaPremasterSecret") {
1036                     return new P11TlsRsaPremasterSecretGenerator(
1037                         token, algorithm, mechanism);
1038                 } else if (algorithm == "SunTlsMasterSecret") {
1039                     return new P11TlsMasterSecretGenerator(
1040                         token, algorithm, mechanism);
1041                 } else if (algorithm == "SunTlsKeyMaterial") {
1042                     return new P11TlsKeyMaterialGenerator(
1043                         token, algorithm, mechanism);
1044                 } else if (algorithm == "SunTlsPrf") {
1045                     return new P11TlsPrfGenerator(token, algorithm, mechanism);
1046                 } else {
1047                     return new P11KeyGenerator(token, algorithm, mechanism);
1048                 }
1049             } else if (type == SR) {
1050                 return token.getRandom();
1051             } else if (type == KS) {
1052                 return token.getKeyStore();
1053             } else if (type == AGP) {
1054                 return new sun.security.util.ECParameters();
1055             } else {
1056                 throw new NoSuchAlgorithmException("Unknown type: " + type);
1057             }
1058         }
1059 
1060         public boolean supportsParameter(Object param) {
1061             if ((param == null) || (token.isValid() == false)) {
1062                 return false;
1063             }
1064             if (param instanceof Key == false) {
1065                 throw new InvalidParameterException("Parameter must be a Key");
1066             }
1067             String algorithm = getAlgorithm();
1068             String type = getType();
1069             Key key = (Key)param;
1070             String keyAlgorithm = key.getAlgorithm();
1071             // RSA signatures and cipher
1072             if (((type == CIP) && algorithm.startsWith("RSA"))
1073                     || (type == SIG) && algorithm.endsWith("RSA")) {
1074                 if (keyAlgorithm.equals("RSA") == false) {
1075                     return false;
1076                 }
1077                 return isLocalKey(key)
1078                         || (key instanceof RSAPrivateKey)
1079                         || (key instanceof RSAPublicKey);
1080             }
1081             // EC
1082             if (((type == KA) && algorithm.equals("ECDH"))
1083                     || ((type == SIG) && algorithm.contains("ECDSA"))) {
1084                 if (keyAlgorithm.equals("EC") == false) {
1085                     return false;
1086                 }
1087                 return isLocalKey(key)
1088                         || (key instanceof ECPrivateKey)
1089                         || (key instanceof ECPublicKey);
1090             }
1091             // DSA signatures
1092             if ((type == SIG) && algorithm.contains("DSA") &&
1093                     !algorithm.contains("ECDSA")) {
1094                 if (keyAlgorithm.equals("DSA") == false) {
1095                     return false;
1096                 }
1097                 return isLocalKey(key)
1098                         || (key instanceof DSAPrivateKey)
1099                         || (key instanceof DSAPublicKey);
1100             }
1101             // MACs and symmetric ciphers
1102             if ((type == CIP) || (type == MAC)) {
1103                 // do not check algorithm name, mismatch is unlikely anyway
1104                 return isLocalKey(key) || "RAW".equals(key.getFormat());
1105             }
1106             // DH key agreement
1107             if (type == KA) {
1108                 if (keyAlgorithm.equals("DH") == false) {
1109                     return false;
1110                 }
1111                 return isLocalKey(key)
1112                         || (key instanceof DHPrivateKey)
1113                         || (key instanceof DHPublicKey);
1114             }
1115             // should not reach here,
1116             // unknown engine type or algorithm
1117             throw new AssertionError
1118                 ("SunPKCS11 error: " + type + ", " + algorithm);
1119         }
1120 
1121         private boolean isLocalKey(Key key) {
1122             return (key instanceof P11Key) && (((P11Key)key).token == token);
1123         }
1124 
1125         public String toString() {
1126             return super.toString() +
1127                 " (" + Functions.getMechanismName(mechanism) + ")";
1128         }
1129 
1130     }
1131 
1132     /**
1133      * Log in to this provider.
1134      *
1135      * <p> If the token expects a PIN to be supplied by the caller,
1136      * the <code>handler</code> implementation must support
1137      * a <code>PasswordCallback</code>.
1138      *
1139      * <p> To determine if the token supports a protected authentication path,
1140      * the CK_TOKEN_INFO flag, CKF_PROTECTED_AUTHENTICATION_PATH, is consulted.
1141      *
1142      * @param subject this parameter is ignored
1143      * @param handler the <code>CallbackHandler</code> used by
1144      *  this provider to communicate with the caller
1145      *
1146      * @exception LoginException if the login operation fails
1147      * @exception SecurityException if the does not pass a security check for
1148      *  <code>SecurityPermission("authProvider.<i>name</i>")</code>,
1149      *  where <i>name</i> is the value returned by
1150      *  this provider's <code>getName</code> method
1151      */
1152     public void login(Subject subject, CallbackHandler handler)
1153         throws LoginException {
1154 
1155         // security check
1156 
1157         SecurityManager sm = System.getSecurityManager();
1158         if (sm != null) {
1159             if (debug != null) {
1160                 debug.println("checking login permission");
1161             }
1162             sm.checkPermission(new SecurityPermission
1163                         ("authProvider." + this.getName()));
1164         }
1165 
1166         if (hasValidToken() == false) {
1167             throw new LoginException("No token present");
1168         }
1169 
1170         // see if a login is required
1171 
1172         if ((token.tokenInfo.flags & CKF_LOGIN_REQUIRED) == 0) {
1173             if (debug != null) {
1174                 debug.println("login operation not required for token - " +
1175                                 "ignoring login request");
1176             }
1177             return;
1178         }
1179 
1180         // see if user already logged in
1181 
1182         try {
1183             if (token.isLoggedInNow(null)) {
1184                 // user already logged in
1185                 if (debug != null) {
1186                     debug.println("user already logged in");
1187                 }
1188                 return;
1189             }
1190         } catch (PKCS11Exception e) {
1191             // ignore - fall thru and attempt login
1192         }
1193 
1194         // get the pin if necessary
1195 
1196         char[] pin = null;
1197         if ((token.tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) {
1198 
1199             // get password
1200 
1201             CallbackHandler myHandler = getCallbackHandler(handler);
1202             if (myHandler == null) {
1203                 // XXX PolicyTool is dependent on this message text
1204                 throw new LoginException
1205                         ("no password provided, and no callback handler " +
1206                         "available for retrieving password");
1207             }
1208 
1209             java.text.MessageFormat form = new java.text.MessageFormat
1210                         (ResourcesMgr.getString
1211                         ("PKCS11.Token.providerName.Password."));
1212             Object[] source = { getName() };
1213 
1214             PasswordCallback pcall = new PasswordCallback(form.format(source),
1215                                                         false);
1216             Callback[] callbacks = { pcall };
1217             try {
1218                 myHandler.handle(callbacks);
1219             } catch (Exception e) {
1220                 LoginException le = new LoginException
1221                         ("Unable to perform password callback");
1222                 le.initCause(e);
1223                 throw le;
1224             }
1225 
1226             pin = pcall.getPassword();
1227             pcall.clearPassword();
1228             if (pin == null) {
1229                 if (debug != null) {
1230                     debug.println("caller passed NULL pin");
1231                 }
1232             }
1233         }
1234 
1235         // perform token login
1236 
1237         Session session = null;
1238         try {
1239             session = token.getOpSession();
1240 
1241             // pin is NULL if using CKF_PROTECTED_AUTHENTICATION_PATH
1242             p11.C_Login(session.id(), CKU_USER, pin);
1243             if (debug != null) {
1244                 debug.println("login succeeded");
1245             }
1246         } catch (PKCS11Exception pe) {
1247             if (pe.getErrorCode() == CKR_USER_ALREADY_LOGGED_IN) {
1248                 // let this one go
1249                 if (debug != null) {
1250                     debug.println("user already logged in");
1251                 }
1252                 return;
1253             } else if (pe.getErrorCode() == CKR_PIN_INCORRECT) {
1254                 FailedLoginException fle = new FailedLoginException();
1255                 fle.initCause(pe);
1256                 throw fle;
1257             } else {
1258                 LoginException le = new LoginException();
1259                 le.initCause(pe);
1260                 throw le;
1261             }
1262         } finally {
1263             token.releaseSession(session);
1264             if (pin != null) {
1265                 Arrays.fill(pin, ' ');
1266             }
1267         }
1268 
1269         // we do not store the PIN in the subject for now
1270     }
1271 
1272     /**
1273      * Log out from this provider
1274      *
1275      * @exception LoginException if the logout operation fails
1276      * @exception SecurityException if the does not pass a security check for
1277      *  <code>SecurityPermission("authProvider.<i>name</i>")</code>,
1278      *  where <i>name</i> is the value returned by
1279      *  this provider's <code>getName</code> method
1280      */
1281     public void logout() throws LoginException {
1282 
1283         // security check
1284 
1285         SecurityManager sm = System.getSecurityManager();
1286         if (sm != null) {
1287             sm.checkPermission
1288                 (new SecurityPermission("authProvider." + this.getName()));
1289         }
1290 
1291         if (hasValidToken() == false) {
1292             // app may call logout for cleanup, allow
1293             return;
1294         }
1295 
1296         if ((token.tokenInfo.flags & CKF_LOGIN_REQUIRED) == 0) {
1297             if (debug != null) {
1298                 debug.println("logout operation not required for token - " +
1299                                 "ignoring logout request");
1300             }
1301             return;
1302         }
1303 
1304         try {
1305             if (token.isLoggedInNow(null) == false) {
1306                 if (debug != null) {
1307                     debug.println("user not logged in");
1308                 }
1309                 return;
1310             }
1311         } catch (PKCS11Exception e) {
1312             // ignore
1313         }
1314 
1315         // perform token logout
1316 
1317         Session session = null;
1318         try {
1319             session = token.getOpSession();
1320             p11.C_Logout(session.id());
1321             if (debug != null) {
1322                 debug.println("logout succeeded");
1323             }
1324         } catch (PKCS11Exception pe) {
1325             if (pe.getErrorCode() == CKR_USER_NOT_LOGGED_IN) {
1326                 // let this one go
1327                 if (debug != null) {
1328                     debug.println("user not logged in");
1329                 }
1330                 return;
1331             }
1332             LoginException le = new LoginException();
1333             le.initCause(pe);
1334             throw le;
1335         } finally {
1336             token.releaseSession(session);
1337         }
1338     }
1339 
1340     /**
1341      * Set a <code>CallbackHandler</code>
1342      *
1343      * <p> The provider uses this handler if one is not passed to the
1344      * <code>login</code> method.  The provider also uses this handler
1345      * if it invokes <code>login</code> on behalf of callers.
1346      * In either case if a handler is not set via this method,
1347      * the provider queries the
1348      * <i>auth.login.defaultCallbackHandler</i> security property
1349      * for the fully qualified class name of a default handler implementation.
1350      * If the security property is not set,
1351      * the provider is assumed to have alternative means
1352      * for obtaining authentication information.
1353      *
1354      * @param handler a <code>CallbackHandler</code> for obtaining
1355      *          authentication information, which may be <code>null</code>
1356      *
1357      * @exception SecurityException if the caller does not pass a
1358      *  security check for
1359      *  <code>SecurityPermission("authProvider.<i>name</i>")</code>,
1360      *  where <i>name</i> is the value returned by
1361      *  this provider's <code>getName</code> method
1362      */
1363     public void setCallbackHandler(CallbackHandler handler) {
1364 
1365         // security check
1366 
1367         SecurityManager sm = System.getSecurityManager();
1368         if (sm != null) {
1369             sm.checkPermission
1370                 (new SecurityPermission("authProvider." + this.getName()));
1371         }
1372 
1373         synchronized (LOCK_HANDLER) {
1374             pHandler = handler;
1375         }
1376     }
1377 
1378     private CallbackHandler getCallbackHandler(CallbackHandler handler) {
1379 
1380         // get default handler if necessary
1381 
1382         if (handler != null) {
1383             return handler;
1384         }
1385 
1386         if (debug != null) {
1387             debug.println("getting provider callback handler");
1388         }
1389 
1390         synchronized (LOCK_HANDLER) {
1391             // see if handler was set via setCallbackHandler
1392             if (pHandler != null) {
1393                 return pHandler;
1394             }
1395 
1396             try {
1397                 if (debug != null) {
1398                     debug.println("getting default callback handler");
1399                 }
1400 
1401                 CallbackHandler myHandler = AccessController.doPrivileged
1402                     (new PrivilegedExceptionAction<CallbackHandler>() {
1403                     public CallbackHandler run() throws Exception {
1404 
1405                         String defaultHandler =
1406                                 java.security.Security.getProperty
1407                                 ("auth.login.defaultCallbackHandler");
1408 
1409                         if (defaultHandler == null ||
1410                             defaultHandler.length() == 0) {
1411 
1412                             // ok
1413                             if (debug != null) {
1414                                 debug.println("no default handler set");
1415                             }
1416                             return null;
1417                         }
1418 
1419                         Class<?> c = Class.forName
1420                                    (defaultHandler,
1421                                    true,
1422                                    Thread.currentThread().getContextClassLoader());
1423                         return (CallbackHandler)c.newInstance();
1424                     }
1425                 });
1426 
1427                 // save it
1428                 pHandler = myHandler;
1429                 return myHandler;
1430 
1431             } catch (PrivilegedActionException pae) {
1432                 // ok
1433                 if (debug != null) {
1434                     debug.println("Unable to load default callback handler");
1435                     pae.printStackTrace();
1436                 }
1437             }
1438         }
1439         return null;
1440     }
1441 
1442     private Object writeReplace() throws ObjectStreamException {
1443         return new SunPKCS11Rep(this);
1444     }
1445 
1446     /**
1447      * Serialized representation of the SunPKCS11 provider.
1448      */
1449     private static class SunPKCS11Rep implements Serializable {
1450 
1451         static final long serialVersionUID = -2896606995897745419L;
1452 
1453         private final String providerName;
1454 
1455         private final String configName;
1456 
1457         SunPKCS11Rep(SunPKCS11 provider) throws NotSerializableException {
1458             providerName = provider.getName();
1459             configName = provider.configName;
1460             if (Security.getProvider(providerName) != provider) {
1461                 throw new NotSerializableException("Only SunPKCS11 providers "
1462                     + "installed in java.security.Security can be serialized");
1463             }
1464         }
1465 
1466         private Object readResolve() throws ObjectStreamException {
1467             SunPKCS11 p = (SunPKCS11)Security.getProvider(providerName);
1468             if ((p == null) || (p.configName.equals(configName) == false)) {
1469                 throw new NotSerializableException("Could not find "
1470                         + providerName + " in installed providers");
1471             }
1472             return p;
1473         }
1474     }
1475 }