/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/**
* PKCS#11 provider main class.
*
* @author Andreas Sterbenz
* @since 1.5
*/
private static int dummyConfigId;
// the PKCS11 object through which we make the native calls
// name of the configuration file
// configuration information
// id of the PKCS#11 slot we are using
final long slotID;
final boolean removable;
final boolean nssUseSecmodTrust;
return token;
}
public SunPKCS11() {
super("SunPKCS11-Dummy", 1.7d, "SunPKCS11-Dummy");
throw new ProviderException
("SunPKCS11 requires configuration file argument");
}
}
}
throw new NullPointerException();
}
return obj;
}
int id = ++dummyConfigId;
}
/**
* @deprecated use new SunPKCS11(String) or new SunPKCS11(InputStream)
* instead
*/
super("SunPKCS11-" +
this.configName = configName;
}
//
// 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.
try {
if (secmod.isInitialized()) {
if (nssSecmodDirectory != null) {
if ((s != null) &&
(s.equals(nssSecmodDirectory) == false)) {
throw new ProviderException("Secmod directory "
+ " invalid, NSS already initialized with "
+ s);
}
}
if (nssLibraryDirectory != null) {
if ((s != null) &&
(s.equals(nssLibraryDirectory) == false)) {
throw new ProviderException("NSS library directory "
+ " invalid, NSS already initialized with "
+ s);
}
}
} else {
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");
}
}
}
} catch (IOException e) {
// XXX which exception to throw
throw new ProviderException("Could not initialize NSS", e);
}
if (config.getShowInfo()) {
}
if (moduleName == null) {
moduleName = "fips";
} else {
"crypto" : "keystore";
}
}
nssUseSecmodTrust = true;
functionList = "FC_GetFunctionList";
nssUseSecmodTrust = true;
// XXX should the option be called trustanchor or trustanchors??
nssUseSecmodTrust = true;
int moduleIndex;
try {
} catch (NumberFormatException e) {
moduleIndex = -1;
}
if (moduleIndex < 1) {
throw new ProviderException
("Invalid external module: " + moduleName);
}
int k = 0;
if (++k == moduleIndex) {
break;
}
}
}
+ ": only " + k + " external NSS modules available");
}
} else {
throw new ProviderException(
"Unknown NSS module: " + moduleName);
}
throw new ProviderException(
"NSS module not available: " + moduleName);
}
if (nssModule.hasInitializedProvider()) {
throw new ProviderException("Secmod module already configured");
}
}
this.nssUseSecmodTrust = nssUseSecmodTrust;
// 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.
throw new ProviderException(msg);
} else {
throw new UnsupportedOperationException(msg);
}
}
}
try {
}
}
// request multithreaded access first
try {
} catch (PKCS11Exception e) {
}
if (config.getAllowSingleThreadedModules() == false) {
throw e;
}
// fall back to single threaded access
// if possible, use null initArgs for better compatibility
} else {
}
}
throw new ProviderException("Only PKCS#11 v2.0 and later "
}
if (showInfo) {
}
if (showInfo) {
}
if (slotID < 0) {
if ((slotListIndex < 0)
throw new ProviderException("slotListIndex is "
}
}
}
nssModule.setProvider(this);
}
} catch (Exception e) {
throw new UnsupportedOperationException
("Initialization failed", e);
} else {
throw new ProviderException
("Initialization failed", e);
}
}
}
return "(none)";
}
}
}
return this == obj;
}
public int hashCode() {
return System.identityHashCode(this);
}
}
}
private static final class Descriptor {
final int[] mechanisms;
this.mechanisms = mechanisms;
}
return new P11Service
}
}
}
// Map from mechanism to List of Descriptors that should be
// registered if the mechanism is supported
private static int[] m(long m1) {
return new int[] {(int)m1};
}
}
}
}
int[] m) {
}
}
int m = d.mechanisms[i];
}
}
}
static {
// names of all the implementation classes
// use local variables, only used here
// XXX register all aliases
m(CKM_MD2));
m(CKM_MD5));
m(CKM_SHA_1));
m(CKM_SHA256));
m(CKM_SHA384));
m(CKM_SHA512));
m(CKM_MD5_HMAC));
m(CKM_SHA_1_HMAC));
m(CKM_SHA256_HMAC));
m(CKM_SHA384_HMAC));
m(CKM_SHA512_HMAC));
m(CKM_SSL3_MD5_MAC));
m(CKM_SSL3_SHA1_MAC));
m(CKM_DSA_KEY_PAIR_GEN));
m(CKM_EC_KEY_PAIR_GEN));
m(CKM_RC4_KEY_GEN));
m(CKM_DES_KEY_GEN));
m(CKM_AES_KEY_GEN));
m(CKM_BLOWFISH_KEY_GEN));
// register (Secret)KeyFactories if there are any mechanisms
// for a particular algorithm that we support
// AlgorithmParameters for EC.
// Only needed until we have an EC implementation in the SUN provider.
s("1.2.840.10045.2.1"),
m(CKM_DH_PKCS_DERIVE));
m(CKM_ECDH1_DERIVE));
m(CKM_RC4));
m(CKM_DES_CBC));
m(CKM_DES3_CBC));
m(CKM_AES_CBC));
m(CKM_BLOWFISH_CBC));
// XXX attributes for Ciphers (supported modes, padding)
m(CKM_RC4));
m(CKM_DES_CBC));
m(CKM_DES_CBC_PAD, CKM_DES_CBC));
m(CKM_DES_ECB));
m(CKM_DES_ECB));
m(CKM_DES3_CBC));
m(CKM_DES3_CBC_PAD, CKM_DES3_CBC));
m(CKM_DES3_ECB));
m(CKM_DES3_ECB));
m(CKM_AES_CBC));
m(CKM_AES_CBC_PAD, CKM_AES_CBC));
m(CKM_AES_ECB));
m(CKM_AES_ECB));
m(CKM_AES_CTR));
m(CKM_BLOWFISH_CBC));
m(CKM_BLOWFISH_CBC));
// XXX RSA_X_509, RSA_OAEP not yet supported
m(CKM_RSA_PKCS));
m(CKM_RSA_X_509));
m(CKM_DSA));
m(CKM_DSA_SHA1, CKM_DSA));
m(CKM_ECDSA));
m(CKM_ECDSA_SHA1, CKM_ECDSA));
m(CKM_ECDSA));
m(CKM_ECDSA));
m(CKM_ECDSA));
/*
* 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",
d(KG, "SunTlsMasterSecret",
"sun.security.pkcs11.P11TlsMasterSecretGenerator",
d(KG, "SunTlsKeyMaterial",
"sun.security.pkcs11.P11TlsKeyMaterialGenerator",
}
// 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 volatile boolean enabled;
enabled = true;
}
public void run() {
while (enabled) {
try {
} catch (InterruptedException e) {
break;
}
if (enabled == false) {
break;
}
try {
} catch (PKCS11Exception e) {
// ignore
}
}
}
void disable() {
enabled = false;
}
}
// create the poller thread, if not already active
private void createPoller() {
return;
}
t.setDaemon(true);
t.start();
}
// destroy the poller thread, if active
private void destroyPoller() {
}
}
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;
}
*/
}
// destroy the token. Called if we detect that it has been removed
// mismatch, our token must already be destroyed
return;
}
// unregister all algorithms
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
}
createPoller();
return;
}
if (showInfo) {
}
if (showInfo) {
}
// 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.
long longMech = supportedMechanisms[i];
if (showInfo) {
if (isEnabled == false) {
}
}
if (isEnabled == false) {
continue;
}
// we do not know of mechs with the upper 32 bits set
continue;
}
continue;
}
for (Descriptor d : ds) {
continue;
}
// See if there is something "more preferred"
// than what we currently have in the supportedAlgs
// map.
int nextMech = d.mechanisms[j];
break;
} else if (intOldMech == nextMech) {
break;
}
}
}
}
// register algorithms in provider
: supportedAlgs.entrySet()) {
putService(s);
}
// 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.
"sun.security.pkcs11.P11SecureRandom", null,
}
"sun.security.pkcs11.P11KeyStore",
}
return null;
}
});
}
private final long mechanism;
}
}
throws NoSuchAlgorithmException {
throw new NoSuchAlgorithmException("Token has been removed");
}
try {
return newInstance0(param);
} catch (PKCS11Exception e) {
throw new NoSuchAlgorithmException(e);
}
}
} else {
}
} else {
}
// reference equality
if (algorithm == "SunTlsRsaPremasterSecret") {
return new P11TlsRsaPremasterSecretGenerator(
} else if (algorithm == "SunTlsMasterSecret") {
return new P11TlsMasterSecretGenerator(
} else if (algorithm == "SunTlsKeyMaterial") {
return new P11TlsKeyMaterialGenerator(
} else if (algorithm == "SunTlsPrf") {
} else {
}
return token.getKeyStore();
} else {
}
}
return false;
}
throw new InvalidParameterException("Parameter must be a Key");
}
// RSA signatures and cipher
return false;
}
return isLocalKey(key)
|| (key instanceof RSAPrivateKey)
|| (key instanceof RSAPublicKey);
}
// EC
return false;
}
return isLocalKey(key)
|| (key instanceof ECPrivateKey)
|| (key instanceof ECPublicKey);
}
// DSA signatures
return false;
}
return isLocalKey(key)
|| (key instanceof DSAPrivateKey)
|| (key instanceof DSAPublicKey);
}
// MACs and symmetric ciphers
// do not check algorithm name, mismatch is unlikely anyway
}
// DH key agreement
return false;
}
return isLocalKey(key)
|| (key instanceof DHPrivateKey)
|| (key instanceof DHPublicKey);
}
// should not reach here,
// unknown engine type or algorithm
throw new AssertionError
}
}
return super.toString() +
}
}
/**
* Log in to this provider.
*
* <p> If the token expects a PIN to be supplied by the caller,
* the <code>handler</code> implementation must support
* a <code>PasswordCallback</code>.
*
* <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</code> 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.<i>name</i>")</code>,
* where <i>name</i> is the value returned by
* this provider's <code>getName</code> method
*/
throws LoginException {
// security check
}
("authProvider." + this.getName()));
}
if (hasValidToken() == false) {
throw new LoginException("No token present");
}
// see if a login is required
"ignoring login request");
}
return;
}
// see if user already logged in
try {
// user already logged in
}
return;
}
} catch (PKCS11Exception e) {
// ignore - fall thru and attempt login
}
// get the pin if necessary
// get password
// XXX PolicyTool is dependent on this message text
throw new LoginException
("no password provided, and no callback handler " +
"available for retrieving password");
}
("PKCS11.Token.providerName.Password."));
false);
try {
} catch (Exception e) {
("Unable to perform password callback");
throw le;
}
}
}
}
// perform token login
try {
// pin is NULL if using CKF_PROTECTED_AUTHENTICATION_PATH
}
} catch (PKCS11Exception pe) {
// let this one go
}
return;
throw fle;
} else {
throw le;
}
} finally {
}
}
// 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.<i>name</i>")</code>,
* where <i>name</i> is the value returned by
* this provider's <code>getName</code> method
*/
// security check
}
if (hasValidToken() == false) {
// app may call logout for cleanup, allow
return;
}
"ignoring logout request");
}
return;
}
try {
}
return;
}
} catch (PKCS11Exception e) {
// ignore
}
// perform token logout
try {
}
} catch (PKCS11Exception pe) {
// let this one go
}
return;
}
throw le;
} finally {
}
}
/**
* Set a <code>CallbackHandler</code>
*
* <p> The provider uses this handler if one is not passed to the
* <code>login</code> method. The provider also uses this handler
* if it invokes <code>login</code> on behalf of callers.
* In either case if a handler is not set via this method,
* the provider queries the
* <i>auth.login.defaultCallbackHandler</i> 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</code> for obtaining
* authentication information, which may be <code>null</code>
*
* @exception SecurityException if the caller does not pass a
* security check for
* <code>SecurityPermission("authProvider.<i>name</i>")</code>,
* where <i>name</i> is the value returned by
* this provider's <code>getName</code> method
*/
// security check
}
synchronized (LOCK_HANDLER) {
}
}
// get default handler if necessary
return handler;
}
}
synchronized (LOCK_HANDLER) {
// see if handler was set via setCallbackHandler
return pHandler;
}
try {
}
(new PrivilegedExceptionAction<CallbackHandler>() {
("auth.login.defaultCallbackHandler");
if (defaultHandler == null ||
// ok
}
return null;
}
true,
return (CallbackHandler)c.newInstance();
}
});
// save it
return myHandler;
} catch (PrivilegedActionException pae) {
// ok
}
}
}
return null;
}
return new SunPKCS11Rep(this);
}
/**
* Serialized representation of the SunPKCS11 provider.
*/
throw new NotSerializableException("Only SunPKCS11 providers "
+ "installed in java.security.Security can be serialized");
}
}
throw new NotSerializableException("Could not find "
+ providerName + " in installed providers");
}
return p;
}
}
}