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
26package sun.security.pkcs11;
27
28import java.io.*;
29import java.util.*;
30
31import java.security.*;
32import java.security.interfaces.*;
33
34import javax.crypto.interfaces.*;
35
36import javax.security.auth.Subject;
37import javax.security.auth.login.LoginException;
38import javax.security.auth.login.FailedLoginException;
39import javax.security.auth.callback.Callback;
40import javax.security.auth.callback.CallbackHandler;
41import javax.security.auth.callback.ConfirmationCallback;
42import javax.security.auth.callback.PasswordCallback;
43import javax.security.auth.callback.TextOutputCallback;
44
45import sun.security.util.Debug;
46import sun.security.util.ResourcesMgr;
47import static sun.security.util.SecurityConstants.PROVIDER_VER;
48
49import sun.security.pkcs11.Secmod.*;
50
51import sun.security.pkcs11.wrapper.*;
52import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
53
54/**
55 * PKCS#11 provider main class.
56 *
57 * @author  Andreas Sterbenz
58 * @since   1.5
59 */
60public 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}
1507