1 /*
   2  * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.pkcs11;
  27 
  28 import java.io.*;
  29 import java.util.*;
  30 
  31 import java.security.*;
  32 import java.security.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", "/usr/sfw/lib/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                 InputStream in = new ByteArrayInputStream(config.getBytes("UTF8"));
 518                 return new SunPKCS11(in);
 519             } catch (Exception e) {
 520                 // XXX
 521                 throw new ProviderException(e);
 522             }
 523         }
 524 
 525         synchronized void setTrust(Token token, X509Certificate cert) {
 526             Bytes bytes = new Bytes(getDigest(cert, "SHA-1"));
 527             TrustAttributes attr = getTrust(bytes);
 528             if (attr == null) {
 529                 attr = new TrustAttributes(token, cert, bytes, CKT_NETSCAPE_TRUSTED_DELEGATOR);
 530                 trust.put(bytes, attr);
 531             } else {
 532                 // does it already have the correct trust settings?
 533                 if (attr.isTrusted(TrustType.ALL) == false) {
 534                     // XXX not yet implemented
 535                     throw new ProviderException("Cannot change existing trust attributes");
 536                 }
 537             }
 538         }
 539 
 540         TrustAttributes getTrust(Bytes hash) {
 541             if (trust == null) {
 542                 // If provider is not set, create a temporary provider to
 543                 // retrieve the trust information. This can happen if we need
 544                 // to get the trust information for the trustanchor module
 545                 // because we need to look for user customized settings in the
 546                 // keystore module (which may not have a provider created yet).
 547                 // Creating a temporary provider and then dropping it on the
 548                 // floor immediately is flawed, but it's the best we can do
 549                 // for now.
 550                 synchronized (this) {
 551                     SunPKCS11 p = provider;
 552                     if (p == null) {
 553                         p = newProvider();
 554                     }
 555                     try {
 556                         trust = Secmod.getTrust(p);
 557                     } catch (PKCS11Exception e) {
 558                         throw new RuntimeException(e);
 559                     }
 560                 }
 561             }
 562             return trust.get(hash);
 563         }
 564 
 565         public String toString() {
 566             return
 567             commonName + " (" + type + ", " + libraryName + ", slot " + slot + ")";
 568         }
 569 
 570     }
 571 
 572     /**
 573      * Constants representing NSS trust categories.
 574      */
 575     public static enum TrustType {
 576         /** Trusted for all purposes */
 577         ALL,
 578         /** Trusted for SSL client authentication */
 579         CLIENT_AUTH,
 580         /** Trusted for SSL server authentication */
 581         SERVER_AUTH,
 582         /** Trusted for code signing */
 583         CODE_SIGNING,
 584         /** Trusted for email protection */
 585         EMAIL_PROTECTION,
 586     }
 587 
 588     public static enum DbMode {
 589         READ_WRITE("NSS_InitReadWrite"),
 590         READ_ONLY ("NSS_Init"),
 591         NO_DB     ("NSS_NoDB_Init");
 592 
 593         final String functionName;
 594         DbMode(String functionName) {
 595             this.functionName = functionName;
 596         }
 597     }
 598 
 599     /**
 600      * A LoadStoreParameter for use with the NSS Softtoken or
 601      * NSS TrustAnchor KeyStores.
 602      * <p>
 603      * It allows the set of trusted certificates that are returned by
 604      * the KeyStore to be specified.
 605      */
 606     public static final class KeyStoreLoadParameter implements LoadStoreParameter {
 607         final TrustType trustType;
 608         final ProtectionParameter protection;
 609         public KeyStoreLoadParameter(TrustType trustType, char[] password) {
 610             this(trustType, new PasswordProtection(password));
 611 
 612         }
 613         public KeyStoreLoadParameter(TrustType trustType, ProtectionParameter prot) {
 614             if (trustType == null) {
 615                 throw new NullPointerException("trustType must not be null");
 616             }
 617             this.trustType = trustType;
 618             this.protection = prot;
 619         }
 620         public ProtectionParameter getProtectionParameter() {
 621             return protection;
 622         }
 623         public TrustType getTrustType() {
 624             return trustType;
 625         }
 626     }
 627 
 628     static class TrustAttributes {
 629         final long handle;
 630         final long clientAuth, serverAuth, codeSigning, emailProtection;
 631         final byte[] shaHash;
 632         TrustAttributes(Token token, X509Certificate cert, Bytes bytes, long trustValue) {
 633             Session session = null;
 634             try {
 635                 session = token.getOpSession();
 636                 // XXX use KeyStore TrustType settings to determine which
 637                 // attributes to set
 638                 CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
 639                     new CK_ATTRIBUTE(CKA_TOKEN, true),
 640                     new CK_ATTRIBUTE(CKA_CLASS, CKO_NETSCAPE_TRUST),
 641                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_SERVER_AUTH, trustValue),
 642                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CODE_SIGNING, trustValue),
 643                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_EMAIL_PROTECTION, trustValue),
 644                     new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CLIENT_AUTH, trustValue),
 645                     new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_SHA1_HASH, bytes.b),
 646                     new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_MD5_HASH, getDigest(cert, "MD5")),
 647                     new CK_ATTRIBUTE(CKA_ISSUER, cert.getIssuerX500Principal().getEncoded()),
 648                     new CK_ATTRIBUTE(CKA_SERIAL_NUMBER, cert.getSerialNumber().toByteArray()),
 649                     // XXX per PKCS#11 spec, the serial number should be in ASN.1
 650                 };
 651                 handle = token.p11.C_CreateObject(session.id(), attrs);
 652                 shaHash = bytes.b;
 653                 clientAuth = trustValue;
 654                 serverAuth = trustValue;
 655                 codeSigning = trustValue;
 656                 emailProtection = trustValue;
 657             } catch (PKCS11Exception e) {
 658                 throw new ProviderException("Could not create trust object", e);
 659             } finally {
 660                 token.releaseSession(session);
 661             }
 662         }
 663         TrustAttributes(Token token, Session session, long handle)
 664                         throws PKCS11Exception {
 665             this.handle = handle;
 666             CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
 667                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_SERVER_AUTH),
 668                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CODE_SIGNING),
 669                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_EMAIL_PROTECTION),
 670                 new CK_ATTRIBUTE(CKA_NETSCAPE_CERT_SHA1_HASH),
 671             };
 672 
 673             token.p11.C_GetAttributeValue(session.id(), handle, attrs);
 674             serverAuth = attrs[0].getLong();
 675             codeSigning = attrs[1].getLong();
 676             emailProtection = attrs[2].getLong();
 677             shaHash = attrs[3].getByteArray();
 678 
 679             attrs = new CK_ATTRIBUTE[] {
 680                 new CK_ATTRIBUTE(CKA_NETSCAPE_TRUST_CLIENT_AUTH),
 681             };
 682             long c;
 683             try {
 684                 token.p11.C_GetAttributeValue(session.id(), handle, attrs);
 685                 c = attrs[0].getLong();
 686             } catch (PKCS11Exception e) {
 687                 // trust anchor module does not support this attribute
 688                 c = serverAuth;
 689             }
 690             clientAuth = c;
 691         }
 692         Bytes getHash() {
 693             return new Bytes(shaHash);
 694         }
 695         boolean isTrusted(TrustType type) {
 696             switch (type) {
 697             case CLIENT_AUTH:
 698                 return isTrusted(clientAuth);
 699             case SERVER_AUTH:
 700                 return isTrusted(serverAuth);
 701             case CODE_SIGNING:
 702                 return isTrusted(codeSigning);
 703             case EMAIL_PROTECTION:
 704                 return isTrusted(emailProtection);
 705             case ALL:
 706                 return isTrusted(TrustType.CLIENT_AUTH)
 707                     && isTrusted(TrustType.SERVER_AUTH)
 708                     && isTrusted(TrustType.CODE_SIGNING)
 709                     && isTrusted(TrustType.EMAIL_PROTECTION);
 710             default:
 711                 return false;
 712             }
 713         }
 714 
 715         private boolean isTrusted(long l) {
 716             // XXX CKT_TRUSTED?
 717             return (l == CKT_NETSCAPE_TRUSTED_DELEGATOR);
 718         }
 719 
 720     }
 721 
 722     private static class Bytes {
 723         final byte[] b;
 724         Bytes(byte[] b) {
 725             this.b = b;
 726         }
 727         public int hashCode() {
 728             return Arrays.hashCode(b);
 729         }
 730         public boolean equals(Object o) {
 731             if (this == o) {
 732                 return true;
 733             }
 734             if (o instanceof Bytes == false) {
 735                 return false;
 736             }
 737             Bytes other = (Bytes)o;
 738             return Arrays.equals(this.b, other.b);
 739         }
 740     }
 741 
 742     private static Map<Bytes,TrustAttributes> getTrust(SunPKCS11 provider)
 743             throws PKCS11Exception {
 744         Map<Bytes,TrustAttributes> trustMap = new HashMap<Bytes,TrustAttributes>();
 745         Token token = provider.getToken();
 746         Session session = null;
 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         } finally {
 767             token.releaseSession(session);
 768         }
 769         return trustMap;
 770     }
 771 
 772     private static native long nssGetLibraryHandle(String libraryName);
 773 
 774     private static native long nssLoadLibrary(String name) throws IOException;
 775 
 776     private static native boolean nssVersionCheck(long handle, String minVersion);
 777 
 778     private static native boolean nssInitialize(String functionName, long handle, String configDir, boolean nssOptimizeSpace);
 779 
 780     private static native Object nssGetModuleList(long handle, String libDir);
 781 
 782 }