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), and
are specified at the Security in J2SE 5 home 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.
2.0 Sun PKCS#11 Provider
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,
Cryptographic Smartcards,
Hardware cryptographic accelerators, and
High performance software implementations.
Note that Java SE only
facilitates accessing native PKCS#11 implementations, it does not itself include
a native PKCS#11 implementation. However, cryptographic devices such as
Smartcards and hardware accelerators often come with software that includes a
PKCS#11 implementation, which you need to install and configure according to
manufacturer's instructions.
2.1 Requirements
The Sun PKCS#11 provider is supported on
Solaris (SPARC and x86) and Linux (x86) in both 32-bit and 64-bit Java
processes. It is also supported on 32-bit Windows (x86) but not currently
on 64-bit Windows platforms due to the lack of suitable PKCS#11 libraries.
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.
2.2 Configuration
The Sun PKCS#11 provider is implemented by the main
class 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 ommitted
security.provider.7=sun.security.pkcs11.SunPKCS11 /opt/bar/cfg/pkcs11.cfg
To 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.so
Comments 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 one 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
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.
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 accomodate tokens that require particular attributes.
For details, see the section below.
Attributes Configuration
The attributes option allows you to specify additional PKCS#11 attributes
that should be set when creating PKCS#11 key objects. By default, the
SunPKCS11 provider only specifies mandatory PKCS#11 attributes when creating
objects. For example, for RSA public keys it specifies the key type and
algorithm (CKA_CLASS and CKA_KEY_TYPE) and the key values for RSA public
keys (CKA_MODULUS and CKA_PUBLIC_EXPONENT). The PKCS#11 library you are
using will assign implementation specific default values to the other
attributes of an RSA public key, for example that the key can be used
to encrypt and verify messages (CKA_ENCRYPT and CKA_VERIFY = true).
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:
generate, for keys generated via a KeyPairGenerator
or KeyGenerator
import, for keys created via a KeyFactory or SecretKeyFactory.
This also applies to Java software keys automatically converted to PKCS#11 key
objects when they are passed to the initialization method of a cryptographic
operation, for example Signature.initSign().
*, for keys created using either a generate or a create operation.
Valid values for keytype are CKO_PUBLIC_KEY, CKO_PRIVATE_KEY,
and CKO_SECRET_KEY, for public, private, and secret keys, respectively,
and * to match any type of key.
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:
a boolean value, true or false
an integer, in decimal form (default) or in hexadecimal form
if it begins with 0x.
null, indicating that this attribute should not be
specified when creating objects.
If the attributes option is specified multiple times, the entries are
processed in the order specified with the attributes aggregated and later
attributes overriding earlier ones. For example, consider the following
configuration file excerpt:
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 useable 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.
2.3 Accessing Network Security Services (NSS)
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.11.1.
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 LD_LIBRARY_PATH
or PATH (on Windows) to include this directory in order to allow
the operating system to locate the dependent libraries.
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. This mode is useful because NSS includes highly optimized
implementations and algorithms not currently available in
Sun's bundled Java based crypto providers,
for example Elliptic Curve Cryptography (ECC).
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 crypto module is the default in noDb mode.
It supports crypto operations without login but no persistent keys.
The fips module is the default if the NSS secmod.db
has been set to FIPS-140 compliant mode. In this mode, NSS restricts the
available algorithms and the PKCS#11 attributes with which keys can be
created.
The keystore module is the default in other configurations.
It supports persistent keys using the PKCS11 KeyStore, which are stored
in the NSS DB files. This module requires login.
The trustanchors module enables access to NSS trust anchor
certificates via the PKCS11 KeyStore, if secmod.db has been
configured to include the trust anchor library.
name = NSSfips
nssLibraryDirectory = /opt/tests/nss/lib
nssSecmodDirectory = /opt/tests/nss/fipsdb
nssModule = fips
3.0 Application Developers
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 enhancments are discussed in
this section.
3.1 Token Login
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.
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.Builder builder = new KeyStore.Builder("PKCS11");
builder.setCallbackHandler(new MyGuiCallbackHandler());
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.
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 = Security.getProvider("SunPKCS11");
aprov.login(subject, new MyGuiCallbackHandler());
3.2 Token Keys
Java Key objects may or may not contain actual key material.
A software Key object does contain the actual key material and allows
access to that material.
An unextractable key on a secure token (such as a Smartcard) is
represented by a Java Key object that does not contain the actual key
material. The Key object only contains a reference to the actual key.
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.
3.3 Delayed Provider Selection
Prior to J2SE 5.0, the Java cryptography getInstance()
methods, such as Cipher.getInstance("DES"), 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.
Furthermore, if an application calls the
initialization method multiple times (each time with a different key, for
example), the proper provider for the given key is selected each time. In
other words, a different provider may be selected for each initialization
call.
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.
Cipher.getBlockSize
Cipher.getExcemptionMechanism
Cipher.getIV
Cipher.getOutputSize
Cipher.getParameters
Mac.getMacLength
Signature.getParameters
Signature.setParameter
3.4 JAAS KeyStoreLoginModule
Java SE comes with a JAAS keystore login
module, KeyStoreLoginModule
that allows an application to authenticate using its identity in a specified
keystore. After authentication, the application would have acquire its
principal and credentials information (certificate and private key) from the
keystore. By using this login module and configuring it to use a PKCS#11 token
as a keystore, the application can acquire this information from a PKCS#11
token.
Use the following options to configure the KeyStoreLoginModule to
use a PKCS#11 token as the keystore.
keyStoreURL="NONE"
keyStoreType="PKCS11"
keyStorePasswordURL=some_pin_url
where
some_pin_url is the location of the PIN. If the
keyStorePasswordURL option is omitted, then the login module will get
the PIN via the application's callback handler, supplying it with a
PasswordCallback. Here is an example of a configuration file that
uses a PKCS#11 token as a 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;
};
3.5 Tokens as JSSE Keystore and Trust Stores
To use PKCS#11 tokens as
JSSE keystores or trust stores, the JSSE application can use the APIs described
previously to instantiate a KeyStore that is backed by a PKCS#11
token and pass it to its key manager and trust manager. The JSSE application
will then have access to the keys on the token.
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").
4.0 Tools
In J2SE 5.0, the security
tools were updated to support operations using the new Sun PKCS#11 provider.
The changes are discussed below.
4.1 KeyTool and JarSigner
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.
-keystore NONE
-storetype PKCS11
Here an example of a command to list the
contents of the configured PKCS#11 token.
keytool -keystore NONE -storetype PKCS11 -list
The 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.
-providerName providerName
For the Sun PKCS#11 provider,
providerName 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 command lists the contents of
the PKCS#11 keystore provider instance with name suffix SmartCard.
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.
ConfigFilePath is the path to the token configuration file.
Here is an example of a command to list a PKCS#11 keystore when the Sun
PKCS#11 provider has not been configured in the java.security file.
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.
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.
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
facilties.
5.1 Provider Services
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.
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.Servicee 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.
5.1.1 Instantiating Engine Classes
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).
5.1.2 Parameter Support
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.
Appendix A: Sun PKCS#11 Provider's Supported Algorithms
The following
table lists the Java algorithms supported by the Sun PKCS#11 provider and
corresponding PKCS#11 mechanisms needed to support them. When multiple
mechanisms are listed, they are given in the order of preference and any one of
them is sufficent.
Note that SunPKCS11 can be instructed to ignore mechanisms by using the
disabledMechanisms and enabledMechanismsconfiguration 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.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.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
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.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-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
Appendix B: Sun PKCS#11 provider's KeyStore Requirements
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.
Read-Only Access
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.
A search for all private key objects on the token
is performed by calling C_FindObjects[Init|Final].
The search template includes the following attributes:
CKA_TOKEN = true
CKA_CLASS = CKO_PRIVATE_KEY
A search for all certificate objects on the token
is performed by calling C_FindObjects[Init|Final].
The search template includes the following attributes:
CKA_TOKEN = true
CKA_CLASS = CKO_CERTIFICATE
Each private key object is matched with its corresponding
certificate by retrieving their respective CKA_ID attributes.
A matching pair must share the same unique CKA_ID.
For each matching pair, the certificate chain is built
by following the issuer->subject path. From the end entity certificate,
a call fo C_FindObjects[Init|Final] is made with a search template
that includes the following attributes:
CKA_TOKEN = true
CKA_CLASS = CKO_CERTIFICATE
CKA_SUBJECT = [DN of certificate issuer]
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).
Each certificate not part of a private key entry
(as the end entity certificate) is checked whether it is trusted.
If the CKA_TRUSTED attribute is true, then a KeyStore
trusted certificate entry is created with the CKA_LABEL
value as the KeyStore alias. If the certificate has no CKA_LABEL,
or if multiple certificates share the same CKA_LABEL,
then the alias is derived as described above.
If the CKA_TRUSTED attribute is not supported
then no trusted certificate entries are created.
Any private key or certificate object not part of a private key entry
or trusted certificate entry is ignored.
A search for all secret key objects on the token
is performed by calling C_FindObjects[Init|Final].
The search template includes the following attributes:
CKA_TOKEN = true
CKA_CLASS = CKO_SECRET_KEY
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.
Write Access
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.
When creating a KeyStore entry (during KeyStore.setEntry, for example),
C_CreateObject is called with CKA_TOKEN=true to create token objects
for the respective entry contents.
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.
If an attempt is made to convert a session object to a token object
(for example, if KeyStore.setEntry is called and the private key object
in the specified entry is a session ojbect), then C_CopyObject
is called with CKA_TOKEN=true.
If multiple certificates in the token are found to share the same
CKA_LABEL, then the write capabilities to the token are disabled.
Since the PKCS#11 specification does not allow regular applications
to set CKA_TRUSTED=true (only token initialization applications may do so),
trusted certificate entries can not be created.
Miscellaneous
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 or CKO_PRIVATE_KEY
CKA_ID [cka_id]
Appendix C: Example Provider
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 MD5, one for SHA-1, 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 (MD5, SHA1, DES, and AES)
putService(new MyService
(this, "MessageDigest", "MD5", "com.foo.ExampleProvider$MyMessageDigest"));
putService(new MyService
(this, "MessageDigest", "SHA1", "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);
}
}
}