1 /*
2  * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.security.pkcs11;
27 
28 import java.io.*;
29 import java.util.*;
30 
31 import java.security.*;
32 import java.security.KeyStore.*;
33 import java.security.cert.X509Certificate;
34 
35 import sun.security.pkcs11.wrapper.*;
36 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
37 
38 
39 /**
40  * The Secmod class defines the interface to the native NSS
41  * library and the configuration information it stores in its
42  * secmod.db file.
43  *
44  * <p>Example code:
45  * <pre>
46  *   Secmod secmod = Secmod.getInstance();
47  *   if (secmod.isInitialized() == false) {
48  *       secmod.initialize("/home/myself/.mozilla");
49  *   }
50  *
51  *   Provider p = secmod.getModule(ModuleType.KEYSTORE).getProvider();
52  *   KeyStore ks = KeyStore.getInstance("PKCS11", p);
53  *   ks.load(null, password);
54  * </pre>
55  *
56  * @since   1.6
57  * @author  Andreas Sterbenz
58  */
59 public final class Secmod {
60 
61     private final static boolean DEBUG = false;
62 
63     private final static Secmod INSTANCE;
64 
65     static {
sun.security.pkcs11.wrapper.PKCS11.loadNative()66         sun.security.pkcs11.wrapper.PKCS11.loadNative();
67         INSTANCE = new Secmod();
68     }
69 
70     private final static String NSS_LIB_NAME = "nss3";
71 
72     private final static String SOFTTOKEN_LIB_NAME = "softokn3";
73 
74     private final static String TRUST_LIB_NAME = "nssckbi";
75 
76     // handle to be passed to the native code, 0 means not initialized
77     private long nssHandle;
78 
79     // whether this is a supported version of NSS
80     private boolean supported;
81 
82     // list of the modules
83     private List<Module> modules;
84 
85     private String configDir;
86 
87     private String nssLibDir;
88 
Secmod()89     private Secmod() {
90         // empty
91     }
92 
93     /**
94      * Return the singleton Secmod instance.
95      */
getInstance()96     public static Secmod getInstance() {
97         return INSTANCE;
98     }
99 
isLoaded()100     private boolean isLoaded() {
101         if (nssHandle == 0) {
102             nssHandle = nssGetLibraryHandle(System.mapLibraryName(NSS_LIB_NAME));
103             if (nssHandle != 0) {
104                 fetchVersions();
105             }
106         }
107         return (nssHandle != 0);
108     }
109 
fetchVersions()110     private void fetchVersions() {
111         supported = nssVersionCheck(nssHandle, "3.7");
112     }
113 
114     /**
115      * Test whether this Secmod has been initialized. Returns true
116      * if NSS has been initialized using either the initialize() method
117      * or by directly calling the native NSS APIs. The latter may be
118      * the case if the current process contains components that use
119      * NSS directly.
120      *
121      * @throws IOException if an incompatible version of NSS
122      *   has been loaded
123      */
isInitialized()124     public synchronized boolean isInitialized() throws IOException {
125         // NSS does not allow us to check if it is initialized already
126         // assume that if it is loaded it is also initialized
127         if (isLoaded() == false) {
128             return false;
129         }
130         if (supported == false) {
131             throw new IOException
132                 ("An incompatible version of NSS is already loaded, "
133                 + "3.7 or later required");
134         }
135         return true;
136     }
137 
getConfigDir()138     String getConfigDir() {
139         return configDir;
140     }
141 
getLibDir()142     String getLibDir() {
143         return nssLibDir;
144     }
145 
146     /**
147      * Initialize this Secmod.
148      *
149      * @param configDir the directory containing the NSS configuration
150      *   files such as secmod.db
151      * @param nssLibDir the directory containing the NSS libraries
152      *   (libnss3.so or nss3.dll) or null if the library is on
153      *   the system default shared library path
154      *
155      * @throws IOException if NSS has already been initialized,
156      *   the specified directories are invalid, or initialization
157      *   fails for any other reason
158      */
initialize(String configDir, String nssLibDir)159     public void initialize(String configDir, String nssLibDir)
160             throws IOException {
161         initialize(DbMode.READ_WRITE, configDir, nssLibDir, false);
162     }
163 
initialize(DbMode dbMode, String configDir, String nssLibDir)164     public void initialize(DbMode dbMode, String configDir, String nssLibDir)
165             throws IOException {
166         initialize(dbMode, configDir, nssLibDir, false);
167     }
168 
initialize(DbMode dbMode, String configDir, String nssLibDir, boolean nssOptimizeSpace)169     public synchronized void initialize(DbMode dbMode, String configDir,
170         String nssLibDir, boolean nssOptimizeSpace) throws IOException {
171 
172         if (isInitialized()) {
173             throw new IOException("NSS is already initialized");
174         }
175 
176         if (dbMode == null) {
177             throw new NullPointerException();
178         }
179         if ((dbMode != DbMode.NO_DB) && (configDir == null)) {
180             throw new NullPointerException();
181         }
182         String platformLibName = System.mapLibraryName("nss3");
183         String platformPath;
184         if (nssLibDir == null) {
185             platformPath = platformLibName;
186         } else {
187             File base = new File(nssLibDir);
188             if (base.isDirectory() == false) {
189                 throw new IOException("nssLibDir must be a directory:" + nssLibDir);
190             }
191             File platformFile = new File(base, platformLibName);
192             if (platformFile.isFile() == false) {
193                 throw new FileNotFoundException(platformFile.getPath());
194             }
195             platformPath = platformFile.getPath();
196         }
197 
198         if (configDir != null) {
199             String configDirPath = null;
200             String sqlPrefix = "sql:";
201             if (!configDir.startsWith(sqlPrefix)) {
202                 configDirPath = configDir;
203             } else {
204                 StringBuilder configDirPathSB = new StringBuilder(configDir);
205                 configDirPath = configDirPathSB.substring(sqlPrefix.length());
206             }
207             File configBase = new File(configDirPath);
208             if (configBase.isDirectory() == false ) {
209                 throw new IOException("configDir must be a directory: " + configDirPath);
210             }
211             if (!configDir.startsWith(sqlPrefix)) {
212                 File secmodFile = new File(configBase, "secmod.db");
213                 if (secmodFile.isFile() == false) {
214                     throw new FileNotFoundException(secmodFile.getPath());
215                 }
216             }
217         }
218 
219         if (DEBUG) System.out.println("lib: " + platformPath);
220         nssHandle = nssLoadLibrary(platformPath);
221         if (DEBUG) System.out.println("handle: " + nssHandle);
222         fetchVersions();
223         if (supported == false) {
224             throw new IOException
225                 ("The specified version of NSS is incompatible, "
226                 + "3.7 or later required");
227         }
228 
229         if (DEBUG) System.out.println("dir: " + configDir);
230         boolean initok = nssInitialize(dbMode.functionName, nssHandle,
231             configDir, nssOptimizeSpace);
232         if (DEBUG) System.out.println("init: " + initok);
233         if (initok == false) {
234             throw new IOException("NSS initialization failed");
235         }
236 
237         this.configDir = configDir;
238         this.nssLibDir = nssLibDir;
239     }
240 
241     /**
242      * Return an immutable list of all available modules.
243      *
244      * @throws IllegalStateException if this Secmod is misconfigured
245      *   or not initialized
246      */
getModules()247     public synchronized List<Module> getModules() {
248         try {
249             if (isInitialized() == false) {
250                 throw new IllegalStateException("NSS not initialized");
251             }
252         } catch (IOException e) {
253             // IOException if misconfigured
254             throw new IllegalStateException(e);
255         }
256         if (modules == null) {
257             @SuppressWarnings("unchecked")
258             List<Module> modules = (List<Module>)nssGetModuleList(nssHandle,
259                 nssLibDir);
260             this.modules = Collections.unmodifiableList(modules);
261         }
262         return modules;
263     }
264 
getDigest(X509Certificate cert, String algorithm)265     private static byte[] getDigest(X509Certificate cert, String algorithm) {
266         try {
267             MessageDigest md = MessageDigest.getInstance(algorithm);
268             return md.digest(cert.getEncoded());
269         } catch (GeneralSecurityException e) {
270             throw new ProviderException(e);
271         }
272     }
273 
isTrusted(X509Certificate cert, TrustType trustType)274     boolean isTrusted(X509Certificate cert, TrustType trustType) {
275         Bytes bytes = new Bytes(getDigest(cert, "SHA-1"));
276         TrustAttributes attr = getModuleTrust(ModuleType.KEYSTORE, bytes);
277         if (attr == null) {
278             attr = getModuleTrust(ModuleType.FIPS, bytes);
279             if (attr == null) {
280                 attr = getModuleTrust(ModuleType.TRUSTANCHOR, bytes);
281             }
282         }
283         return (attr == null) ? false : attr.isTrusted(trustType);
284     }
285 
getModuleTrust(ModuleType type, Bytes bytes)286     private TrustAttributes getModuleTrust(ModuleType type, Bytes bytes) {
287         Module module = getModule(type);
288         TrustAttributes t = (module == null) ? null : module.getTrust(bytes);
289         return t;
290     }
291 
292     /**
293      * Constants describing the different types of NSS modules.
294      * For this API, NSS modules are classified as either one
295      * of the internal modules delivered as part of NSS or
296      * as an external module provided by a 3rd party.
297      */
298     public static enum ModuleType {
299         /**
300          * The NSS Softtoken crypto module. This is the first
301          * slot of the softtoken object.
302          * This module provides
303          * implementations for cryptographic algorithms but no KeyStore.
304          */
305         CRYPTO,
306         /**
307          * The NSS Softtoken KeyStore module. This is the second
308          * slot of the softtoken object.
309          * This module provides
310          * implementations for cryptographic algorithms (after login)
311          * and the KeyStore.
312          */
313         KEYSTORE,
314         /**
315          * The NSS Softtoken module in FIPS mode. Note that in FIPS mode the
316          * softtoken presents only one slot, not separate CRYPTO and KEYSTORE
317          * slots as in non-FIPS mode.
318          */
319         FIPS,
320         /**
321          * The NSS builtin trust anchor module. This is the
322          * NSSCKBI object. It provides no crypto functions.
323          */
324         TRUSTANCHOR,
325         /**
326          * An external module.
327          */
328         EXTERNAL,
329     }
330 
331     /**
332      * Returns the first module of the specified type. If no such
333      * module exists, this method returns null.
334      *
335      * @throws IllegalStateException if this Secmod is misconfigured
336      *   or not initialized
337      */
getModule(ModuleType type)338     public Module getModule(ModuleType type) {
339         for (Module module : getModules()) {
340             if (module.getType() == type) {
341                 return module;
342             }
343         }
344         return null;
345     }
346 
347     static final String TEMPLATE_EXTERNAL =
348         "library = %s\n"
349         + "name = \"%s\"\n"
350         + "slotListIndex = %d\n";
351 
352     static final String TEMPLATE_TRUSTANCHOR =
353         "library = %s\n"
354         + "name = \"NSS Trust Anchors\"\n"
355         + "slotListIndex = 0\n"
356         + "enabledMechanisms = { KeyStore }\n"
357         + "nssUseSecmodTrust = true\n";
358 
359     static final String TEMPLATE_CRYPTO =
360         "library = %s\n"
361         + "name = \"NSS SoftToken Crypto\"\n"
362         + "slotListIndex = 0\n"
363         + "disabledMechanisms = { KeyStore }\n";
364 
365     static final String TEMPLATE_KEYSTORE =
366         "library = %s\n"
367         + "name = \"NSS SoftToken KeyStore\"\n"
368         + "slotListIndex = 1\n"
369         + "nssUseSecmodTrust = true\n";
370 
371     static final String TEMPLATE_FIPS =
372         "library = %s\n"
373         + "name = \"NSS FIPS SoftToken\"\n"
374         + "slotListIndex = 0\n"
375         + "nssUseSecmodTrust = true\n";
376 
377     /**
378      * A representation of one PKCS#11 slot in a PKCS#11 module.
379      */
380     public static final class Module {
381         // path of the native library
382         final String libraryName;
383         // descriptive name used by NSS
384         final String commonName;
385         final int slot;
386         final ModuleType type;
387 
388         private String config;
389         private SunPKCS11 provider;
390 
391         // trust attributes. Used for the KEYSTORE and TRUSTANCHOR modules only
392         private Map<Bytes,TrustAttributes> trust;
393 
Module(String libraryDir, String libraryName, String commonName, boolean fips, int slot)394         Module(String libraryDir, String libraryName, String commonName,
395                 boolean fips, int slot) {
396             ModuleType type;
397 
398             if ((libraryName == null) || (libraryName.length() == 0)) {
399                 // must be softtoken
400                 libraryName = System.mapLibraryName(SOFTTOKEN_LIB_NAME);
401                 if (fips == false) {
402                     type = (slot == 0) ? ModuleType.CRYPTO : ModuleType.KEYSTORE;
403                 } else {
404                     type = ModuleType.FIPS;
405                     if (slot != 0) {
406                         throw new RuntimeException
407                             ("Slot index should be 0 for FIPS slot");
408                     }
409                 }
410             } else {
411                 if (libraryName.endsWith(System.mapLibraryName(TRUST_LIB_NAME))
412                         || commonName.equals("Builtin Roots Module")) {
413                     type = ModuleType.TRUSTANCHOR;
414                 } else {
415                     type = ModuleType.EXTERNAL;
416                 }
417             }
418             // On Ubuntu the libsoftokn3 library is located in a subdirectory
419             // of the system libraries directory. (Since Ubuntu 11.04.)
420             File libraryFile = new File(libraryDir, libraryName);
421             if (!libraryFile.isFile()) {
422                File failover = new File(libraryDir, "nss/" + libraryName);
423                if (failover.isFile()) {
424                    libraryFile = failover;
425                }
426             }
427             this.libraryName = libraryFile.getPath();
428             this.commonName = commonName;
429             this.slot = slot;
430             this.type = type;
431             initConfiguration();
432         }
433 
initConfiguration()434         private void initConfiguration() {
435             switch (type) {
436             case EXTERNAL:
437                 config = String.format(TEMPLATE_EXTERNAL, libraryName,
438                                             commonName + " " + slot, slot);
439                 break;
440             case CRYPTO:
441                 config = String.format(TEMPLATE_CRYPTO, libraryName);
442                 break;
443             case KEYSTORE:
444                 config = String.format(TEMPLATE_KEYSTORE, libraryName);
445                 break;
446             case FIPS:
447                 config = String.format(TEMPLATE_FIPS, libraryName);
448                 break;
449             case TRUSTANCHOR:
450                 config = String.format(TEMPLATE_TRUSTANCHOR, libraryName);
451                 break;
452             default:
453                 throw new RuntimeException("Unknown module type: " + type);
454             }
455         }
456 
457         /**
458          * Get the configuration for this module. This is a string
459          * in the SunPKCS11 configuration format. It can be
460          * customized with additional options and then made
461          * current using the setConfiguration() method.
462          */
463         @Deprecated
getConfiguration()464         public synchronized String getConfiguration() {
465             return config;
466         }
467 
468         /**
469          * Set the configuration for this module.
470          *
471          * @throws IllegalStateException if the associated provider
472          *   instance has already been created.
473          */
474         @Deprecated
setConfiguration(String config)475         public synchronized void setConfiguration(String config) {
476             if (provider != null) {
477                 throw new IllegalStateException("Provider instance already created");
478             }
479             this.config = config;
480         }
481 
482         /**
483          * Return the pathname of the native library that implements
484          * this module. For example, /usr/lib/libpkcs11.so.
485          */
getLibraryName()486         public String getLibraryName() {
487             return libraryName;
488         }
489 
490         /**
491          * Returns the type of this module.
492          */
getType()493         public ModuleType getType() {
494             return type;
495         }
496 
497         /**
498          * Returns the provider instance that is associated with this
499          * module. The first call to this method creates the provider
500          * instance.
501          */
502         @Deprecated
getProvider()503         public synchronized Provider getProvider() {
504             if (provider == null) {
505                 provider = newProvider();
506             }
507             return provider;
508         }
509 
hasInitializedProvider()510         synchronized boolean hasInitializedProvider() {
511             return provider != null;
512         }
513 
setProvider(SunPKCS11 p)514         void setProvider(SunPKCS11 p) {
515             if (provider != null) {
516                 throw new ProviderException("Secmod provider already initialized");
517             }
518             provider = p;
519         }
520 
newProvider()521         private SunPKCS11 newProvider() {
522             try {
523                 return new SunPKCS11(new Config("--" + config));
524             } catch (Exception e) {
525                 // XXX
526                 throw new ProviderException(e);
527             }
528         }
529 
setTrust(Token token, X509Certificate cert)530         synchronized void setTrust(Token token, X509Certificate cert) {
531             Bytes bytes = new Bytes(getDigest(cert, "SHA-1"));
532             TrustAttributes attr = getTrust(bytes);
533             if (attr == null) {
534                 attr = new TrustAttributes(token, cert, bytes, CKT_NETSCAPE_TRUSTED_DELEGATOR);
535                 trust.put(bytes, attr);
536             } else {
537                 // does it already have the correct trust settings?
538                 if (attr.isTrusted(TrustType.ALL) == false) {
539                     // XXX not yet implemented
540                     throw new ProviderException("Cannot change existing trust attributes");
541                 }
542             }
543         }
544 
getTrust(Bytes hash)545         TrustAttributes getTrust(Bytes hash) {
546             if (trust == null) {
547                 // If provider is not set, create a temporary provider to
548                 // retrieve the trust information. This can happen if we need
549                 // to get the trust information for the trustanchor module
550                 // because we need to look for user customized settings in the
551                 // keystore module (which may not have a provider created yet).
552                 // Creating a temporary provider and then dropping it on the
553                 // floor immediately is flawed, but it's the best we can do
554                 // for now.
555                 synchronized (this) {
556                     SunPKCS11 p = provider;
557                     if (p == null) {
558                         p = newProvider();
559                     }
560                     try {
561                         trust = Secmod.getTrust(p);
562                     } catch (PKCS11Exception e) {
563                         throw new RuntimeException(e);
564                     }
565                 }
566             }
567             return trust.get(hash);
568         }
569 
toString()570         public String toString() {
571             return
572             commonName + " (" + type + ", " + libraryName + ", slot " + slot + ")";
573         }
574 
575     }
576 
577     /**
578      * Constants representing NSS trust categories.
579      */
580     public static enum TrustType {
581         /** Trusted for all purposes */
582         ALL,
583         /** Trusted for SSL client authentication */
584         CLIENT_AUTH,
585         /** Trusted for SSL server authentication */
586         SERVER_AUTH,
587         /** Trusted for code signing */
588         CODE_SIGNING,
589         /** Trusted for email protection */
590         EMAIL_PROTECTION,
591     }
592 
593     public static enum DbMode {
594         READ_WRITE("NSS_InitReadWrite"),
595         READ_ONLY ("NSS_Init"),
596         NO_DB     ("NSS_NoDB_Init");
597 
598         final String functionName;
DbMode(String functionName)599         DbMode(String functionName) {
600             this.functionName = functionName;
601         }
602     }
603 
604     /**
605      * A LoadStoreParameter for use with the NSS Softtoken or
606      * NSS TrustAnchor KeyStores.
607      * <p>
608      * It allows the set of trusted certificates that are returned by
609      * the KeyStore to be specified.
610      */
611     public static final class KeyStoreLoadParameter implements LoadStoreParameter {
612         final TrustType trustType;
613         final ProtectionParameter protection;
KeyStoreLoadParameter(TrustType trustType, char[] password)614         public KeyStoreLoadParameter(TrustType trustType, char[] password) {
615             this(trustType, new PasswordProtection(password));
616 
617         }
KeyStoreLoadParameter(TrustType trustType, ProtectionParameter prot)618         public KeyStoreLoadParameter(TrustType trustType, ProtectionParameter prot) {
619             if (trustType == null) {
620                 throw new NullPointerException("trustType must not be null");
621             }
622             this.trustType = trustType;
623             this.protection = prot;
624         }
getProtectionParameter()625         public ProtectionParameter getProtectionParameter() {
626             return protection;
627         }
getTrustType()628         public TrustType getTrustType() {
629             return trustType;
630         }
631     }
632 
633     static class TrustAttributes {
634         final long handle;
635         final long clientAuth, serverAuth, codeSigning, emailProtection;
636         final byte[] shaHash;
TrustAttributes(Token token, X509Certificate cert, Bytes bytes, long trustValue)637         TrustAttributes(Token token, X509Certificate cert, Bytes bytes, long trustValue) {
638             Session session = null;
639             try {
640                 session = token.getOpSession();
641                 // XXX use KeyStore TrustType settings to determine which
642                 // attributes to set
643                 CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
644                     new CK_ATTRIBUTE(CKA_TOKEN, true),
645                     new CK_ATTRIBUTE(CKA_CLASS, CKO_NETSCAPE_TRUST),
646                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_SERVER_AUTH, trustValue),
647                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CODE_SIGNING, trustValue),
648                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_EMAIL_PROTECTION, trustValue),
649                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CLIENT_AUTH, trustValue),
650                     new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_SHA1_HASH, bytes.b),
651                     new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_MD5_HASH, getDigest(cert, "MD5")),
652                     new CK_ATTRIBUTE(CKA_ISSUER, cert.getIssuerX500Principal().getEncoded()),
653                     new CK_ATTRIBUTE(CKA_SERIAL_NUMBER, cert.getSerialNumber().toByteArray()),
654                     // XXX per PKCS#11 spec, the serial number should be in ASN.1
655                 };
656                 handle = token.p11.C_CreateObject(session.id(), attrs);
657                 shaHash = bytes.b;
658                 clientAuth = trustValue;
659                 serverAuth = trustValue;
660                 codeSigning = trustValue;
661                 emailProtection = trustValue;
662             } catch (PKCS11Exception e) {
663                 throw new ProviderException("Could not create trust object", e);
664             } finally {
665                 token.releaseSession(session);
666             }
667         }
TrustAttributes(Token token, Session session, long handle)668         TrustAttributes(Token token, Session session, long handle)
669                         throws PKCS11Exception {
670             this.handle = handle;
671             CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
672                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_SERVER_AUTH),
673                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CODE_SIGNING),
674                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_EMAIL_PROTECTION),
675                 new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_SHA1_HASH),
676             };
677 
678             token.p11.C_GetAttributeValue(session.id(), handle, attrs);
679             serverAuth = attrs[0].getLong();
680             codeSigning = attrs[1].getLong();
681             emailProtection = attrs[2].getLong();
682             shaHash = attrs[3].getByteArray();
683 
684             attrs = new CK_ATTRIBUTE[] {
685                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CLIENT_AUTH),
686             };
687             long c;
688             try {
689                 token.p11.C_GetAttributeValue(session.id(), handle, attrs);
690                 c = attrs[0].getLong();
691             } catch (PKCS11Exception e) {
692                 // trust anchor module does not support this attribute
693                 c = serverAuth;
694             }
695             clientAuth = c;
696         }
getHash()697         Bytes getHash() {
698             return new Bytes(shaHash);
699         }
isTrusted(TrustType type)700         boolean isTrusted(TrustType type) {
701             switch (type) {
702             case CLIENT_AUTH:
703                 return isTrusted(clientAuth);
704             case SERVER_AUTH:
705                 return isTrusted(serverAuth);
706             case CODE_SIGNING:
707                 return isTrusted(codeSigning);
708             case EMAIL_PROTECTION:
709                 return isTrusted(emailProtection);
710             case ALL:
711                 return isTrusted(TrustType.CLIENT_AUTH)
712                     && isTrusted(TrustType.SERVER_AUTH)
713                     && isTrusted(TrustType.CODE_SIGNING)
714                     && isTrusted(TrustType.EMAIL_PROTECTION);
715             default:
716                 return false;
717             }
718         }
719 
isTrusted(long l)720         private boolean isTrusted(long l) {
721             // XXX CKT_TRUSTED?
722             return (l == CKT_NETSCAPE_TRUSTED_DELEGATOR);
723         }
724 
725     }
726 
727     private static class Bytes {
728         final byte[] b;
Bytes(byte[] b)729         Bytes(byte[] b) {
730             this.b = b;
731         }
hashCode()732         public int hashCode() {
733             return Arrays.hashCode(b);
734         }
equals(Object o)735         public boolean equals(Object o) {
736             if (this == o) {
737                 return true;
738             }
739             if (o instanceof Bytes == false) {
740                 return false;
741             }
742             Bytes other = (Bytes)o;
743             return Arrays.equals(this.b, other.b);
744         }
745     }
746 
getTrust(SunPKCS11 provider)747     private static Map<Bytes,TrustAttributes> getTrust(SunPKCS11 provider)
748             throws PKCS11Exception {
749         Map<Bytes,TrustAttributes> trustMap = new HashMap<Bytes,TrustAttributes>();
750         Token token = provider.getToken();
751         Session session = null;
752         boolean exceptionOccurred = true;
753         try {
754             session = token.getOpSession();
755             int MAX_NUM = 8192;
756             CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
757                 new CK_ATTRIBUTE(CKA_CLASS, CKO_NETSCAPE_TRUST),
758             };
759             token.p11.C_FindObjectsInit(session.id(), attrs);
760             long[] handles = token.p11.C_FindObjects(session.id(), MAX_NUM);
761             token.p11.C_FindObjectsFinal(session.id());
762             if (DEBUG) System.out.println("handles: " + handles.length);
763 
764             for (long handle : handles) {
765                 try {
766                     TrustAttributes trust = new TrustAttributes(token, session, handle);
767                     trustMap.put(trust.getHash(), trust);
768                 } catch (PKCS11Exception e) {
769                     // skip put on pkcs11 error
770                 }
771             }
772             exceptionOccurred = false;
773         } finally {
774             if (exceptionOccurred) {
775                 token.killSession(session);
776             } else {
777                 token.releaseSession(session);
778             }
779         }
780         return trustMap;
781     }
782 
nssGetLibraryHandle(String libraryName)783     private static native long nssGetLibraryHandle(String libraryName);
784 
nssLoadLibrary(String name)785     private static native long nssLoadLibrary(String name) throws IOException;
786 
nssVersionCheck(long handle, String minVersion)787     private static native boolean nssVersionCheck(long handle, String minVersion);
788 
nssInitialize(String functionName, long handle, String configDir, boolean nssOptimizeSpace)789     private static native boolean nssInitialize(String functionName, long handle, String configDir, boolean nssOptimizeSpace);
790 
nssGetModuleList(long handle, String libDir)791     private static native Object nssGetModuleList(long handle, String libDir);
792 
793 }
794