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