jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/Secmod.java
changeset 43248 5e15de85a1a0
parent 43247 8d242299a219
child 43249 b017b10f62ab
equal deleted inserted replaced
43247:8d242299a219 43248:5e15de85a1a0
     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 {
       
    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 
       
    89     private Secmod() {
       
    90         // empty
       
    91     }
       
    92 
       
    93     /**
       
    94      * Return the singleton Secmod instance.
       
    95      */
       
    96     public static Secmod getInstance() {
       
    97         return INSTANCE;
       
    98     }
       
    99 
       
   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 
       
   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      */
       
   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 
       
   138     String getConfigDir() {
       
   139         return configDir;
       
   140     }
       
   141 
       
   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      */
       
   159     public void initialize(String configDir, String nssLibDir)
       
   160             throws IOException {
       
   161         initialize(DbMode.READ_WRITE, configDir, nssLibDir, false);
       
   162     }
       
   163 
       
   164     public void initialize(DbMode dbMode, String configDir, String nssLibDir)
       
   165             throws IOException {
       
   166         initialize(dbMode, configDir, nssLibDir, false);
       
   167     }
       
   168 
       
   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             File configBase = new File(configDir);
       
   200             if (configBase.isDirectory() == false ) {
       
   201                 throw new IOException("configDir must be a directory: " + configDir);
       
   202             }
       
   203             File secmodFile = new File(configBase, "secmod.db");
       
   204             if (secmodFile.isFile() == false) {
       
   205                 throw new FileNotFoundException(secmodFile.getPath());
       
   206             }
       
   207         }
       
   208 
       
   209         if (DEBUG) System.out.println("lib: " + platformPath);
       
   210         nssHandle = nssLoadLibrary(platformPath);
       
   211         if (DEBUG) System.out.println("handle: " + nssHandle);
       
   212         fetchVersions();
       
   213         if (supported == false) {
       
   214             throw new IOException
       
   215                 ("The specified version of NSS is incompatible, "
       
   216                 + "3.7 or later required");
       
   217         }
       
   218 
       
   219         if (DEBUG) System.out.println("dir: " + configDir);
       
   220         boolean initok = nssInitialize(dbMode.functionName, nssHandle,
       
   221             configDir, nssOptimizeSpace);
       
   222         if (DEBUG) System.out.println("init: " + initok);
       
   223         if (initok == false) {
       
   224             throw new IOException("NSS initialization failed");
       
   225         }
       
   226 
       
   227         this.configDir = configDir;
       
   228         this.nssLibDir = nssLibDir;
       
   229     }
       
   230 
       
   231     /**
       
   232      * Return an immutable list of all available modules.
       
   233      *
       
   234      * @throws IllegalStateException if this Secmod is misconfigured
       
   235      *   or not initialized
       
   236      */
       
   237     public synchronized List<Module> getModules() {
       
   238         try {
       
   239             if (isInitialized() == false) {
       
   240                 throw new IllegalStateException("NSS not initialized");
       
   241             }
       
   242         } catch (IOException e) {
       
   243             // IOException if misconfigured
       
   244             throw new IllegalStateException(e);
       
   245         }
       
   246         if (modules == null) {
       
   247             @SuppressWarnings("unchecked")
       
   248             List<Module> modules = (List<Module>)nssGetModuleList(nssHandle,
       
   249                 nssLibDir);
       
   250             this.modules = Collections.unmodifiableList(modules);
       
   251         }
       
   252         return modules;
       
   253     }
       
   254 
       
   255     private static byte[] getDigest(X509Certificate cert, String algorithm) {
       
   256         try {
       
   257             MessageDigest md = MessageDigest.getInstance(algorithm);
       
   258             return md.digest(cert.getEncoded());
       
   259         } catch (GeneralSecurityException e) {
       
   260             throw new ProviderException(e);
       
   261         }
       
   262     }
       
   263 
       
   264     boolean isTrusted(X509Certificate cert, TrustType trustType) {
       
   265         Bytes bytes = new Bytes(getDigest(cert, "SHA-1"));
       
   266         TrustAttributes attr = getModuleTrust(ModuleType.KEYSTORE, bytes);
       
   267         if (attr == null) {
       
   268             attr = getModuleTrust(ModuleType.FIPS, bytes);
       
   269             if (attr == null) {
       
   270                 attr = getModuleTrust(ModuleType.TRUSTANCHOR, bytes);
       
   271             }
       
   272         }
       
   273         return (attr == null) ? false : attr.isTrusted(trustType);
       
   274     }
       
   275 
       
   276     private TrustAttributes getModuleTrust(ModuleType type, Bytes bytes) {
       
   277         Module module = getModule(type);
       
   278         TrustAttributes t = (module == null) ? null : module.getTrust(bytes);
       
   279         return t;
       
   280     }
       
   281 
       
   282     /**
       
   283      * Constants describing the different types of NSS modules.
       
   284      * For this API, NSS modules are classified as either one
       
   285      * of the internal modules delivered as part of NSS or
       
   286      * as an external module provided by a 3rd party.
       
   287      */
       
   288     public static enum ModuleType {
       
   289         /**
       
   290          * The NSS Softtoken crypto module. This is the first
       
   291          * slot of the softtoken object.
       
   292          * This module provides
       
   293          * implementations for cryptographic algorithms but no KeyStore.
       
   294          */
       
   295         CRYPTO,
       
   296         /**
       
   297          * The NSS Softtoken KeyStore module. This is the second
       
   298          * slot of the softtoken object.
       
   299          * This module provides
       
   300          * implementations for cryptographic algorithms (after login)
       
   301          * and the KeyStore.
       
   302          */
       
   303         KEYSTORE,
       
   304         /**
       
   305          * The NSS Softtoken module in FIPS mode. Note that in FIPS mode the
       
   306          * softtoken presents only one slot, not separate CRYPTO and KEYSTORE
       
   307          * slots as in non-FIPS mode.
       
   308          */
       
   309         FIPS,
       
   310         /**
       
   311          * The NSS builtin trust anchor module. This is the
       
   312          * NSSCKBI object. It provides no crypto functions.
       
   313          */
       
   314         TRUSTANCHOR,
       
   315         /**
       
   316          * An external module.
       
   317          */
       
   318         EXTERNAL,
       
   319     }
       
   320 
       
   321     /**
       
   322      * Returns the first module of the specified type. If no such
       
   323      * module exists, this method returns null.
       
   324      *
       
   325      * @throws IllegalStateException if this Secmod is misconfigured
       
   326      *   or not initialized
       
   327      */
       
   328     public Module getModule(ModuleType type) {
       
   329         for (Module module : getModules()) {
       
   330             if (module.getType() == type) {
       
   331                 return module;
       
   332             }
       
   333         }
       
   334         return null;
       
   335     }
       
   336 
       
   337     static final String TEMPLATE_EXTERNAL =
       
   338         "library = %s\n"
       
   339         + "name = \"%s\"\n"
       
   340         + "slotListIndex = %d\n";
       
   341 
       
   342     static final String TEMPLATE_TRUSTANCHOR =
       
   343         "library = %s\n"
       
   344         + "name = \"NSS Trust Anchors\"\n"
       
   345         + "slotListIndex = 0\n"
       
   346         + "enabledMechanisms = { KeyStore }\n"
       
   347         + "nssUseSecmodTrust = true\n";
       
   348 
       
   349     static final String TEMPLATE_CRYPTO =
       
   350         "library = %s\n"
       
   351         + "name = \"NSS SoftToken Crypto\"\n"
       
   352         + "slotListIndex = 0\n"
       
   353         + "disabledMechanisms = { KeyStore }\n";
       
   354 
       
   355     static final String TEMPLATE_KEYSTORE =
       
   356         "library = %s\n"
       
   357         + "name = \"NSS SoftToken KeyStore\"\n"
       
   358         + "slotListIndex = 1\n"
       
   359         + "nssUseSecmodTrust = true\n";
       
   360 
       
   361     static final String TEMPLATE_FIPS =
       
   362         "library = %s\n"
       
   363         + "name = \"NSS FIPS SoftToken\"\n"
       
   364         + "slotListIndex = 0\n"
       
   365         + "nssUseSecmodTrust = true\n";
       
   366 
       
   367     /**
       
   368      * A representation of one PKCS#11 slot in a PKCS#11 module.
       
   369      */
       
   370     public static final class Module {
       
   371         // path of the native library
       
   372         final String libraryName;
       
   373         // descriptive name used by NSS
       
   374         final String commonName;
       
   375         final int slot;
       
   376         final ModuleType type;
       
   377 
       
   378         private String config;
       
   379         private SunPKCS11 provider;
       
   380 
       
   381         // trust attributes. Used for the KEYSTORE and TRUSTANCHOR modules only
       
   382         private Map<Bytes,TrustAttributes> trust;
       
   383 
       
   384         Module(String libraryDir, String libraryName, String commonName,
       
   385                 boolean fips, int slot) {
       
   386             ModuleType type;
       
   387 
       
   388             if ((libraryName == null) || (libraryName.length() == 0)) {
       
   389                 // must be softtoken
       
   390                 libraryName = System.mapLibraryName(SOFTTOKEN_LIB_NAME);
       
   391                 if (fips == false) {
       
   392                     type = (slot == 0) ? ModuleType.CRYPTO : ModuleType.KEYSTORE;
       
   393                 } else {
       
   394                     type = ModuleType.FIPS;
       
   395                     if (slot != 0) {
       
   396                         throw new RuntimeException
       
   397                             ("Slot index should be 0 for FIPS slot");
       
   398                     }
       
   399                 }
       
   400             } else {
       
   401                 if (libraryName.endsWith(System.mapLibraryName(TRUST_LIB_NAME))
       
   402                         || commonName.equals("Builtin Roots Module")) {
       
   403                     type = ModuleType.TRUSTANCHOR;
       
   404                 } else {
       
   405                     type = ModuleType.EXTERNAL;
       
   406                 }
       
   407                 if (fips) {
       
   408                     throw new RuntimeException("FIPS flag set for non-internal "
       
   409                         + "module: " + libraryName + ", " + commonName);
       
   410                 }
       
   411             }
       
   412             // On Ubuntu the libsoftokn3 library is located in a subdirectory
       
   413             // of the system libraries directory. (Since Ubuntu 11.04.)
       
   414             File libraryFile = new File(libraryDir, libraryName);
       
   415             if (!libraryFile.isFile()) {
       
   416                File failover = new File(libraryDir, "nss/" + libraryName);
       
   417                if (failover.isFile()) {
       
   418                    libraryFile = failover;
       
   419                }
       
   420             }
       
   421             this.libraryName = libraryFile.getPath();
       
   422             this.commonName = commonName;
       
   423             this.slot = slot;
       
   424             this.type = type;
       
   425             initConfiguration();
       
   426         }
       
   427 
       
   428         private void initConfiguration() {
       
   429             switch (type) {
       
   430             case EXTERNAL:
       
   431                 config = String.format(TEMPLATE_EXTERNAL, libraryName,
       
   432                                             commonName + " " + slot, slot);
       
   433                 break;
       
   434             case CRYPTO:
       
   435                 config = String.format(TEMPLATE_CRYPTO, libraryName);
       
   436                 break;
       
   437             case KEYSTORE:
       
   438                 config = String.format(TEMPLATE_KEYSTORE, libraryName);
       
   439                 break;
       
   440             case FIPS:
       
   441                 config = String.format(TEMPLATE_FIPS, libraryName);
       
   442                 break;
       
   443             case TRUSTANCHOR:
       
   444                 config = String.format(TEMPLATE_TRUSTANCHOR, libraryName);
       
   445                 break;
       
   446             default:
       
   447                 throw new RuntimeException("Unknown module type: " + type);
       
   448             }
       
   449         }
       
   450 
       
   451         /**
       
   452          * Get the configuration for this module. This is a string
       
   453          * in the SunPKCS11 configuration format. It can be
       
   454          * customized with additional options and then made
       
   455          * current using the setConfiguration() method.
       
   456          */
       
   457         @Deprecated
       
   458         public synchronized String getConfiguration() {
       
   459             return config;
       
   460         }
       
   461 
       
   462         /**
       
   463          * Set the configuration for this module.
       
   464          *
       
   465          * @throws IllegalStateException if the associated provider
       
   466          *   instance has already been created.
       
   467          */
       
   468         @Deprecated
       
   469         public synchronized void setConfiguration(String config) {
       
   470             if (provider != null) {
       
   471                 throw new IllegalStateException("Provider instance already created");
       
   472             }
       
   473             this.config = config;
       
   474         }
       
   475 
       
   476         /**
       
   477          * Return the pathname of the native library that implements
       
   478          * this module. For example, /usr/lib/libpkcs11.so.
       
   479          */
       
   480         public String getLibraryName() {
       
   481             return libraryName;
       
   482         }
       
   483 
       
   484         /**
       
   485          * Returns the type of this module.
       
   486          */
       
   487         public ModuleType getType() {
       
   488             return type;
       
   489         }
       
   490 
       
   491         /**
       
   492          * Returns the provider instance that is associated with this
       
   493          * module. The first call to this method creates the provider
       
   494          * instance.
       
   495          */
       
   496         @Deprecated
       
   497         public synchronized Provider getProvider() {
       
   498             if (provider == null) {
       
   499                 provider = newProvider();
       
   500             }
       
   501             return provider;
       
   502         }
       
   503 
       
   504         synchronized boolean hasInitializedProvider() {
       
   505             return provider != null;
       
   506         }
       
   507 
       
   508         void setProvider(SunPKCS11 p) {
       
   509             if (provider != null) {
       
   510                 throw new ProviderException("Secmod provider already initialized");
       
   511             }
       
   512             provider = p;
       
   513         }
       
   514 
       
   515         private SunPKCS11 newProvider() {
       
   516             try {
       
   517                 return new SunPKCS11(new Config("--" + config));
       
   518             } catch (Exception e) {
       
   519                 // XXX
       
   520                 throw new ProviderException(e);
       
   521             }
       
   522         }
       
   523 
       
   524         synchronized void setTrust(Token token, X509Certificate cert) {
       
   525             Bytes bytes = new Bytes(getDigest(cert, "SHA-1"));
       
   526             TrustAttributes attr = getTrust(bytes);
       
   527             if (attr == null) {
       
   528                 attr = new TrustAttributes(token, cert, bytes, CKT_NETSCAPE_TRUSTED_DELEGATOR);
       
   529                 trust.put(bytes, attr);
       
   530             } else {
       
   531                 // does it already have the correct trust settings?
       
   532                 if (attr.isTrusted(TrustType.ALL) == false) {
       
   533                     // XXX not yet implemented
       
   534                     throw new ProviderException("Cannot change existing trust attributes");
       
   535                 }
       
   536             }
       
   537         }
       
   538 
       
   539         TrustAttributes getTrust(Bytes hash) {
       
   540             if (trust == null) {
       
   541                 // If provider is not set, create a temporary provider to
       
   542                 // retrieve the trust information. This can happen if we need
       
   543                 // to get the trust information for the trustanchor module
       
   544                 // because we need to look for user customized settings in the
       
   545                 // keystore module (which may not have a provider created yet).
       
   546                 // Creating a temporary provider and then dropping it on the
       
   547                 // floor immediately is flawed, but it's the best we can do
       
   548                 // for now.
       
   549                 synchronized (this) {
       
   550                     SunPKCS11 p = provider;
       
   551                     if (p == null) {
       
   552                         p = newProvider();
       
   553                     }
       
   554                     try {
       
   555                         trust = Secmod.getTrust(p);
       
   556                     } catch (PKCS11Exception e) {
       
   557                         throw new RuntimeException(e);
       
   558                     }
       
   559                 }
       
   560             }
       
   561             return trust.get(hash);
       
   562         }
       
   563 
       
   564         public String toString() {
       
   565             return
       
   566             commonName + " (" + type + ", " + libraryName + ", slot " + slot + ")";
       
   567         }
       
   568 
       
   569     }
       
   570 
       
   571     /**
       
   572      * Constants representing NSS trust categories.
       
   573      */
       
   574     public static enum TrustType {
       
   575         /** Trusted for all purposes */
       
   576         ALL,
       
   577         /** Trusted for SSL client authentication */
       
   578         CLIENT_AUTH,
       
   579         /** Trusted for SSL server authentication */
       
   580         SERVER_AUTH,
       
   581         /** Trusted for code signing */
       
   582         CODE_SIGNING,
       
   583         /** Trusted for email protection */
       
   584         EMAIL_PROTECTION,
       
   585     }
       
   586 
       
   587     public static enum DbMode {
       
   588         READ_WRITE("NSS_InitReadWrite"),
       
   589         READ_ONLY ("NSS_Init"),
       
   590         NO_DB     ("NSS_NoDB_Init");
       
   591 
       
   592         final String functionName;
       
   593         DbMode(String functionName) {
       
   594             this.functionName = functionName;
       
   595         }
       
   596     }
       
   597 
       
   598     /**
       
   599      * A LoadStoreParameter for use with the NSS Softtoken or
       
   600      * NSS TrustAnchor KeyStores.
       
   601      * <p>
       
   602      * It allows the set of trusted certificates that are returned by
       
   603      * the KeyStore to be specified.
       
   604      */
       
   605     public static final class KeyStoreLoadParameter implements LoadStoreParameter {
       
   606         final TrustType trustType;
       
   607         final ProtectionParameter protection;
       
   608         public KeyStoreLoadParameter(TrustType trustType, char[] password) {
       
   609             this(trustType, new PasswordProtection(password));
       
   610 
       
   611         }
       
   612         public KeyStoreLoadParameter(TrustType trustType, ProtectionParameter prot) {
       
   613             if (trustType == null) {
       
   614                 throw new NullPointerException("trustType must not be null");
       
   615             }
       
   616             this.trustType = trustType;
       
   617             this.protection = prot;
       
   618         }
       
   619         public ProtectionParameter getProtectionParameter() {
       
   620             return protection;
       
   621         }
       
   622         public TrustType getTrustType() {
       
   623             return trustType;
       
   624         }
       
   625     }
       
   626 
       
   627     static class TrustAttributes {
       
   628         final long handle;
       
   629         final long clientAuth, serverAuth, codeSigning, emailProtection;
       
   630         final byte[] shaHash;
       
   631         TrustAttributes(Token token, X509Certificate cert, Bytes bytes, long trustValue) {
       
   632             Session session = null;
       
   633             try {
       
   634                 session = token.getOpSession();
       
   635                 // XXX use KeyStore TrustType settings to determine which
       
   636                 // attributes to set
       
   637                 CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
       
   638                     new CK_ATTRIBUTE(CKA_TOKEN, true),
       
   639                     new CK_ATTRIBUTE(CKA_CLASS, CKO_NETSCAPE_TRUST),
       
   640                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_SERVER_AUTH, trustValue),
       
   641                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CODE_SIGNING, trustValue),
       
   642                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_EMAIL_PROTECTION, trustValue),
       
   643                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CLIENT_AUTH, trustValue),
       
   644                     new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_SHA1_HASH, bytes.b),
       
   645                     new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_MD5_HASH, getDigest(cert, "MD5")),
       
   646                     new CK_ATTRIBUTE(CKA_ISSUER, cert.getIssuerX500Principal().getEncoded()),
       
   647                     new CK_ATTRIBUTE(CKA_SERIAL_NUMBER, cert.getSerialNumber().toByteArray()),
       
   648                     // XXX per PKCS#11 spec, the serial number should be in ASN.1
       
   649                 };
       
   650                 handle = token.p11.C_CreateObject(session.id(), attrs);
       
   651                 shaHash = bytes.b;
       
   652                 clientAuth = trustValue;
       
   653                 serverAuth = trustValue;
       
   654                 codeSigning = trustValue;
       
   655                 emailProtection = trustValue;
       
   656             } catch (PKCS11Exception e) {
       
   657                 throw new ProviderException("Could not create trust object", e);
       
   658             } finally {
       
   659                 token.releaseSession(session);
       
   660             }
       
   661         }
       
   662         TrustAttributes(Token token, Session session, long handle)
       
   663                         throws PKCS11Exception {
       
   664             this.handle = handle;
       
   665             CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
       
   666                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_SERVER_AUTH),
       
   667                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CODE_SIGNING),
       
   668                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_EMAIL_PROTECTION),
       
   669                 new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_SHA1_HASH),
       
   670             };
       
   671 
       
   672             token.p11.C_GetAttributeValue(session.id(), handle, attrs);
       
   673             serverAuth = attrs[0].getLong();
       
   674             codeSigning = attrs[1].getLong();
       
   675             emailProtection = attrs[2].getLong();
       
   676             shaHash = attrs[3].getByteArray();
       
   677 
       
   678             attrs = new CK_ATTRIBUTE[] {
       
   679                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CLIENT_AUTH),
       
   680             };
       
   681             long c;
       
   682             try {
       
   683                 token.p11.C_GetAttributeValue(session.id(), handle, attrs);
       
   684                 c = attrs[0].getLong();
       
   685             } catch (PKCS11Exception e) {
       
   686                 // trust anchor module does not support this attribute
       
   687                 c = serverAuth;
       
   688             }
       
   689             clientAuth = c;
       
   690         }
       
   691         Bytes getHash() {
       
   692             return new Bytes(shaHash);
       
   693         }
       
   694         boolean isTrusted(TrustType type) {
       
   695             switch (type) {
       
   696             case CLIENT_AUTH:
       
   697                 return isTrusted(clientAuth);
       
   698             case SERVER_AUTH:
       
   699                 return isTrusted(serverAuth);
       
   700             case CODE_SIGNING:
       
   701                 return isTrusted(codeSigning);
       
   702             case EMAIL_PROTECTION:
       
   703                 return isTrusted(emailProtection);
       
   704             case ALL:
       
   705                 return isTrusted(TrustType.CLIENT_AUTH)
       
   706                     && isTrusted(TrustType.SERVER_AUTH)
       
   707                     && isTrusted(TrustType.CODE_SIGNING)
       
   708                     && isTrusted(TrustType.EMAIL_PROTECTION);
       
   709             default:
       
   710                 return false;
       
   711             }
       
   712         }
       
   713 
       
   714         private boolean isTrusted(long l) {
       
   715             // XXX CKT_TRUSTED?
       
   716             return (l == CKT_NETSCAPE_TRUSTED_DELEGATOR);
       
   717         }
       
   718 
       
   719     }
       
   720 
       
   721     private static class Bytes {
       
   722         final byte[] b;
       
   723         Bytes(byte[] b) {
       
   724             this.b = b;
       
   725         }
       
   726         public int hashCode() {
       
   727             return Arrays.hashCode(b);
       
   728         }
       
   729         public boolean equals(Object o) {
       
   730             if (this == o) {
       
   731                 return true;
       
   732             }
       
   733             if (o instanceof Bytes == false) {
       
   734                 return false;
       
   735             }
       
   736             Bytes other = (Bytes)o;
       
   737             return Arrays.equals(this.b, other.b);
       
   738         }
       
   739     }
       
   740 
       
   741     private static Map<Bytes,TrustAttributes> getTrust(SunPKCS11 provider)
       
   742             throws PKCS11Exception {
       
   743         Map<Bytes,TrustAttributes> trustMap = new HashMap<Bytes,TrustAttributes>();
       
   744         Token token = provider.getToken();
       
   745         Session session = null;
       
   746         boolean exceptionOccurred = true;
       
   747         try {
       
   748             session = token.getOpSession();
       
   749             int MAX_NUM = 8192;
       
   750             CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
       
   751                 new CK_ATTRIBUTE(CKA_CLASS, CKO_NETSCAPE_TRUST),
       
   752             };
       
   753             token.p11.C_FindObjectsInit(session.id(), attrs);
       
   754             long[] handles = token.p11.C_FindObjects(session.id(), MAX_NUM);
       
   755             token.p11.C_FindObjectsFinal(session.id());
       
   756             if (DEBUG) System.out.println("handles: " + handles.length);
       
   757 
       
   758             for (long handle : handles) {
       
   759                 try {
       
   760                     TrustAttributes trust = new TrustAttributes(token, session, handle);
       
   761                     trustMap.put(trust.getHash(), trust);
       
   762                 } catch (PKCS11Exception e) {
       
   763                     // skip put on pkcs11 error
       
   764                 }
       
   765             }
       
   766             exceptionOccurred = false;
       
   767         } finally {
       
   768             if (exceptionOccurred) {
       
   769                 token.killSession(session);
       
   770             } else {
       
   771                 token.releaseSession(session);
       
   772             }
       
   773         }
       
   774         return trustMap;
       
   775     }
       
   776 
       
   777     private static native long nssGetLibraryHandle(String libraryName);
       
   778 
       
   779     private static native long nssLoadLibrary(String name) throws IOException;
       
   780 
       
   781     private static native boolean nssVersionCheck(long handle, String minVersion);
       
   782 
       
   783     private static native boolean nssInitialize(String functionName, long handle, String configDir, boolean nssOptimizeSpace);
       
   784 
       
   785     private static native Object nssGetModuleList(long handle, String libDir);
       
   786 
       
   787 }