SATSA-PKI allows applications to request digital signatures from a smart card. It also includes basic certificate management methods.
SATSA-PKI contains two classes, javax.microedition.securityservice.CMSMessageSignatureService
and javax.microedition.pki.UserCredentialManager
.
Public Key Infrastructure (PKI) is one way of associating cryptographic keys with people, businesses, or other objects. It is based on cryptographic signatures and certificates.
A signature is a value computed from input data and a private key, in a process that is called signing the data. A signature can be verified using the same input data and the public key that corresponds to the signing key. Signatures are useful for ensuring data integrity. If Bob signs some data with his private key and sends it to Fiona, she can use his public key to verify the signature, assuring herself that the data has not changed in transit.
A certificate is a special package that consists of information about a person, a copy of the person’s public key, and a signature by another person. In essence, a certificate says “I, the signer, certify that this person has this public key.” For example, Fiona could create a certificate that links Bob to his public key.
Why is a certificate useful? It allows you to trust someone you might not know very well. For example, suppose that Orrin trusts Fiona but doesn’t know Bob. If Orrin gets a signed message from Bob, how can he verify the signature? Bob can supply his certificate from Fiona that links him to his public key. Orrin can verify the certificate using Fiona’s public key, which means he can now use Bob’s public key to verify the message he just received from Bob.
Certificate can be chained together in this way until they end in a root certificate, issued by a Certificate Authority (CA). The term root is a little misleading, implying strength and fundamental structure. In truth, a CA root certificate is a self-signed certificate, which means the certificate was signed using the private key whose matching public key is contained in the certificate. Self-signed certificates are easy to make, and you can claim to be anyone you want in a self-signed certificate. The reason it’s hard to forge a CA certificate is that there are so many authentic copies already distributed throughout the computing world.
In practice, devices (or browsers) usually have a database of CA root certificates so that when certificate chains are received, they can be verified back to a CA root.
This section provides only a brief introduction to signatures and certificates. For deeper coverage, try Bruce Schneier’s excellent Applied Cryptography (Wiley, 1995).
The CMSMessageSignatureService
class allows MIDP applications to request a cryptographic signature. A signature is useful for two reasons. First, it proves the identity of the user, which is called authentication. Second, it certifies the integrity of data. This use is also referred to as non-repudiation, which means after data is signed, the signer can’t “take it back” or deny signing the data. A user’s keys can be marked specifically for one use or the other.
CMSMessageSignatureService
supports both uses of digital signatures by selecting an appropriate key to generate a signature. The type of key selected depends on whether you call the sign()
method or one of the authenticate()
methods.
Although it is likely that the signature is performed on a smart card, if one is available, the cryptographic signing can take place anywhere, depending on the implementation. At the application level, simply call one of the methods in CMSMessageSignatureService
and the implementation handles the details.
A call to authenticate()
or sign()
returns a formatted digital signature, which is essentially the signature itself plus information about the signer and the data that was signed. CMSMessageSignatureService
produces formatted digital signatures that conform to the Cryptographic Message Syntax (CMS), which is defined in RFC 2630 and extended in RFC 2634. For more information, refer to the RFCs directly:
http://www.ietf.org/rfc/rfc2630.txt
http://www.ietf.org/rfc/rfc2634.txt
Typically, a MIDP application uses CMSMessageSignatureService
to have a smart card create a signature, then passes the signature to a server where it is verified and used to perform some action on behalf of the user.
When your application calls sign()
or authenticate()
, the SATSA implementation tries to locate an appropriate signing key. You can pass additional parameters to sign()
or authenticate()
to affect how the implementation searches for keys.
You can pass a list of acceptable Certificate Authorities (CAs). The implementation only considers keys that are certified by the CAs in the list you supply. The list is a string array, where each string is the distinguished name of a CA, formatted according to RFC 2253.
If the implementation cannot find any appropriate keys for signing, it displays a prompt to the user. You can specify the text of the prompt that is shown to the user, which is usually something like “Please insert such-and-so card now.”
Conversely, if the implementation finds more than one appropriate signing key, it is obliged to offer the user a choice of keys.
The use of private keys on a smart card or other security element might be restricted. For example, a smart card could require the user to enter a short code (a PIN) to access a private key, or a more sophisticated card might need to verify a fingerprint. As an application developer, bear in mind that a call to sign()
or authenticate()
might result in several user prompts outside your application’s control.
The form of the signature returned by sign()
or authenticate()
can be controlled using two options that are defined as constants in the CMSMessageSignatureService
class.
SIG_INCLUDE_CONTENT
indicates that the formatted signature should include the content that was signed (an opaque signature). The absence of this option tells the implementation to create a detached signature.
The other option, SIG_INCLUDE_CERTIFICATE
, controls whether the signer’s certificate is included in the formatted signature.
To combine the two options, use the bitwise OR operator (|
).
To generate a signature to verify data integrity, use the sign()
method:
public static final byte[] sign(String stringToSign, int options, String[] caNames, String securityElementPrompt) throws CMSMessageSignatureServiceException, UserCredentialManagerException
The stringToSign
is the data you would like signed. The options
are described previously, as is the list of CAs in caNames
. Finally, securityElementPrompt
is the string that is shown to the user if an appropriate key cannot be found.
Before proceeding with the signing, the implementation must display stringToSign
as well as the certificate name corresponding to the key that will be used for signing. The user must explicitly confirm everything before the implementation can create the signature.
Authentication proceeds almost exactly like signing, except the implementation searches for keys that are marked for authentication. In addition, the authenticate()
method has two overloaded forms. The first form is just like the sign()
method:
public static final byte[] authenticate(String stringToAuthenticate, int options, String[] caNames, String securityElementPrompt) throws CMSMessageSignatureServiceException, UserCredentialManagerException
The second form signs a byte array instead of a string.
public static final byte[] authenticate( byte[] byteArrayToAuthenticate, int options, String[] caNames, String securityElementPrompt) throws CMSMessageSignatureServiceException, UserCredentialManagerException
In this case, the byte array is not displayed to the user, although the implementation is still supposed to show the name of the certificate whose key will be used for signing.
The sign()
and authenticate()
methods can throw CMSMessageSignatureServiceException
, a special type of exception class that includes constant values representing the cause of the exception. The getReason()
method returns a value that indicates the specific problem with the cryptographic signature or the security element that was supposed to generate the signature. See the documentation of the CMSMessageSignatureServiceException
class for the reason values and their meanings.
The other class in SATSA-PKI, UserCredentialManager
, provides methods for managing a user’s keys. These are the same keys that CMSMessageSignatureService
uses to generate signatures.
UserCredentialManager
provides methods for adding keys, removing keys, and generating a request for new keys. Keys are represented by certificates that link keys to specific people.
Keys are represented by a certificate path. The path is a trail of certification that begins with a CA and ends with the user’s keys. For example, the certificate path might consist of three certificates:
The certificate path is represented as a byte array, and normally is the response you receive after submitting a Certificate Signing Request (CSR) to a certificate issuer. Later in this chapter, <Z_OpenQuote>Requesting a New Certificate” describes how to create a CSR with UserCredentialManager
.
To add a user’s certificate path, use this method in UserCredentialManager
:
public static final boolean addCredential(String certDisplayName, byte[] pkiPath, String uri) throws UserCredentialManagerException
You need to supply a human-readable name for the key pair in certDisplayName
. The actual certificate path is pkiPath
.
The uri
parameter is optional. If it is not null
, uri
represents the user certificate, the last one in the path. This is useful for devices whose keys are stored off the device. On some WAP networks, for example, certificate stores are maintained on a gateway server. In this case, a device can use uri
to reference the certificate on the gateway server rather than storing certificates locally.
The user is prompted to confirm the addition.
When you add certificates with UserCredentialManager
, where do they go? The specification is deliberately flexible about this question and dictates only that they are added to a certificate store. This means that a device is assumed to contain some database of certificates, but it could be stored on the device or on a smart card or other security element. At the application level, you don’t have to worry where the certificates are physically stored. You can add certificates with UserCredentialManager
and obtain signatures with CMSMessageSignatureService
.
You can remove certificates from the certificate store with the removeCredential()
method:
public static final boolean removeCredential(String certDisplayName, byte[] issuerAndSerialNumber, String securityElementID, String securityElementPrompt) throws UserCredentialManagerException
You need to supply the displayable name in certDisplayName
(the same name that was used to add the certificate). You also need to supply the certificate’s issuer and the certificate serial number, formatted as a byte array conforming to RFC 3369.
The securityElementID
parameter identifies the smart card or other security element where the given certificate is expected to be found. If this paramter is null
, the implementation attempts to find the given certificate wherever it can. Finally, securityElementPrompt
is text that is shown to the user to suggest what needs to be done for the implementation to find the certificate it needs to remove. Usually, this is a suggestion to insert a smart card into the device.
The last method in UserCredentialManager
creates a Certificate Signing Request (CSR) that you can use to request a certificate for a key pair.
public static final byte[] generateCSR(String nameInfo, String algorithm, int keyLen, int keyUsage, String securityElementID, String securityElementPrompt, boolean forceKeyGen) throws UserCredentialManagerException, CMSMessageSignatureServiceException
In general, new keys are generated on a smart card (or other security element) and the CSR is also generated on the smart card. You can specify which security element to use with securityElementID
, and securityElementPrompt
is shown to the user if the security element your application requests is not immediately available. If you pass null
for securityElementID
, the implementation selects an appropriate security element if one is available.
The nameInfo
parameter contains the name you want to associate with a key pair. It is a distinguished name which is formatted according to RFC 2253. You can pass null
for nameInfo
, in which case the implementation chooses a name for you.
The actual keys that are used may already exist on the smart card, or they are created if no existing appropriate keys are found. The forceKeyGen
parameter controls whether existing keys can be used (false
) or new keys must be generated (true
).
The type of keys are controlled by algorithm
, keyLen
, and keyUsage
.
The key algorithm is an object identifier for a cryptographic signature algorithm, as described in RFC 1778. UserCredentialManager
provides two constants, ALGORITHM_DSA
and ALGORITHM_RSA
, that can be used for the algorithm
parameter.
The desired key length, in bits, is passed in the keyLen
parameter.
As you already learned in the CMSMessageSignatureService
class, keys can be used for authentication or general-purpose signing. The certificate that contains a key indicates its intended use. When you generate a CSR with UserCredentialManager
, the keyUsage
parameter specifies the purpose of the key. Use a constant value, either KEY_USAGE_AUTHENTICATION
or KEY_USAGE_NON_REPUDIATION
.
SATSA Developer's Guide SATSA Reference Implementation 1.0 |
Copyright © 2004 Sun Microsystems, Inc. All rights reserved.