|
Java example source code file (SunPKCS11.java)
This example Java source code file (SunPKCS11.java) is included in the alvinalexander.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Learn more about this Java project at its project page.
The SunPKCS11.java Java example source code
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.pkcs11;
import java.io.*;
import java.util.*;
import java.security.*;
import java.security.interfaces.*;
import javax.crypto.interfaces.*;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.ConfirmationCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextOutputCallback;
import sun.security.util.Debug;
import sun.security.util.ResourcesMgr;
import sun.security.pkcs11.Secmod.*;
import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
/**
* PKCS#11 provider main class.
*
* @author Andreas Sterbenz
* @since 1.5
*/
public final class SunPKCS11 extends AuthProvider {
private static final long serialVersionUID = -1354835039035306505L;
static final Debug debug = Debug.getInstance("sunpkcs11");
private static int dummyConfigId;
// the PKCS11 object through which we make the native calls
final PKCS11 p11;
// name of the configuration file
private final String configName;
// configuration information
final Config config;
// id of the PKCS#11 slot we are using
final long slotID;
private CallbackHandler pHandler;
private final Object LOCK_HANDLER = new Object();
final boolean removable;
final Module nssModule;
final boolean nssUseSecmodTrust;
private volatile Token token;
private TokenPoller poller;
Token getToken() {
return token;
}
public SunPKCS11() {
super("SunPKCS11-Dummy", 1.8d, "SunPKCS11-Dummy");
throw new ProviderException
("SunPKCS11 requires configuration file argument");
}
public SunPKCS11(String configName) {
this(checkNull(configName), null);
}
public SunPKCS11(InputStream configStream) {
this(getDummyConfigName(), checkNull(configStream));
}
private static <T> T checkNull(T obj) {
if (obj == null) {
throw new NullPointerException();
}
return obj;
}
private static synchronized String getDummyConfigName() {
int id = ++dummyConfigId;
return "---DummyConfig-" + id + "---";
}
/**
* @deprecated use new SunPKCS11(String) or new SunPKCS11(InputStream)
* instead
*/
@Deprecated
public SunPKCS11(String configName, InputStream configStream) {
super("SunPKCS11-" +
Config.getConfig(configName, configStream).getName(),
1.8d, Config.getConfig(configName, configStream).getDescription());
this.configName = configName;
this.config = Config.removeConfig(configName);
if (debug != null) {
System.out.println("SunPKCS11 loading " + configName);
}
String library = config.getLibrary();
String functionList = config.getFunctionList();
long slotID = config.getSlotID();
int slotListIndex = config.getSlotListIndex();
boolean useSecmod = config.getNssUseSecmod();
boolean nssUseSecmodTrust = config.getNssUseSecmodTrust();
Module nssModule = null;
//
// Initialization via Secmod. The way this works is as follows:
// SunPKCS11 is either in normal mode or in NSS Secmod mode.
// Secmod is activated by specifying one or more of the following
// options in the config file:
// nssUseSecmod, nssSecmodDirectory, nssLibrary, nssModule
//
// XXX add more explanation here
//
// If we are in Secmod mode and configured to use either the
// nssKeyStore or the nssTrustAnchors module, we automatically
// switch to using the NSS trust attributes for trusted certs
// (KeyStore).
//
if (useSecmod) {
// note: Config ensures library/slot/slotListIndex not specified
// in secmod mode.
Secmod secmod = Secmod.getInstance();
DbMode nssDbMode = config.getNssDbMode();
try {
String nssLibraryDirectory = config.getNssLibraryDirectory();
String nssSecmodDirectory = config.getNssSecmodDirectory();
boolean nssOptimizeSpace = config.getNssOptimizeSpace();
if (secmod.isInitialized()) {
if (nssSecmodDirectory != null) {
String s = secmod.getConfigDir();
if ((s != null) &&
(s.equals(nssSecmodDirectory) == false)) {
throw new ProviderException("Secmod directory "
+ nssSecmodDirectory
+ " invalid, NSS already initialized with "
+ s);
}
}
if (nssLibraryDirectory != null) {
String s = secmod.getLibDir();
if ((s != null) &&
(s.equals(nssLibraryDirectory) == false)) {
throw new ProviderException("NSS library directory "
+ nssLibraryDirectory
+ " invalid, NSS already initialized with "
+ s);
}
}
} else {
if (nssDbMode != DbMode.NO_DB) {
if (nssSecmodDirectory == null) {
throw new ProviderException(
"Secmod not initialized and "
+ "nssSecmodDirectory not specified");
}
} else {
if (nssSecmodDirectory != null) {
throw new ProviderException(
"nssSecmodDirectory must not be "
+ "specified in noDb mode");
}
}
secmod.initialize(nssDbMode, nssSecmodDirectory,
nssLibraryDirectory, nssOptimizeSpace);
}
} catch (IOException e) {
// XXX which exception to throw
throw new ProviderException("Could not initialize NSS", e);
}
List<Module> modules = secmod.getModules();
if (config.getShowInfo()) {
System.out.println("NSS modules: " + modules);
}
String moduleName = config.getNssModule();
if (moduleName == null) {
nssModule = secmod.getModule(ModuleType.FIPS);
if (nssModule != null) {
moduleName = "fips";
} else {
moduleName = (nssDbMode == DbMode.NO_DB) ?
"crypto" : "keystore";
}
}
if (moduleName.equals("fips")) {
nssModule = secmod.getModule(ModuleType.FIPS);
nssUseSecmodTrust = true;
functionList = "FC_GetFunctionList";
} else if (moduleName.equals("keystore")) {
nssModule = secmod.getModule(ModuleType.KEYSTORE);
nssUseSecmodTrust = true;
} else if (moduleName.equals("crypto")) {
nssModule = secmod.getModule(ModuleType.CRYPTO);
} else if (moduleName.equals("trustanchors")) {
// XXX should the option be called trustanchor or trustanchors??
nssModule = secmod.getModule(ModuleType.TRUSTANCHOR);
nssUseSecmodTrust = true;
} else if (moduleName.startsWith("external-")) {
int moduleIndex;
try {
moduleIndex = Integer.parseInt
(moduleName.substring("external-".length()));
} catch (NumberFormatException e) {
moduleIndex = -1;
}
if (moduleIndex < 1) {
throw new ProviderException
("Invalid external module: " + moduleName);
}
int k = 0;
for (Module module : modules) {
if (module.getType() == ModuleType.EXTERNAL) {
if (++k == moduleIndex) {
nssModule = module;
break;
}
}
}
if (nssModule == null) {
throw new ProviderException("Invalid module " + moduleName
+ ": only " + k + " external NSS modules available");
}
} else {
throw new ProviderException(
"Unknown NSS module: " + moduleName);
}
if (nssModule == null) {
throw new ProviderException(
"NSS module not available: " + moduleName);
}
if (nssModule.hasInitializedProvider()) {
throw new ProviderException("Secmod module already configured");
}
library = nssModule.libraryName;
slotListIndex = nssModule.slot;
}
this.nssUseSecmodTrust = nssUseSecmodTrust;
this.nssModule = nssModule;
File libraryFile = new File(library);
// if the filename is a simple filename without path
// (e.g. "libpkcs11.so"), it may refer to a library somewhere on the
// OS library search path. Omit the test for file existance as that
// only looks in the current directory.
if (libraryFile.getName().equals(library) == false) {
if (new File(library).isFile() == false) {
String msg = "Library " + library + " does not exist";
if (config.getHandleStartupErrors() == Config.ERR_HALT) {
throw new ProviderException(msg);
} else {
throw new UnsupportedOperationException(msg);
}
}
}
try {
if (debug != null) {
debug.println("Initializing PKCS#11 library " + library);
}
CK_C_INITIALIZE_ARGS initArgs = new CK_C_INITIALIZE_ARGS();
String nssArgs = config.getNssArgs();
if (nssArgs != null) {
initArgs.pReserved = nssArgs;
}
// request multithreaded access first
initArgs.flags = CKF_OS_LOCKING_OK;
PKCS11 tmpPKCS11;
try {
tmpPKCS11 = PKCS11.getInstance(
library, functionList, initArgs,
config.getOmitInitialize());
} catch (PKCS11Exception e) {
if (debug != null) {
debug.println("Multi-threaded initialization failed: " + e);
}
if (config.getAllowSingleThreadedModules() == false) {
throw e;
}
// fall back to single threaded access
if (nssArgs == null) {
// if possible, use null initArgs for better compatibility
initArgs = null;
} else {
initArgs.flags = 0;
}
tmpPKCS11 = PKCS11.getInstance(library,
functionList, initArgs, config.getOmitInitialize());
}
p11 = tmpPKCS11;
CK_INFO p11Info = p11.C_GetInfo();
if (p11Info.cryptokiVersion.major < 2) {
throw new ProviderException("Only PKCS#11 v2.0 and later "
+ "supported, library version is v" + p11Info.cryptokiVersion);
}
boolean showInfo = config.getShowInfo();
if (showInfo) {
System.out.println("Information for provider " + getName());
System.out.println("Library info:");
System.out.println(p11Info);
}
if ((slotID < 0) || showInfo) {
long[] slots = p11.C_GetSlotList(false);
if (showInfo) {
System.out.println("All slots: " + toString(slots));
slots = p11.C_GetSlotList(true);
System.out.println("Slots with tokens: " + toString(slots));
}
if (slotID < 0) {
if ((slotListIndex < 0)
|| (slotListIndex >= slots.length)) {
throw new ProviderException("slotListIndex is "
+ slotListIndex
+ " but token only has " + slots.length + " slots");
}
slotID = slots[slotListIndex];
}
}
this.slotID = slotID;
CK_SLOT_INFO slotInfo = p11.C_GetSlotInfo(slotID);
removable = (slotInfo.flags & CKF_REMOVABLE_DEVICE) != 0;
initToken(slotInfo);
if (nssModule != null) {
nssModule.setProvider(this);
}
} catch (Exception e) {
if (config.getHandleStartupErrors() == Config.ERR_IGNORE_ALL) {
throw new UnsupportedOperationException
("Initialization failed", e);
} else {
throw new ProviderException
("Initialization failed", e);
}
}
}
private static String toString(long[] longs) {
if (longs.length == 0) {
return "(none)";
}
StringBuilder sb = new StringBuilder();
sb.append(longs[0]);
for (int i = 1; i < longs.length; i++) {
sb.append(", ");
sb.append(longs[i]);
}
return sb.toString();
}
public boolean equals(Object obj) {
return this == obj;
}
public int hashCode() {
return System.identityHashCode(this);
}
private static String[] s(String ...aliases) {
return aliases;
}
private static final class Descriptor {
final String type;
final String algorithm;
final String className;
final String[] aliases;
final int[] mechanisms;
private Descriptor(String type, String algorithm, String className,
String[] aliases, int[] mechanisms) {
this.type = type;
this.algorithm = algorithm;
this.className = className;
this.aliases = aliases;
this.mechanisms = mechanisms;
}
private P11Service service(Token token, int mechanism) {
return new P11Service
(token, type, algorithm, className, aliases, mechanism);
}
public String toString() {
return type + "." + algorithm;
}
}
// Map from mechanism to List of Descriptors that should be
// registered if the mechanism is supported
private final static Map<Integer,List descriptors =
new HashMap<Integer,List();
private static int[] m(long m1) {
return new int[] {(int)m1};
}
private static int[] m(long m1, long m2) {
return new int[] {(int)m1, (int)m2};
}
private static int[] m(long m1, long m2, long m3) {
return new int[] {(int)m1, (int)m2, (int)m3};
}
private static int[] m(long m1, long m2, long m3, long m4) {
return new int[] {(int)m1, (int)m2, (int)m3, (int)m4};
}
private static void d(String type, String algorithm, String className,
int[] m) {
register(new Descriptor(type, algorithm, className, null, m));
}
private static void d(String type, String algorithm, String className,
String[] aliases, int[] m) {
register(new Descriptor(type, algorithm, className, aliases, m));
}
private static void register(Descriptor d) {
for (int i = 0; i < d.mechanisms.length; i++) {
int m = d.mechanisms[i];
Integer key = Integer.valueOf(m);
List<Descriptor> list = descriptors.get(key);
if (list == null) {
list = new ArrayList<Descriptor>();
descriptors.put(key, list);
}
list.add(d);
}
}
private final static String MD = "MessageDigest";
private final static String SIG = "Signature";
private final static String KPG = "KeyPairGenerator";
private final static String KG = "KeyGenerator";
private final static String AGP = "AlgorithmParameters";
private final static String KF = "KeyFactory";
private final static String SKF = "SecretKeyFactory";
private final static String CIP = "Cipher";
private final static String MAC = "Mac";
private final static String KA = "KeyAgreement";
private final static String KS = "KeyStore";
private final static String SR = "SecureRandom";
static {
// names of all the implementation classes
// use local variables, only used here
String P11Digest = "sun.security.pkcs11.P11Digest";
String P11MAC = "sun.security.pkcs11.P11MAC";
String P11KeyPairGenerator = "sun.security.pkcs11.P11KeyPairGenerator";
String P11KeyGenerator = "sun.security.pkcs11.P11KeyGenerator";
String P11RSAKeyFactory = "sun.security.pkcs11.P11RSAKeyFactory";
String P11DSAKeyFactory = "sun.security.pkcs11.P11DSAKeyFactory";
String P11DHKeyFactory = "sun.security.pkcs11.P11DHKeyFactory";
String P11KeyAgreement = "sun.security.pkcs11.P11KeyAgreement";
String P11SecretKeyFactory = "sun.security.pkcs11.P11SecretKeyFactory";
String P11Cipher = "sun.security.pkcs11.P11Cipher";
String P11RSACipher = "sun.security.pkcs11.P11RSACipher";
String P11Signature = "sun.security.pkcs11.P11Signature";
// XXX register all aliases
d(MD, "MD2", P11Digest,
m(CKM_MD2));
d(MD, "MD5", P11Digest,
m(CKM_MD5));
d(MD, "SHA1", P11Digest,
s("SHA", "SHA-1", "1.3.14.3.2.26", "OID.1.3.14.3.2.26"),
m(CKM_SHA_1));
d(MD, "SHA-224", P11Digest,
s("2.16.840.1.101.3.4.2.4", "OID.2.16.840.1.101.3.4.2.4"),
m(CKM_SHA224));
d(MD, "SHA-256", P11Digest,
s("2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1"),
m(CKM_SHA256));
d(MD, "SHA-384", P11Digest,
s("2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2"),
m(CKM_SHA384));
d(MD, "SHA-512", P11Digest,
s("2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3"),
m(CKM_SHA512));
d(MAC, "HmacMD5", P11MAC,
m(CKM_MD5_HMAC));
d(MAC, "HmacSHA1", P11MAC,
s("1.2.840.113549.2.7", "OID.1.2.840.113549.2.7"),
m(CKM_SHA_1_HMAC));
d(MAC, "HmacSHA224", P11MAC,
s("1.2.840.113549.2.8", "OID.1.2.840.113549.2.8"),
m(CKM_SHA224_HMAC));
d(MAC, "HmacSHA256", P11MAC,
s("1.2.840.113549.2.9", "OID.1.2.840.113549.2.9"),
m(CKM_SHA256_HMAC));
d(MAC, "HmacSHA384", P11MAC,
s("1.2.840.113549.2.10", "OID.1.2.840.113549.2.10"),
m(CKM_SHA384_HMAC));
d(MAC, "HmacSHA512", P11MAC,
s("1.2.840.113549.2.11", "OID.1.2.840.113549.2.11"),
m(CKM_SHA512_HMAC));
d(MAC, "SslMacMD5", P11MAC,
m(CKM_SSL3_MD5_MAC));
d(MAC, "SslMacSHA1", P11MAC,
m(CKM_SSL3_SHA1_MAC));
d(KPG, "RSA", P11KeyPairGenerator,
m(CKM_RSA_PKCS_KEY_PAIR_GEN));
d(KPG, "DSA", P11KeyPairGenerator,
s("1.3.14.3.2.12", "1.2.840.10040.4.1", "OID.1.2.840.10040.4.1"),
m(CKM_DSA_KEY_PAIR_GEN));
d(KPG, "DH", P11KeyPairGenerator, s("DiffieHellman"),
m(CKM_DH_PKCS_KEY_PAIR_GEN));
d(KPG, "EC", P11KeyPairGenerator,
m(CKM_EC_KEY_PAIR_GEN));
d(KG, "ARCFOUR", P11KeyGenerator, s("RC4"),
m(CKM_RC4_KEY_GEN));
d(KG, "DES", P11KeyGenerator,
m(CKM_DES_KEY_GEN));
d(KG, "DESede", P11KeyGenerator,
m(CKM_DES3_KEY_GEN, CKM_DES2_KEY_GEN));
d(KG, "AES", P11KeyGenerator,
m(CKM_AES_KEY_GEN));
d(KG, "Blowfish", P11KeyGenerator,
m(CKM_BLOWFISH_KEY_GEN));
// register (Secret)KeyFactories if there are any mechanisms
// for a particular algorithm that we support
d(KF, "RSA", P11RSAKeyFactory,
m(CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS, CKM_RSA_X_509));
d(KF, "DSA", P11DSAKeyFactory,
s("1.3.14.3.2.12", "1.2.840.10040.4.1", "OID.1.2.840.10040.4.1"),
m(CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1));
d(KF, "DH", P11DHKeyFactory, s("DiffieHellman"),
m(CKM_DH_PKCS_KEY_PAIR_GEN, CKM_DH_PKCS_DERIVE));
d(KF, "EC", P11DHKeyFactory,
m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE,
CKM_ECDSA, CKM_ECDSA_SHA1));
// AlgorithmParameters for EC.
// Only needed until we have an EC implementation in the SUN provider.
d(AGP, "EC", "sun.security.ec.ECParameters",
s("1.2.840.10045.2.1"),
m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE,
CKM_ECDSA, CKM_ECDSA_SHA1));
d(KA, "DH", P11KeyAgreement, s("DiffieHellman"),
m(CKM_DH_PKCS_DERIVE));
d(KA, "ECDH", "sun.security.pkcs11.P11ECDHKeyAgreement",
m(CKM_ECDH1_DERIVE));
d(SKF, "ARCFOUR", P11SecretKeyFactory, s("RC4"),
m(CKM_RC4));
d(SKF, "DES", P11SecretKeyFactory,
m(CKM_DES_CBC));
d(SKF, "DESede", P11SecretKeyFactory,
m(CKM_DES3_CBC));
d(SKF, "AES", P11SecretKeyFactory,
s("2.16.840.1.101.3.4.1", "OID.2.16.840.1.101.3.4.1"),
m(CKM_AES_CBC));
d(SKF, "Blowfish", P11SecretKeyFactory,
m(CKM_BLOWFISH_CBC));
// XXX attributes for Ciphers (supported modes, padding)
d(CIP, "ARCFOUR", P11Cipher, s("RC4"),
m(CKM_RC4));
d(CIP, "DES/CBC/NoPadding", P11Cipher,
m(CKM_DES_CBC));
d(CIP, "DES/CBC/PKCS5Padding", P11Cipher,
m(CKM_DES_CBC_PAD, CKM_DES_CBC));
d(CIP, "DES/ECB/NoPadding", P11Cipher,
m(CKM_DES_ECB));
d(CIP, "DES/ECB/PKCS5Padding", P11Cipher, s("DES"),
m(CKM_DES_ECB));
d(CIP, "DESede/CBC/NoPadding", P11Cipher,
m(CKM_DES3_CBC));
d(CIP, "DESede/CBC/PKCS5Padding", P11Cipher,
m(CKM_DES3_CBC_PAD, CKM_DES3_CBC));
d(CIP, "DESede/ECB/NoPadding", P11Cipher,
m(CKM_DES3_ECB));
d(CIP, "DESede/ECB/PKCS5Padding", P11Cipher, s("DESede"),
m(CKM_DES3_ECB));
d(CIP, "AES/CBC/NoPadding", P11Cipher,
m(CKM_AES_CBC));
d(CIP, "AES_128/CBC/NoPadding", P11Cipher,
s("2.16.840.1.101.3.4.1.2", "OID.2.16.840.1.101.3.4.1.2"),
m(CKM_AES_CBC));
d(CIP, "AES_192/CBC/NoPadding", P11Cipher,
s("2.16.840.1.101.3.4.1.22", "OID.2.16.840.1.101.3.4.1.22"),
m(CKM_AES_CBC));
d(CIP, "AES_256/CBC/NoPadding", P11Cipher,
s("2.16.840.1.101.3.4.1.42", "OID.2.16.840.1.101.3.4.1.42"),
m(CKM_AES_CBC));
d(CIP, "AES/CBC/PKCS5Padding", P11Cipher,
m(CKM_AES_CBC_PAD, CKM_AES_CBC));
d(CIP, "AES/ECB/NoPadding", P11Cipher,
m(CKM_AES_ECB));
d(CIP, "AES_128/ECB/NoPadding", P11Cipher,
s("2.16.840.1.101.3.4.1.1", "OID.2.16.840.1.101.3.4.1.1"),
m(CKM_AES_ECB));
d(CIP, "AES_192/ECB/NoPadding", P11Cipher,
s("2.16.840.1.101.3.4.1.21", "OID.2.16.840.1.101.3.4.1.21"),
m(CKM_AES_ECB));
d(CIP, "AES_256/ECB/NoPadding", P11Cipher,
s("2.16.840.1.101.3.4.1.41", "OID.2.16.840.1.101.3.4.1.41"),
m(CKM_AES_ECB));
d(CIP, "AES/ECB/PKCS5Padding", P11Cipher, s("AES"),
m(CKM_AES_ECB));
d(CIP, "AES/CTR/NoPadding", P11Cipher,
m(CKM_AES_CTR));
d(CIP, "Blowfish/CBC/NoPadding", P11Cipher,
m(CKM_BLOWFISH_CBC));
d(CIP, "Blowfish/CBC/PKCS5Padding", P11Cipher,
m(CKM_BLOWFISH_CBC));
// XXX RSA_X_509, RSA_OAEP not yet supported
d(CIP, "RSA/ECB/PKCS1Padding", P11RSACipher, s("RSA"),
m(CKM_RSA_PKCS));
d(CIP, "RSA/ECB/NoPadding", P11RSACipher,
m(CKM_RSA_X_509));
d(SIG, "RawDSA", P11Signature, s("NONEwithDSA"),
m(CKM_DSA));
d(SIG, "DSA", P11Signature,
s("SHA1withDSA", "1.3.14.3.2.13", "1.3.14.3.2.27",
"1.2.840.10040.4.3", "OID.1.2.840.10040.4.3"),
m(CKM_DSA_SHA1, CKM_DSA));
d(SIG, "NONEwithECDSA", P11Signature,
m(CKM_ECDSA));
d(SIG, "SHA1withECDSA", P11Signature,
s("ECDSA", "1.2.840.10045.4.1", "OID.1.2.840.10045.4.1"),
m(CKM_ECDSA_SHA1, CKM_ECDSA));
d(SIG, "SHA224withECDSA", P11Signature,
s("1.2.840.10045.4.3.1", "OID.1.2.840.10045.4.3.1"),
m(CKM_ECDSA));
d(SIG, "SHA256withECDSA", P11Signature,
s("1.2.840.10045.4.3.2", "OID.1.2.840.10045.4.3.2"),
m(CKM_ECDSA));
d(SIG, "SHA384withECDSA", P11Signature,
s("1.2.840.10045.4.3.3", "OID.1.2.840.10045.4.3.3"),
m(CKM_ECDSA));
d(SIG, "SHA512withECDSA", P11Signature,
s("1.2.840.10045.4.3.4", "OID.1.2.840.10045.4.3.4"),
m(CKM_ECDSA));
d(SIG, "MD2withRSA", P11Signature,
s("1.2.840.113549.1.1.2", "OID.1.2.840.113549.1.1.2"),
m(CKM_MD2_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
d(SIG, "MD5withRSA", P11Signature,
s("1.2.840.113549.1.1.4", "OID.1.2.840.113549.1.1.4"),
m(CKM_MD5_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
d(SIG, "SHA1withRSA", P11Signature,
s("1.2.840.113549.1.1.5", "OID.1.2.840.113549.1.1.5",
"1.3.14.3.2.29"),
m(CKM_SHA1_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
d(SIG, "SHA224withRSA", P11Signature,
s("1.2.840.113549.1.1.14", "OID.1.2.840.113549.1.1.14"),
m(CKM_SHA224_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
d(SIG, "SHA256withRSA", P11Signature,
s("1.2.840.113549.1.1.11", "OID.1.2.840.113549.1.1.11"),
m(CKM_SHA256_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
d(SIG, "SHA384withRSA", P11Signature,
s("1.2.840.113549.1.1.12", "OID.1.2.840.113549.1.1.12"),
m(CKM_SHA384_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
d(SIG, "SHA512withRSA", P11Signature,
s("1.2.840.113549.1.1.13", "OID.1.2.840.113549.1.1.13"),
m(CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
/*
* TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the
* PRF calculations. As of 2010, there is no PKCS11-level
* support for TLS 1.2 PRF calculations, and no known OS's have
* an internal variant we could use. Therefore for TLS 1.2, we
* are updating JSSE to request different provider algorithms
* (e.g. "SunTls12Prf"), and currently only SunJCE has these
* TLS 1.2 algorithms.
*
* If we reused the names such as "SunTlsPrf", the PKCS11
* providers would need be updated to fail correctly when
* presented with the wrong version number (via
* Provider.Service.supportsParameters()), and we would also
* need to add the appropriate supportsParamters() checks into
* KeyGenerators (not currently there).
*
* In the future, if PKCS11 support is added, we will restructure
* this.
*/
d(KG, "SunTlsRsaPremasterSecret",
"sun.security.pkcs11.P11TlsRsaPremasterSecretGenerator",
m(CKM_SSL3_PRE_MASTER_KEY_GEN, CKM_TLS_PRE_MASTER_KEY_GEN));
d(KG, "SunTlsMasterSecret",
"sun.security.pkcs11.P11TlsMasterSecretGenerator",
m(CKM_SSL3_MASTER_KEY_DERIVE, CKM_TLS_MASTER_KEY_DERIVE,
CKM_SSL3_MASTER_KEY_DERIVE_DH,
CKM_TLS_MASTER_KEY_DERIVE_DH));
d(KG, "SunTlsKeyMaterial",
"sun.security.pkcs11.P11TlsKeyMaterialGenerator",
m(CKM_SSL3_KEY_AND_MAC_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE));
d(KG, "SunTlsPrf", "sun.security.pkcs11.P11TlsPrfGenerator",
m(CKM_TLS_PRF, CKM_NSS_TLS_PRF_GENERAL));
}
// background thread that periodically checks for token insertion
// if no token is present. We need to do that in a separate thread because
// the insertion check may block for quite a long time on some tokens.
private static class TokenPoller implements Runnable {
private final SunPKCS11 provider;
private volatile boolean enabled;
private TokenPoller(SunPKCS11 provider) {
this.provider = provider;
enabled = true;
}
public void run() {
int interval = provider.config.getInsertionCheckInterval();
while (enabled) {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
break;
}
if (enabled == false) {
break;
}
try {
provider.initToken(null);
} catch (PKCS11Exception e) {
// ignore
}
}
}
void disable() {
enabled = false;
}
}
// create the poller thread, if not already active
private void createPoller() {
if (poller != null) {
return;
}
TokenPoller poller = new TokenPoller(this);
Thread t = new Thread(poller, "Poller " + getName());
t.setDaemon(true);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
this.poller = poller;
}
// destroy the poller thread, if active
private void destroyPoller() {
if (poller != null) {
poller.disable();
poller = null;
}
}
private boolean hasValidToken() {
/* Commented out to work with Solaris softtoken impl which
returns 0-value flags, e.g. both REMOVABLE_DEVICE and
TOKEN_PRESENT are false, when it can't access the token.
if (removable == false) {
return true;
}
*/
Token token = this.token;
return (token != null) && token.isValid();
}
// destroy the token. Called if we detect that it has been removed
synchronized void uninitToken(Token token) {
if (this.token != token) {
// mismatch, our token must already be destroyed
return;
}
destroyPoller();
this.token = null;
// unregister all algorithms
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
clear();
return null;
}
});
createPoller();
}
// test if a token is present and initialize this provider for it if so.
// does nothing if no token is found
// called from constructor and by poller
private void initToken(CK_SLOT_INFO slotInfo) throws PKCS11Exception {
if (slotInfo == null) {
slotInfo = p11.C_GetSlotInfo(slotID);
}
if (removable && (slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
createPoller();
return;
}
destroyPoller();
boolean showInfo = config.getShowInfo();
if (showInfo) {
System.out.println("Slot info for slot " + slotID + ":");
System.out.println(slotInfo);
}
final Token token = new Token(this);
if (showInfo) {
System.out.println
("Token info for token in slot " + slotID + ":");
System.out.println(token.tokenInfo);
}
long[] supportedMechanisms = p11.C_GetMechanismList(slotID);
// Create a map from the various Descriptors to the "most
// preferred" mechanism that was defined during the
// static initialization. For example, DES/CBC/PKCS5Padding
// could be mapped to CKM_DES_CBC_PAD or CKM_DES_CBC. Prefer
// the earliest entry. When asked for "DES/CBC/PKCS5Padding", we
// return a CKM_DES_CBC_PAD.
final Map<Descriptor,Integer> supportedAlgs =
new HashMap<Descriptor,Integer>();
for (int i = 0; i < supportedMechanisms.length; i++) {
long longMech = supportedMechanisms[i];
boolean isEnabled = config.isEnabled(longMech);
if (showInfo) {
CK_MECHANISM_INFO mechInfo =
p11.C_GetMechanismInfo(slotID, longMech);
System.out.println("Mechanism " +
Functions.getMechanismName(longMech) + ":");
if (isEnabled == false) {
System.out.println("DISABLED in configuration");
}
System.out.println(mechInfo);
}
if (isEnabled == false) {
continue;
}
// we do not know of mechs with the upper 32 bits set
if (longMech >>> 32 != 0) {
continue;
}
int mech = (int)longMech;
Integer integerMech = Integer.valueOf(mech);
List<Descriptor> ds = descriptors.get(integerMech);
if (ds == null) {
continue;
}
for (Descriptor d : ds) {
Integer oldMech = supportedAlgs.get(d);
if (oldMech == null) {
supportedAlgs.put(d, integerMech);
continue;
}
// See if there is something "more preferred"
// than what we currently have in the supportedAlgs
// map.
int intOldMech = oldMech.intValue();
for (int j = 0; j < d.mechanisms.length; j++) {
int nextMech = d.mechanisms[j];
if (mech == nextMech) {
supportedAlgs.put(d, integerMech);
break;
} else if (intOldMech == nextMech) {
break;
}
}
}
}
// register algorithms in provider
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
for (Map.Entry<Descriptor,Integer> entry
: supportedAlgs.entrySet()) {
Descriptor d = entry.getKey();
int mechanism = entry.getValue().intValue();
Service s = d.service(token, mechanism);
putService(s);
}
if (((token.tokenInfo.flags & CKF_RNG) != 0)
&& config.isEnabled(PCKM_SECURERANDOM)
&& !token.sessionManager.lowMaxSessions()) {
// do not register SecureRandom if the token does
// not support many sessions. if we did, we might
// run out of sessions in the middle of a
// nextBytes() call where we cannot fail over.
putService(new P11Service(token, SR, "PKCS11",
"sun.security.pkcs11.P11SecureRandom", null,
PCKM_SECURERANDOM));
}
if (config.isEnabled(PCKM_KEYSTORE)) {
putService(new P11Service(token, KS, "PKCS11",
"sun.security.pkcs11.P11KeyStore",
s("PKCS11-" + config.getName()),
PCKM_KEYSTORE));
}
return null;
}
});
this.token = token;
}
private static final class P11Service extends Service {
private final Token token;
private final long mechanism;
P11Service(Token token, String type, String algorithm,
String className, String[] al, long mechanism) {
super(token.provider, type, algorithm, className, toList(al), null);
this.token = token;
this.mechanism = mechanism & 0xFFFFFFFFL;
}
private static List<String> toList(String[] aliases) {
return (aliases == null) ? null : Arrays.asList(aliases);
}
public Object newInstance(Object param)
throws NoSuchAlgorithmException {
if (token.isValid() == false) {
throw new NoSuchAlgorithmException("Token has been removed");
}
try {
return newInstance0(param);
} catch (PKCS11Exception e) {
throw new NoSuchAlgorithmException(e);
}
}
public Object newInstance0(Object param) throws
PKCS11Exception, NoSuchAlgorithmException {
String algorithm = getAlgorithm();
String type = getType();
if (type == MD) {
return new P11Digest(token, algorithm, mechanism);
} else if (type == CIP) {
if (algorithm.startsWith("RSA")) {
return new P11RSACipher(token, algorithm, mechanism);
} else {
return new P11Cipher(token, algorithm, mechanism);
}
} else if (type == SIG) {
return new P11Signature(token, algorithm, mechanism);
} else if (type == MAC) {
return new P11Mac(token, algorithm, mechanism);
} else if (type == KPG) {
return new P11KeyPairGenerator(token, algorithm, mechanism);
} else if (type == KA) {
if (algorithm.equals("ECDH")) {
return new P11ECDHKeyAgreement(token, algorithm, mechanism);
} else {
return new P11KeyAgreement(token, algorithm, mechanism);
}
} else if (type == KF) {
return token.getKeyFactory(algorithm);
} else if (type == SKF) {
return new P11SecretKeyFactory(token, algorithm);
} else if (type == KG) {
// reference equality
if (algorithm == "SunTlsRsaPremasterSecret") {
return new P11TlsRsaPremasterSecretGenerator(
token, algorithm, mechanism);
} else if (algorithm == "SunTlsMasterSecret") {
return new P11TlsMasterSecretGenerator(
token, algorithm, mechanism);
} else if (algorithm == "SunTlsKeyMaterial") {
return new P11TlsKeyMaterialGenerator(
token, algorithm, mechanism);
} else if (algorithm == "SunTlsPrf") {
return new P11TlsPrfGenerator(token, algorithm, mechanism);
} else {
return new P11KeyGenerator(token, algorithm, mechanism);
}
} else if (type == SR) {
return token.getRandom();
} else if (type == KS) {
return token.getKeyStore();
} else if (type == AGP) {
return new sun.security.ec.ECParameters();
} else {
throw new NoSuchAlgorithmException("Unknown type: " + type);
}
}
public boolean supportsParameter(Object param) {
if ((param == null) || (token.isValid() == false)) {
return false;
}
if (param instanceof Key == false) {
throw new InvalidParameterException("Parameter must be a Key");
}
String algorithm = getAlgorithm();
String type = getType();
Key key = (Key)param;
String keyAlgorithm = key.getAlgorithm();
// RSA signatures and cipher
if (((type == CIP) && algorithm.startsWith("RSA"))
|| (type == SIG) && algorithm.endsWith("RSA")) {
if (keyAlgorithm.equals("RSA") == false) {
return false;
}
return isLocalKey(key)
|| (key instanceof RSAPrivateKey)
|| (key instanceof RSAPublicKey);
}
// EC
if (((type == KA) && algorithm.equals("ECDH"))
|| ((type == SIG) && algorithm.endsWith("ECDSA"))) {
if (keyAlgorithm.equals("EC") == false) {
return false;
}
return isLocalKey(key)
|| (key instanceof ECPrivateKey)
|| (key instanceof ECPublicKey);
}
// DSA signatures
if ((type == SIG) && algorithm.endsWith("DSA")) {
if (keyAlgorithm.equals("DSA") == false) {
return false;
}
return isLocalKey(key)
|| (key instanceof DSAPrivateKey)
|| (key instanceof DSAPublicKey);
}
// MACs and symmetric ciphers
if ((type == CIP) || (type == MAC)) {
// do not check algorithm name, mismatch is unlikely anyway
return isLocalKey(key) || "RAW".equals(key.getFormat());
}
// DH key agreement
if (type == KA) {
if (keyAlgorithm.equals("DH") == false) {
return false;
}
return isLocalKey(key)
|| (key instanceof DHPrivateKey)
|| (key instanceof DHPublicKey);
}
// should not reach here,
// unknown engine type or algorithm
throw new AssertionError
("SunPKCS11 error: " + type + ", " + algorithm);
}
private boolean isLocalKey(Key key) {
return (key instanceof P11Key) && (((P11Key)key).token == token);
}
public String toString() {
return super.toString() +
" (" + Functions.getMechanismName(mechanism) + ")";
}
}
/**
* Log in to this provider.
*
* <p> If the token expects a PIN to be supplied by the caller,
* the <code>handler implementation must support
* a <code>PasswordCallback.
*
* <p> To determine if the token supports a protected authentication path,
* the CK_TOKEN_INFO flag, CKF_PROTECTED_AUTHENTICATION_PATH, is consulted.
*
* @param subject this parameter is ignored
* @param handler the <code>CallbackHandler used by
* this provider to communicate with the caller
*
* @exception LoginException if the login operation fails
* @exception SecurityException if the does not pass a security check for
* <code>SecurityPermission("authProvider.name"),
* where <i>name is the value returned by
* this provider's <code>getName method
*/
public void login(Subject subject, CallbackHandler handler)
throws LoginException {
// security check
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (debug != null) {
debug.println("checking login permission");
}
sm.checkPermission(new SecurityPermission
("authProvider." + this.getName()));
}
if (hasValidToken() == false) {
throw new LoginException("No token present");
}
// see if a login is required
if ((token.tokenInfo.flags & CKF_LOGIN_REQUIRED) == 0) {
if (debug != null) {
debug.println("login operation not required for token - " +
"ignoring login request");
}
return;
}
// see if user already logged in
try {
if (token.isLoggedInNow(null)) {
// user already logged in
if (debug != null) {
debug.println("user already logged in");
}
return;
}
} catch (PKCS11Exception e) {
// ignore - fall thru and attempt login
}
// get the pin if necessary
char[] pin = null;
if ((token.tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) {
// get password
CallbackHandler myHandler = getCallbackHandler(handler);
if (myHandler == null) {
// XXX PolicyTool is dependent on this message text
throw new LoginException
("no password provided, and no callback handler " +
"available for retrieving password");
}
java.text.MessageFormat form = new java.text.MessageFormat
(ResourcesMgr.getString
("PKCS11.Token.providerName.Password."));
Object[] source = { getName() };
PasswordCallback pcall = new PasswordCallback(form.format(source),
false);
Callback[] callbacks = { pcall };
try {
myHandler.handle(callbacks);
} catch (Exception e) {
LoginException le = new LoginException
("Unable to perform password callback");
le.initCause(e);
throw le;
}
pin = pcall.getPassword();
pcall.clearPassword();
if (pin == null) {
if (debug != null) {
debug.println("caller passed NULL pin");
}
}
}
// perform token login
Session session = null;
try {
session = token.getOpSession();
// pin is NULL if using CKF_PROTECTED_AUTHENTICATION_PATH
p11.C_Login(session.id(), CKU_USER, pin);
if (debug != null) {
debug.println("login succeeded");
}
} catch (PKCS11Exception pe) {
if (pe.getErrorCode() == CKR_USER_ALREADY_LOGGED_IN) {
// let this one go
if (debug != null) {
debug.println("user already logged in");
}
return;
} else if (pe.getErrorCode() == CKR_PIN_INCORRECT) {
FailedLoginException fle = new FailedLoginException();
fle.initCause(pe);
throw fle;
} else {
LoginException le = new LoginException();
le.initCause(pe);
throw le;
}
} finally {
token.releaseSession(session);
if (pin != null) {
Arrays.fill(pin, ' ');
}
}
// we do not store the PIN in the subject for now
}
/**
* Log out from this provider
*
* @exception LoginException if the logout operation fails
* @exception SecurityException if the does not pass a security check for
* <code>SecurityPermission("authProvider.name"),
* where <i>name is the value returned by
* this provider's <code>getName method
*/
public void logout() throws LoginException {
// security check
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission
(new SecurityPermission("authProvider." + this.getName()));
}
if (hasValidToken() == false) {
// app may call logout for cleanup, allow
return;
}
if ((token.tokenInfo.flags & CKF_LOGIN_REQUIRED) == 0) {
if (debug != null) {
debug.println("logout operation not required for token - " +
"ignoring logout request");
}
return;
}
try {
if (token.isLoggedInNow(null) == false) {
if (debug != null) {
debug.println("user not logged in");
}
return;
}
} catch (PKCS11Exception e) {
// ignore
}
// perform token logout
Session session = null;
try {
session = token.getOpSession();
p11.C_Logout(session.id());
if (debug != null) {
debug.println("logout succeeded");
}
} catch (PKCS11Exception pe) {
if (pe.getErrorCode() == CKR_USER_NOT_LOGGED_IN) {
// let this one go
if (debug != null) {
debug.println("user not logged in");
}
return;
}
LoginException le = new LoginException();
le.initCause(pe);
throw le;
} finally {
token.releaseSession(session);
}
}
/**
* Set a <code>CallbackHandler
*
* <p> The provider uses this handler if one is not passed to the
* <code>login method. The provider also uses this handler
* if it invokes <code>login on behalf of callers.
* In either case if a handler is not set via this method,
* the provider queries the
* <i>auth.login.defaultCallbackHandler security property
* for the fully qualified class name of a default handler implementation.
* If the security property is not set,
* the provider is assumed to have alternative means
* for obtaining authentication information.
*
* @param handler a <code>CallbackHandler for obtaining
* authentication information, which may be <code>null
*
* @exception SecurityException if the caller does not pass a
* security check for
* <code>SecurityPermission("authProvider.name"),
* where <i>name is the value returned by
* this provider's <code>getName method
*/
public void setCallbackHandler(CallbackHandler handler) {
// security check
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission
(new SecurityPermission("authProvider." + this.getName()));
}
synchronized (LOCK_HANDLER) {
pHandler = handler;
}
}
private CallbackHandler getCallbackHandler(CallbackHandler handler) {
// get default handler if necessary
if (handler != null) {
return handler;
}
if (debug != null) {
debug.println("getting provider callback handler");
}
synchronized (LOCK_HANDLER) {
// see if handler was set via setCallbackHandler
if (pHandler != null) {
return pHandler;
}
try {
if (debug != null) {
debug.println("getting default callback handler");
}
CallbackHandler myHandler = AccessController.doPrivileged
(new PrivilegedExceptionAction<CallbackHandler>() {
public CallbackHandler run() throws Exception {
String defaultHandler =
java.security.Security.getProperty
("auth.login.defaultCallbackHandler");
if (defaultHandler == null ||
defaultHandler.length() == 0) {
// ok
if (debug != null) {
debug.println("no default handler set");
}
return null;
}
Class<?> c = Class.forName
(defaultHandler,
true,
Thread.currentThread().getContextClassLoader());
return (CallbackHandler)c.newInstance();
}
});
// save it
pHandler = myHandler;
return myHandler;
} catch (PrivilegedActionException pae) {
// ok
if (debug != null) {
debug.println("Unable to load default callback handler");
pae.printStackTrace();
}
}
}
return null;
}
private Object writeReplace() throws ObjectStreamException {
return new SunPKCS11Rep(this);
}
/**
* Serialized representation of the SunPKCS11 provider.
*/
private static class SunPKCS11Rep implements Serializable {
static final long serialVersionUID = -2896606995897745419L;
private final String providerName;
private final String configName;
SunPKCS11Rep(SunPKCS11 provider) throws NotSerializableException {
providerName = provider.getName();
configName = provider.configName;
if (Security.getProvider(providerName) != provider) {
throw new NotSerializableException("Only SunPKCS11 providers "
+ "installed in java.security.Security can be serialized");
}
}
private Object readResolve() throws ObjectStreamException {
SunPKCS11 p = (SunPKCS11)Security.getProvider(providerName);
if ((p == null) || (p.configName.equals(configName) == false)) {
throw new NotSerializableException("Could not find "
+ providerName + " in installed providers");
}
return p;
}
}
}
Other Java examples (source code examples)
Here is a short list of links related to this Java SunPKCS11.java source code file:
|