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