1.0 Introduction
4.0 Tools
Appendix A Sun PKCS#11 Provider's Supported Algorithms
Appendix B Sun PKCS#11 Provider's KeyStore Restrictions
Appendix C Example Provider
The Java platform defines a set of programming interfaces for performing cryptographic operations. These interfaces are collectively known as the Java Cryptography Architecture (JCA) and the Java Cryptography Extension (JCE). Specifications are available at the Java SE Security Documentation page.
The cryptographic interfaces are provider-based. Specifically, applications talk to Application Programming Interfaces (APIs), and the actual cryptographic operations are performed in configured providers which adhere to a set of Service Provider Interfaces (SPIs). This architecture supports different provider implementations. Some providers may perform cryptographic operations in software; others may perform the operations on a hardware token (for example, on a smartcard device or on a hardware cryptographic accelerator).
The Cryptographic Token Interface Standard, PKCS#11, is produced by RSA Security and defines native programming interfaces to cryptographic tokens, such as hardware cryptographic accelerators and Smartcards. To facilitate the integration of native PKCS#11 tokens into the Java platform, a new cryptographic provider, the Sun PKCS#11 provider, has been introduced into the J2SE 5.0 release. This new provider enables existing applications written to the JCA and JCE APIs to access native PKCS#11 tokens. No modifications to the application are required. The only requirement is the proper configuration of the provider into the Java Runtime.
Although an application can make use of most PKCS#11 features using existing APIs, some applications might need more flexibility and capabilities. For example, an application might want to deal with Smartcards being removed and inserted dynamically more easily. Or, a PKCS#11 token might require authentication for some non-key-related operations and therefore, the application must be able to log into the token without using keystore. In J2SE 5.0, the JCA was enhanced to allow applications greater flexibility in dealing with different providers.
This document describes how native PKCS#11 tokens can be configured into the Java platform for use by Java applications. It also describes the enhancements that were made to the JCA to make it easier for applications to deal with different types of providers, including PKCS#11 providers.
The Sun PKCS#11 provider, in contrast to most other providers, does not implement cryptographic algorithms itself. Instead, it acts as a bridge between the Java JCA and JCE APIs and the native PKCS#11 cryptographic API, translating the calls and conventions between the two. This means that Java applications calling standard JCA and JCE APIs can, without modification, take advantage of algorithms offered by the underlying PKCS#11 implementations, such as, for example,
The Sun PKCS#11 provider is supported on Solaris (SPARC and x86), Linux (x86), and Windows platforms in both 32-bit and 64-bit Java processes.
The Sun PKCS#11 provider requires an implementation of PKCS#11 v2.0 or later to be installed on the system. This implementation must take the form of a shared-object library (.so on Solaris and Linux) or dynamic-link library (.dll on Windows). Please consult your vendor documentation to find out if your cryptographic device includes such a PKCS#11 implementation, how to configure it, and what the name of the library file is.
The Sun PKCS#11 provider supports a number of algorithms, provided that the underlying PKCS#11 implementation offers them. The algorithms and their corresponding PKCS#11 mechanisms are listed in the table in Appendix A.
sun.security.pkcs11.SunPKCS11
and accepts the full
pathname of a configuration file as an argument. To use the
provider, you must first install it by using the Java Cryptography
Architecture (JCA). As with all JCA providers, installation of
the provider can be done either statically or programmatically. To
install the provider statically, add the provider to the Java
Security properties file
($JAVA_HOME/lib/security/java.security). For example,
here's a fragment of the java.security file that installs
the Sun PKCS#11 provider with the configuration file
/opt/bar/cfg/pkcs11.cfg.
# configuration for security providers 1-6 omitted security.provider.7=sun.security.pkcs11.SunPKCS11 /opt/bar/cfg/pkcs11.cfgTo install the provider dynamically, create an instance of the provider with the appropriate configuration filename and then install it. Here is an example.
String configName = "/opt/bar/cfg/pkcs11.cfg"; Provider p = new sun.security.pkcs11.SunPKCS11(configName); Security.addProvider(p);
To use more than one slot per PKCS#11 implementation, or to use more than one PKCS#11 implementation, simply repeat the installation for each with the appropriate configuration file. This will result in a Sun PKCS#11 provider instance for each slot of each PKCS#11 implementation.
The configuration file is a text file that contains entries in the following format.
attribute = value The valid values for attribute and value are described in the table in this section. The two mandatory attributes are name and library. Here is a sample configuration file.name = FooAccelerator library = /opt/foo/lib/libpkcs11.soComments are denoted by lines starting with the # (number) symbol.
Attribute | Value | Description |
---|---|---|
library | pathname of PKCS#11 implementation | This is the full pathname (including extension) of the PKCS#11
implementation; the format of the pathname is platform dependent.
For example, /opt/foo/lib/libpkcs11.so might be the
pathname of a PKCS#11 implementation on Solaris and Linux while
C:\foo\mypkcs11.dll might be the pathname on
Windows. |
name | name suffix of this provider instance | This string is concatenated with the prefix SunPKCS11-
to produce this provider instance's name (that is, the string
returned by its Provider.getName() method). For
example, if the name attribute is
"FooAccelerator", then the provider instance's name will
be "SunPKCS11-FooAccelerator" . |
description | description of this provider instance | This string will be returned by the provider instance's
Provider.getInfo() method. If none is specified, a
default description will be returned. |
slot | slot id | This is the id of the slot that this provider instance is to be
associated with. For example, you would use 1 for the
slot with the id 1 under PKCS#11. At most one of
slot or slotListIndex may be specified. If
neither is specified, the default is a slotListIndex of
0. |
slotListIndex | slot index | This is the slot index that this provider instance is to be
associated with. It is the index into the list of all slots
returned by the PKCS#11 function C_GetSlotList . For
example, 0 indicates the first slot in the list. At
most one of slot or slotListIndex may be
specified. If neither is specified, the default is a
slotListIndex of 0. |
enabledMechanisms | brace enclosed, whitespace-separated list of PKCS#11 mechanisms to enable | This is the list PKCS#11 mechanisms that this provider instance
should use, provided that they are supported by both the Sun
PKCS#11 provider and PKCS#11 token. All other mechanisms will be
ignored. Each entry in the list is the name of a PKCS#11 mechanism.
Here is an example that lists two PKCS#11 mechanisms.
enabledMechanisms = { CKM_RSA_PKCS CKM_RSA_PKCS_KEY_PAIR_GEN }At most one of enabledMechanisms or disabledMechanisms may be specified. If neither is specified, the mechanisms enabled are those that are supported by both the Sun PKCS#11 provider and the PKCS#11 token. |
disabledMechanisms | brace enclosed, whitespace-separated list of PKCS#11 mechanisms to disable | This is the list of PKCS#11 mechanism that this provider
instance should ignore. Any mechanism listed will be ignored by the
provider, even if they are supported by the token and the Sun
PKCS#11 provider. The strings SecureRandom and
KeyStore may be specified to disable those services.
At most one of enabledMechanisms or disabledMechanisms may be specified. If neither is specified, the mechanisms enabled are those that are supported by both the Sun PKCS#11 provider and the PKCS#11 token. |
attributes | see below | The attributes option can be used to specify additional PKCS#11 that should be set when creating PKCS#11 key objects. This makes it possible to accommodate tokens that require particular attributes. For details, see the section below. |
The attributes option can be used if you do not like the default values your PKCS#11 implementation assigns or if your PKCS#11 implementation does not support defaults and requires a value to be specified explicitly. Note that specifying attributes that your PKCS#11 implementation does not support or that are invalid for the type of key in question may cause the operation to fail at runtime.
The option can be specified zero or more times, the options are processed in the order specified in the configuration file as described below. The attributes option has the format:
attributes(operation, keytype, keyalgorithm) = { name1 = value1 [...] }Valid values for operation are:
Valid values for keyalgorithm are one of the CKK_xxx constants from the PKCS#11 specification, or * to match keys of any algorithm. The algorithms currently supported by the SunPKCS11 provider are CKK_RSA, CKK_DSA, CKK_DH, CKK_AES, CKK_DES, CKK_DES3, CKK_RC4, CKK_BLOWFISH, and CKK_GENERIC.
The attribute names and values are specified as a list of one or more name-value pairs. name must be a CKA_xxx constant from the PKCS#11 specification, for example CKA_SENSITIVE. value can be one of the following:
attributes(*,CKO_PRIVATE_KEY,*) = { CKA_SIGN = true } attributes(*,CKO_PRIVATE_KEY,CKK_DH) = { CKA_SIGN = null } attributes(*,CKO_PRIVATE_KEY,CKK_RSA) = { CKA_DECRYPT = true }The first entry says to specify CKA_SIGN = true for all private keys. The second option overrides that with null for Diffie-Hellman private keys, so the CKA_SIGN attribute will not specified for them at all. Finally, the third option says to also specify CKA_DECRYPT = true for RSA private keys. That means RSA private keys will have both CKA_SIGN = true and CKA_DECRYPT = true set.
There is also a special form of the attributes option. You can write attributes = compatibility in the configuration file. That is a shortcut for a whole set of attribute statements. They are designed to provider maximum compatibility with existing Java applications, which may expect, for example, all key components to be accessible and secret keys to be usable for both encryption and decryption. The compatibility attributes line can be used together with other attributes lines, in which case the same aggregation and overriding rules apply as described earlier.
Network Security Services (NSS) is a set of open source security libraries used by the Mozilla/Firefox browsers, Sun's Java Enterprise System server software, and a number of other products. Its crypto APIs are based on PKCS#11 but it includes special features that are outside of the PKCS#11 standard. The Sun PKCS#11 provider includes code to interact with these NSS specific features, including several NSS specific configuration directives, which are described below.
For best results, we recommend that you use the latest version of NSS available. It should be at least version 3.12.
The Sun PKCS#11 provider uses NSS specific code when any of the
nss
configuration directives described below are used.
In that case, the regular configuration commands
library
, slot
, and
slotListIndex
cannot be used.
Attribute | Value | Description |
---|---|---|
nssLibraryDirectory | directory containing the NSS and NSPR libraries | This is the full pathname of the directory containing the NSS
and NSPR
libraries. It must be specified unless NSS has already been loaded
and initialized by another component running in the same process as
the Java VM.
Depending on your platform, you may have to set
|
nssSecmodDirectory | directory containing the NSS DB files | The full pathname of the directory containing the NSS
configuration and key information (secmod.db ,
key3.db , and cert8.db ). This directive
must be specified unless NSS has already been initialized by
another component (see above) or NSS is used without database files
as described below. |
nssDbMode | one of readWrite , readOnly , and
noDb |
This directives determines how the NSS database is accessed. In
read-write mode, full access is possible but only one process at a
time should be accessing the databases. Read-only mode disallows
modifications to the files.
The noDb mode allows NSS to be used without database files purely as a cryptographic provider. It is not possible to create persistent keys using the PKCS11 KeyStore. |
nssModule | one of keystore , crypto ,
fips , and trustanchors |
NSS makes its functionality available using several different
libraries and slots. This directive determines which of these
modules is accessed by this instance of SunPKCS11.
The The The The |
name = NSScrypto nssLibraryDirectory = /opt/tests/nss/lib nssDbMode = noDb attributes = compatibility
name = NSSfips nssLibraryDirectory = /opt/tests/nss/lib nssSecmodDirectory = /opt/tests/nss/fipsdb nssModule = fips
Sometimes, there could be issues with PKCS#11 which requires
debugging. To show debug info about Library, Slots, Token and
Mechanism, add showInfo=true
in
$JAVA-HOME/jre/lib/security/sunpkcs11-solaris.cfg
file.
For additional debugging info, users can start or restart the Java processes with one of the following options:
-Djava.security.debug=sunpkcs11
-Djava.security.debug=pkcs11keystore
As part of the troubleshooting process, it could be helpful to temporarily disable a PKCS#11 provider or the specific mechanisms of a given provider. Please note that this is only a temporary measure. By disabling the PKCS#11 provider, the provider is no longer available which can cause applications to break or have a performance impact. Once the issue has been identified, only that specific mechanism should remain disabled.
A PKCS#11 provider can be disabled using one of the following methods:
-Dsun.security.pkcs11.enable-solaris=false
sun.security.pkcs11.SunPKCS11,
/lib/security/sunpkcs11-solaris.cfg, /usr/lib/libpkcs11.so
).
$JAVA_HOME/jre/lib/security/java.security
file and
commenting out the PKCS#11 security provider (do not forget to
re-number the order of providers) as shown below.# List of providers and their preference orders (see above): security.provider.1=com.oracle.security.ucrypto.UcryptoProvider ${java.home}/lib/security/ucrypto-solaris.cfg #security.provider.2=sun.security.pkcs11.SunPKCS11 ${java.home}/lib/security/sunpkcs11-solaris.cfg security.provider.2=sun.security.provider.Sun security.provider.3=sun.security.rsa.SunRsaSign security.provider.4=sun.security.ec.SunEC security.provider.5=com.sun.net.ssl.internal.ssl.Provider security.provider.6=com.sun.crypto.provider.SunJCE .................... ....................
Start or restart the Java processes being run on this installation of Java.
When an issue occurs in one of the mechanisms of PKCS11, it can
be resolved by disabling only that particular mechanism, rather
than the entire PKCS11 provider (do not forget to re-enable the
PKCS11 provider if it was disabled earlier). For example, to
disable the SecureRandom
mechanism only, you can add
SecureRandom
to the list of disabled mechanisms in the
$JAVA_HOME/jre/lib/security/sunpkcs11-solaris.cfg
file. Here is an excerpt from such a file:
$ more sunpkcs11-solaris.cfg ....... ........ ........ disabledMechanisms = { SecureRandom CKM_MD2 CKM_MD5 CKM_SHA_1 ......... ......... }
Note: The portion of the
sunpkcs11-solaris.cfg
file shown above is an example
to show where to add the mechanisms that are to be disabled but is
not the complete file.
Java applications can use the existing JCA and JCE APIs to access PKCS#11 tokens via the Sun PKCS#11 provider. This is sufficient for many applications but it might be difficult for an application to deal with certain PKCS#11 features, such as unextractable keys and dynamically changing Smartcards. Consequently, a number of enhancements were made to the APIs to better support applications using certain PKCS#11 features. These enhancements are discussed in this section.
Certain PKCS#11 operations, such as accessing private keys, require a login using a Personal Identification Number, or PIN, before the operations can proceed. The most common type of operations that require login are those that deal with keys on the token. In a Java application, such operations often involve first loading the keystore. When accessing the PKCS#11 token as a keystore via the java.security.KeyStore class, you can supply the PIN in the password input parameter to the load method, similar to how applications initialize a keystore prior to J2SE 5.0. The PIN will then be used by the Sun PKCS#11 provider for logging into the token. Here is an example.
char[] pin = ...; KeyStore ks = KeyStore.getInstance("PKCS11"); ks.load(null, pin);
This is fine for an application that treats PKCS#11 tokens as static keystores. For an application that wants to accommodate PKCS#11 tokens more dynamically, such as Smartcards being inserted and removed, you can use the new KeyStore.Builder class. Here is an example of how to initialize the builder for a PKCS#11 keystore with a callback handler.
KeyStore.CallbackHandlerProtection chp = new KeyStore.CallbackHandlerProtection(new MyGuiCallbackHandler()); KeyStore.Builder builder = KeyStore.Builder.newInstance("PKCS11", null, chp);
For the Sun PKCS#11 provider, the callback handler must be able to satisfy a PasswordCallback, which is used to prompt the user for the PIN. Whenever the application needs access to the keystore, it uses the builder as follows.
KeyStore ks = builder.getKeyStore(); Key key = ks.getKey(alias, null);
The builder will prompt for a password as needed using the previously configured callback handler. The builder will prompt for a password only for the initial access. If the user of the application continues using the same Smartcard, the user will not be prompted again. If the user removes and inserts a different SmartCard, the builder will prompt for a password for the new card.
Depending on the PKCS#11 token, there may be non-key-related operations that also require token login. Applications that use such operations can use the newly introduced java.security.AuthProvider class. The AuthProvider class extends from java.security.Provider and defines methods to perform login and logout operations on a provider, as well as to set a callback handler for the provider to use.
For the Sun PKCS#11 provider, the callback handler must be able to satisfy a PasswordCallback, which is used to prompt the user for the PIN.
Here is an example of how an application might use an AuthProvider to log into the token.
AuthProvider aprov = (AuthProvider)Security.getProvider("SunPKCS11"); aprov.login(subject, new MyGuiCallbackHandler());
Java Key
objects may or may not contain actual key
material.
Applications and providers must use the correct interfaces to represent these different types of Key objects. Software Key objects (or any Key object that has access to the actual key material) should implement the interfaces in the java.security.interfaces and javax.crypto.interfaces packages (such as DSAPrivateKey). Key objects representing unextractable token keys should only implement the relevant generic interfaces in the java.security and javax.crypto packages (PrivateKey, PublicKey, or SecretKey). Identification of the algorithm of a key should be performed using the Key.getAlgorithm() method.
Applications should note that a Key object for an unextractable token key can only be used by the provider associated with that token.
Prior to J2SE 5.0, the Java cryptography getInstance() methods, such as Cipher.getInstance("AES"), returned the implementation from the first provider that implemented the requested algorithm. This is problematic if an application attempts to use a Key object for an unextractable token key with a provider that only accepts software key objects. In such a case, the provider would throw an InvalidKeyException. This is an issue for the Cipher, KeyAgreement, Mac, and Signature classes.
J2SE 5.0, addresses this issue by delaying the selection of the provider until the relevant initialization method is called. The initialization method accepts a Key object and can determine at that point which provider can accept the specified Key object. This ensures that the selected provider can use the specified Key object. The following represents the affected initialization methods.
Although this delayed provider selection is hidden from the
application, it does affect the behavior of the
getProvider()
method for Cipher,
KeyAgreement, Mac, and Signature. If
getProvider()
is called before the
initialization operation has occurred (and therefore before
provider selection has occurred), then the first provider that
supports the requested algorithm is returned. This may not be the
same provider as the one selected after the initialization
method is called. If getProvider()
is called
after the initialization operation has occurred, then the
actual selected provider is returned. It is recommended that
applications only call getProvider()
after they have
called the relevant initialization method.
In addition to getProvider()
, the following
additional methods are similarly affected.
Use the following options to configure the KeyStoreLoginModule to use a PKCS#11 token as the keystore.
other { com.sun.security.auth.module.KeyStoreLoginModule required keyStoreURL="NONE" keyStoreType="PKCS11" keyStorePasswordURL="file:/home/joe/scpin"; };
If more than one Sun PKCS#11 provider has been configured dynamically or in the java.security security properties file, you can use the keyStoreProvider option to target a specific provider instance. The argument to this option is the name of the provider. For the Sun PKCS#11 provider, the provider name is of the form SunPKCS11-TokenName, where TokenName is the name suffix that the provider instance has been configured with, as detailed in the configuration attributes table. For example, the following configuration file names the PKCS#11 provider instance with name suffix SmartCard.
other { com.sun.security.auth.module.KeyStoreLoginModule required keyStoreURL="NONE" keyStoreType="PKCS11" keyStorePasswordURL="file:/home/joe/scpin" keyStoreProvider="SunPKCS11-SmartCard"; };
Some PKCS#11 tokens support login via a protected authentication path. For example, a Smartcard may have a dedicated PIN-pad to enter the pin. Biometric devices will also have their own means to obtain authentication information. If the PKCS#11 token has a protected authentication path, then use the protected=true option and omit the keyStorePasswordURL option. Here is an example of a configuration file for such a token.
other { com.sun.security.auth.module.KeyStoreLoginModule required keyStoreURL="NONE" keyStoreType="PKCS11" protected=true; };
JSSE also supports configuring the use of keystores and trust stores via system properties, as described in the JSSE Reference Guide. To use a PKCS#11 token as a keystore or trust store, set the javax.net.ssl.keyStoreType and javax.net.ssl.trustStoreType system properties, respectively, to "PKCS11", and set the javax.net.ssl.keyStore and javax.net.ssl.trustStore system properties, respectively, to NONE. To specify the use of a specific provider instance, use the javax.net.ssl.keyStoreProvider and javax.net.ssl.trustStoreProvider system properties (e.g., "SunPKCS11-SmartCard").
In J2SE 5.0, the security tools were updated to support operations using the new Sun PKCS#11 provider. The changes are discussed below.
If the Sun PKCS#11 provider has been configured in the java.security security properties file (located in the $JAVA_HOME/lib/security directory of the Java runtime), then keytool and jarsigner can be used to operate on the PKCS#11 token by specifying the following options.
keytool -keystore NONE -storetype PKCS11 -listThe PIN can be specified using the -storepass option. If none has been specified, then keytool and jarsigner will prompt for the token PIN. If the token has a protected authentication path (such as a dedicated PIN-pad or a biometric reader), then the -protected option must be specified, and no password options can be specified.
If more than one Sun PKCS#11 provider has been configured in the java.security security properties file, you can use the -providerName option to target a specific provider instance. The argument to this option is the name of the provider.
keytool -keystore NONE -storetype PKCS11 \ -providerName SunPKCS11-SmartCard \ -list
If the Sun PKCS#11 provider has not been configured in the java.security security properties file, you can use the following options to instruct keytool and jarsigner to install the provider dynamically.
keytool -keystore NONE -storetype PKCS11 \ -providerClass sun.security.pkcs11.SunPKCS11 \ -providerArg /foo/bar/token.config \ -list
Prior to J2SE 5.0, the keystore entry in the default policy implementation had the following syntax.
keystore "some_keystore_url", "keystore_type";This syntax was inadequate for accessing a PKCS#11 keystore because such access usually required a PIN, and there might be multiple PKCS#11 provider instances. To accommodate these requirements, the keystore entry syntax has been updated in J2SE 5.0, to the following.
keystore "some_keystore_url", "keystore_type", "keystore_provider"; keystorePasswordURL "some_password_url";Where keystore_provider is the keystore provider name (for example, "SunPKCS11-SmartCard"), and some_password_url is a URL pointing to the location of the token PIN. Both keystore_provider and the keystorePasswordURL line are optional. If keystore_provider has not been specified, then the first configured provider that supports the specified keystore type is used. If the keystorePasswordURL line has not been specified, then no password is used.
The following is an example keystore policy entry for a PKCS#11 token.
keystore "NONE", "PKCS11", "SunPKCS11-SmartCard"; keystorePasswordURL "file:/foo/bar/passwordFile";
J2SE 5.0 introduces new facilities in the java.security.Provider class for provider implementations to more easily support PKCS#11 tokens and cryptographic services in general. These new facilities are discussed below.
See Appendix C for an example of a simple provider designed to demonstrate the new facilities.
As described in the above provider documentation, prior to J2SE 5.0, providers were required to create java.util.Property entries describing the services they supported. For each service implemented by the provider, there must be a property whose name is the type of service (Cipher, Signature, etc), followed by a period and the name of the algorithm to which the service applies. The property value must specify the fully qualified name of the class implementing the service. Here is an example of a provider setting KeyAgreement.DiffieHellman property to have the value com.sun.crypto.provider.DHKeyAgreement.
put("KeyAgreement.DiffieHellman", "com.sun.crypto.provider.DHKeyAgreement")
J2SE 5.0 introduces a new public static nested class, Provider.Service, to help better encapsulate the properties of a provider service (including its type, attributes, algorithm name, and algorithm aliases). Providers can instantiate Provider.Service objects and register them by calling the Provider.putService() method. This is equivalent to creating a Property entry and calling the Provider.put() method (as was done prior to J2SE 5.0). Note that legacy Property entries registered via Provider.put are still supported.
Here is an example of a provider creating a Service object with the KeyAgreement type, for the DiffieHellman algorithm, implemented by the class com.sun.crypto.provider.DHKeyAgreement.
Service s = new Service(this, "KeyAgreement", "DiffieHellman", "com.sun.crypto.provider.DHKeyAgreement", null, null); putService(s);
Using Provider.Service objects instead of legacy Property entries has a couple of major benefits. One benefit is that it allows the provider to have greater flexibility when instantiating engine classes. Another benefit is that it allows the provider to test parameter validity. These features are discussed in detail next.
Prior to J2SE 5.0, the Java Cryptography framework looked up the provider property for a particular service and directly instantiated the engine class registered for that property. J2SE 5.0, has the same behavior by default, but allows the provider to override this behavior and instantiate the engine class for the requested service itself.
To override the default behavior, the provider overrides the Provider.Service.newInstance() method to add its customer behavior. For example, the provider might call a custom constructor, or might perform initialization using information not accessible outside the provider (or that are only known by the provider).
The Java Cryptography framework may attempt a fast check to determine whether a provider's service implementation can use an application-specified parameter. To perform this fast check, the framework calls Provider.Service.supportsParameter().
In J2SE 5.0, the framework relies on this fast test during
delayed provider selection. When an
application invokes an initialization method
and passes it a Key object, the framework asks an
underlying provider whether it supports the object by calling its
Service.supportsParameter() method. If
supportsParameter()
returns false
, the
framework can immediately remove that provider from consideration.
If supportsParameter()
returns true
, the
framework passes the Key object to that provider's
initialization engine class implementation. A provider that
requires software Key objects should override this method
to return false
when it is passed non-software keys.
Likewise, a provider for a PKCS#11 token that contains
unextractable keys should only return true
for
Key objects that it created, and which therefore
correspond to the Keys on its respective token.
Note that the default implementation of
supportsParameter()
returns true
. This
allows existing providers to work without modification. However,
because of this lenient default implementation, the framework must
be prepared to catch exceptions thrown by providers that reject the
Key object inside their initialization engine class
implementations. The framework treats these cases the same as when
supportsParameter()
returns false
.
disabledMechanisms
and enabledMechanisms
configuration directives.
For Elliptic Curve mechanisms, SunPKCS11 will only use keys that
use the namedCurve
choice as encoding for the
parameters and only allow the uncompressed point format. The Sun
PKCS#11 provider assumes that a token supports all standard named
domain parameters.
Java Algorithm | PKCS#11 Mechanisms |
---|---|
Signature.MD2withRSA | CKM_MD2_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Signature.MD5withRSA | CKM_MD5_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Signature.SHA1withRSA | CKM_SHA1_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Signature.SHA224withRSA | CKM_SHA224_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Signature.SHA256withRSA | CKM_SHA256_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Signature.SHA384withRSA | CKM_SHA384_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Signature.SHA512withRSA | CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Signature.SHA1withDSA | CKM_DSA_SHA1, CKM_DSA |
Signature.NONEwithDSA | CKM_DSA |
Signature.SHA1withECDSA | CKM_ECDSA_SHA1, CKM_ECDSA |
Signature.SHA224withECDSA | CKM_ECDSA |
Signature.SHA256withECDSA | CKM_ECDSA |
Signature.SHA384withECDSA | CKM_ECDSA |
Signature.SHA512withECDSA | CKM_ECDSA |
Signature.NONEwithECDSA | CKM_ECDSA |
Cipher.RSA/ECB/PKCS1Padding | CKM_RSA_PKCS |
Cipher.ARCFOUR | CKM_RC4 |
Cipher.DES/CBC/NoPadding | CKM_DES_CBC |
Cipher.DESede/CBC/NoPadding | CKM_DES3_CBC |
Cipher.AES/CBC/NoPadding | CKM_AES_CBC |
Cipher.Blowfish/CBC/NoPadding | CKM_BLOWFISH_CBC |
Cipher.RSA/ECB/NoPadding | CKM_RSA_X_509 |
Cipher.AES/CTR/NoPadding | CKM_AES_CTR |
KeyAgreement.ECDH | CKM_ECDH1_DERIVE |
KeyAgreement.DiffieHellman | CKM_DH_PKCS_DERIVE |
KeyPairGenerator.RSA | CKM_RSA_PKCS_KEY_PAIR_GEN |
KeyPairGenerator.DSA | CKM_DSA_KEY_PAIR_GEN |
KeyPairGenerator.EC | CKM_EC_KEY_PAIR_GEN |
KeyPairGenerator.DiffieHellman | CKM_DH_PKCS_KEY_PAIR_GEN |
KeyGenerator.ARCFOUR | CKM_RC4_KEY_GEN |
KeyGenerator.DES | CKM_DES_KEY_GEN |
KeyGenerator.DESede | CKM_DES3_KEY_GEN |
KeyGenerator.AES | CKM_AES_KEY_GEN |
KeyGenerator.Blowfish | CKM_BLOWFISH_KEY_GEN |
Mac.HmacMD5 | CKM_MD5_HMAC |
Mac.HmacSHA1 | CKM_SHA_1_HMAC |
Mac.HmacSHA224 | CKM_SHA224_HMAC |
Mac.HmacSHA256 | CKM_SHA256_HMAC |
Mac.HmacSHA384 | CKM_SHA384_HMAC |
Mac.HmacSHA512 | CKM_SHA512_HMAC |
MessageDigest.MD2 | CKM_MD2 |
MessageDigest.MD5 | CKM_MD5 |
MessageDigest.SHA1 | CKM_SHA_1 |
MessageDigest.SHA-224 | CKM_SHA224 |
MessageDigest.SHA-256 | CKM_SHA256 |
MessageDigest.SHA-384 | CKM_SHA384 |
MessageDigest.SHA-512 | CKM_SHA512 |
KeyFactory.RSA | Any supported RSA mechanism |
KeyFactory.DSA | Any supported DSA mechanism |
KeyFactory.EC | Any supported EC mechanism |
KeyFactory.DiffieHellman | Any supported Diffie-Hellman mechanism |
SecretKeyFactory.ARCFOUR | CKM_RC4 |
SecretKeyFactory.DES | CKM_DES_CBC |
SecretKeyFactory.DESede | CKM_DES3_CBC |
SecretKeyFactory.AES | CKM_AES_CBC |
SecretKeyFactory.Blowfish | CKM_BLOWFISH_CBC |
SecureRandom.PKCS11 | CK_TOKEN_INFO has the CKF_RNG bit set |
KeyStore.PKCS11 | Always available |
The following describes the requirements placed by the Sun PKCS#11 Provider's KeyStore implementation on the underlying native PKCS#11 library. Note that changes may be made in future releases to maximize interoperability with as many existing PKCS#11 libraries as possible.
To map existing objects stored on a PKCS#11 token to KeyStore entries, the Sun PKCS#11 Provider's KeyStore implementation performs the following operations.
For each matching pair, the certificate chain is built by following the issuer->subject path. From the end entity certificate, a call to C_FindObjects[Init|Final] is made with a search template that includes the following attributes:
This search is continued until either no certificate for the issuer is found, or until a self-signed certificate is found. If more than one certificate is found the first one is used.
Once a private key and certificate have been matched (and its certificate chain built), the information is stored in a private key entry with the CKA_LABEL value from end entity certificate as the KeyStore alias.
If the end entity certificate has no CKA_LABEL, then the alias is derived from the CKA_ID. If the CKA_ID can be determined to consist exclusively of printable characters, then a String alias is created by decoding the CKA_ID bytes using the UTF-8 charset. Otherwise, a hex String alias is created from the CKA_ID bytes ("0xFFFF...", for example).
If multiple certificates share the same CKA_LABEL, then the alias is derived from the CKA_LABEL plus the end entity certificate issuer and serial number ("MyCert/CN=foobar/1234", for example).
If the CKA_TRUSTED attribute is not supported then no trusted certificate entries are created.
A KeyStore secret key entry is created for each secret key object, with the CKA_LABEL value as the KeyStore alias. Each secret key object must have a unique CKA_LABEL.
To create new KeyStore entries on a PKCS#11 token to KeyStore entries, the Sun PKCS#11 Provider's KeyStore implementation performs the following operations.
Private key objects are stored with CKA_PRIVATE=true. The KeyStore alias (UTF8-encoded) is set as the CKA_ID for both the private key and the corresponding end entity certificate. The KeyStore alias is also set as the CKA_LABEL for the end entity certificate object.
Each certificate in a private key entry's chain is also stored. The CKA_LABEL is not set for CA certificates. If a CA certificate is already in the token, a duplicate is not stored.
Secret key objects are stored with CKA_PRIVATE=true. The KeyStore alias is set as the CKA_LABEL.
In addition to the searches listed above, the following searches may be used by the Sun PKCS#11 provider's KeyStore implementation to perform internal functions. Specifically, C_FindObjects[Init|Final] may be called with any of the following attribute templates:
CKA_TOKEN true CKA_CLASS CKO_CERTIFICATE CKA_SUBJECT [subject DN]
CKA_TOKEN true CKA_CLASS CKO_SECRET_KEY CKA_LABEL [label]
CKA_TOKEN true CKA_CLASS CKO_CERTIFICATE or CKO_PRIVATE_KEY CKA_ID [cka_id]
package com.foo; import java.io.*; import java.lang.reflect.*; import java.security.*; import javax.crypto.*; /** * Example provider that demonstrates some of the new API features. * * . implement multiple different algorithms in a single class. * Previously each algorithm needed to be implemented in a separate class * (e.g. one for SHA-256, one for SHA-384, etc.) * * . multiple concurrent instances of the provider frontend class each * associated with a different backend. * * . it uses "unextractable" keys and lets the framework know which key * objects it can and cannot support * * Note that this is only a simple example provider designed to demonstrate * several of the new features. It is not explicitly designed for efficiency. */ public final class ExampleProvider extends Provider { // reference to the crypto backend that implements all the algorithms final CryptoBackend cryptoBackend; public ExampleProvider(String name, CryptoBackend cryptoBackend) { super(name, 1.0, "JCA/JCE provider for " + name); this.cryptoBackend = cryptoBackend; // register the algorithms we support (SHA-256, SHA-384, DESede, and AES) putService(new MyService (this, "MessageDigest", "SHA-256", "com.foo.ExampleProvider$MyMessageDigest")); putService(new MyService (this, "MessageDigest", "SHA-384", "com.foo.ExampleProvider$MyMessageDigest")); putService(new MyCipherService (this, "Cipher", "DES", "com.foo.ExampleProvider$MyCipher")); putService(new MyCipherService (this, "Cipher", "AES", "com.foo.ExampleProvider$MyCipher")); } // the API of our fictitious crypto backend static abstract class CryptoBackend { abstract byte[] digest(String algorithm, byte[] data); abstract byte[] encrypt(String algorithm, KeyHandle key, byte[] data); abstract byte[] decrypt(String algorithm, KeyHandle key, byte[] data); abstract KeyHandle createKey(String algorithm, byte[] keyData); } // the shell of the representation the crypto backend uses for keys private static final class KeyHandle { // fill in code } // we have our own ServiceDescription implementation that overrides newInstance() // that calls the (Provider, String) constructor instead of the no-args constructor private static class MyService extends Service { private static final Class[] paramTypes = {Provider.class, String.class}; MyService(Provider provider, String type, String algorithm, String className) { super(provider, type, algorithm, className, null, null); } public Object newInstance(Object param) throws NoSuchAlgorithmException { try { // get the Class object for the implementation class Class clazz; Provider provider = getProvider(); ClassLoader loader = provider.getClass().getClassLoader(); if (loader == null) { clazz = Class.forName(getClassName()); } else { clazz = loader.loadClass(getClassName()); } // fetch the (Provider, String) constructor Constructor cons = clazz.getConstructor(paramTypes); // invoke constructor and return the SPI object Object obj = cons.newInstance(new Object[] {provider, getAlgorithm()}); return obj; } catch (Exception e) { throw new NoSuchAlgorithmException("Could not instantiate service", e); } } } // custom ServiceDescription class for Cipher objects. See supportsParameter() below private static class MyCipherService extends MyService { MyCipherService(Provider provider, String type, String algorithm, String className) { super(provider, type, algorithm, className); } // we override supportsParameter() to let the framework know which // keys we can support. We support instances of MySecretKey, if they // are stored in our provider backend, plus SecretKeys with a RAW encoding. public boolean supportsParameter(Object obj) { if (obj instanceof SecretKey == false) { return false; } SecretKey key = (SecretKey)obj; if (key.getAlgorithm().equals(getAlgorithm()) == false) { return false; } if (key instanceof MySecretKey) { MySecretKey myKey = (MySecretKey)key; return myKey.provider == getProvider(); } else { return "RAW".equals(key.getFormat()); } } } // our generic MessageDigest implementation. It implements all digest // algorithms in a single class. We only implement the bare minimum // of MessageDigestSpi methods private static final class MyMessageDigest extends MessageDigestSpi { private final ExampleProvider provider; private final String algorithm; private ByteArrayOutputStream buffer; MyMessageDigest(Provider provider, String algorithm) { super(); this.provider = (ExampleProvider)provider; this.algorithm = algorithm; engineReset(); } protected void engineReset() { buffer = new ByteArrayOutputStream(); } protected void engineUpdate(byte b) { buffer.write(b); } protected void engineUpdate(byte[] b, int ofs, int len) { buffer.write(b, ofs, len); } protected byte[] engineDigest() { byte[] data = buffer.toByteArray(); byte[] digest = provider.cryptoBackend.digest(algorithm, data); engineReset(); return digest; } } // our generic Cipher implementation, only partially complete. It implements // all cipher algorithms in a single class. We implement only as many of the // CipherSpi methods as required to show how it could work private static abstract class MyCipher extends CipherSpi { private final ExampleProvider provider; private final String algorithm; private int opmode; private MySecretKey myKey; private ByteArrayOutputStream buffer; MyCipher(Provider provider, String algorithm) { super(); this.provider = (ExampleProvider)provider; this.algorithm = algorithm; } protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { this.opmode = opmode; myKey = MySecretKey.getKey(provider, algorithm, key); if (myKey == null) { throw new InvalidKeyException(); } buffer = new ByteArrayOutputStream(); } protected byte[] engineUpdate(byte[] b, int ofs, int len) { buffer.write(b, ofs, len); return new byte[0]; } protected int engineUpdate(byte[] b, int ofs, int len, byte[] out, int outOfs) { buffer.write(b, ofs, len); return 0; } protected byte[] engineDoFinal(byte[] b, int ofs, int len) { buffer.write(b, ofs, len); byte[] in = buffer.toByteArray(); byte[] out; if (opmode == Cipher.ENCRYPT_MODE) { out = provider.cryptoBackend.encrypt(algorithm, myKey.handle, in); } else { out = provider.cryptoBackend.decrypt(algorithm, myKey.handle, in); } buffer = new ByteArrayOutputStream(); return out; } // code for remaining CipherSpi methods goes here } // our SecretKey implementation. All our keys are stored in our crypto // backend, we only have an opaque handle available. There is no // encoded form of these keys. private static final class MySecretKey implements SecretKey { final String algorithm; final Provider provider; final KeyHandle handle; MySecretKey(Provider provider, String algorithm, KeyHandle handle) { super(); this.provider = provider; this.algorithm = algorithm; this.handle = handle; } public String getAlgorithm() { return algorithm; } public String getFormat() { return null; // this key has no encoded form } public byte[] getEncoded() { return null; // this key has no encoded form } // Convert the given key to a key of the specified provider, if possible static MySecretKey getKey(ExampleProvider provider, String algorithm, Key key) { if (key instanceof SecretKey == false) { return null; } // algorithm name must match if (!key.getAlgorithm().equals(algorithm)) { return null; } // if key is already an instance of MySecretKey and is stored // on this provider, return it right away if (key instanceof MySecretKey) { MySecretKey myKey = (MySecretKey)key; if (myKey.provider == provider) { return myKey; } } // otherwise, if the input key has a RAW encoding, convert it if (!"RAW".equals(key.getFormat())) { return null; } byte[] encoded = key.getEncoded(); KeyHandle handle = provider.cryptoBackend.createKey(algorithm, encoded); return new MySecretKey(provider, algorithm, handle); } } }