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