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