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