A Brief Introduction to PKI

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.

Generating Signatures

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:

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.

Finding Keys

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.

Signature Options

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 (|).

Signing Data

To generate a signature to verify data integrity, use the sign() method:

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

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:

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.

Exceptions

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.

Certificate Management

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.

Adding Certificates

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:

A self-signed root certificate from the Acme Certificate Authority.

A certificate containing the Trustworthy Software company’s public key, signed by Acme.

A certificate representing the user’s key pair, signed by Trustworthy Software.

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:

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.

Where Do Certificates Go?

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.

Removing Certificates

You can remove certificates from the certificate store with the removeCredential() method:

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.

Requesting a New Certificate

The last method in UserCredentialManager creates a Certificate Signing Request (CSR) that you can use to request a certificate for a key pair.

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.

A script enabled browser is required for this page to function properly.A script enabled browser is required for this page to function properly.A script enabled browser is required for this page to function properly.A script enabled browser is required for this page to function properly.