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 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);
}
}
}