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