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