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 } |
|