/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.pki;
import javax.microedition.securityservice.CMSMessageSignatureServiceException;
import javax.microedition.pki.UserCredentialManagerException;
import com.sun.j2me.main.Configuration;
/**
* This class provides functionality for user credential management
* which includes
* creating certificate signing requests, adding user credentials,
* and removing credentials that may be used to generate digital
* signatures as specified in the
* <code>CMSMessageSignatureService</code> class.
* The initial version of credential management supports
* X.509 version 3 Certificates and URIs that resolve to X.509
* Certificates.
* <p>
* In a public key cryptographic system, a user has two distinct keys.
* One key is kept private while the other is made public. There are
* a number of public key cryptographic systems, some of which may
* be used for the creation of digital signatures (for example, DSA), while
* others can be used for encryption (for example, Rabin). Some systems may
* be used for both encryption and digital signatures (for example, RSA).
* Generally the private key, which is only known to the user,
* is used to generate a signature or to decrypt a message. The
* public key, as can be deduced from the name, is public knowledge
* and is used to verify the user's signature or to encrypt
* information intended for the user.
* </p>
*
* <p>
* When selecting a public key to encrypt a message or verify a
* digital signature, it is important to be able to link the public
* key either to the user for which the encrypted message is intended or to
* the user that generated the signature. Public key infrastructure
* (PKI) provides a mechanism for binding an identity to a public
* key. The binding is expressed in a data structure known as a
* certificate. The X.509 certificate format is one of the most
* widely adopted certificate formats. X.509 certificates generally
* contain at least the following information:
* <ul>
* <li>
* An X.500 name that can potentially be linked to the identity
* of the user.
* </li>
* <li>
* The public key associated with the X.500 name.
* </li>
* <li>
* A validity period for the certificate (Not Before and Not After).
* </li>
* <li>
* Information on the certificate issuer (an X.500 name for the
* issuer and a serial number). This uniquely identifies a
* certificate in a PKI.
* </li>
* </ul>
*
* The certificate may contain additional information. The certificate
* itself is signed by the certificate issuer. The certificate issuer
* is usually referred to as a Certificate Authority (CA).
* </p>
*
* <p>
* The process that a CA follows before issuing a certificate is
* governed by the certification practice statement (CPS) of the
* CA. This usually involves both technical and non-technical
* steps that need to be completed before a certificate is issued.
* Technical steps include obtaining the public key that must be
* certified, verifying that the user is in possession of the
* corresponding private key, and returning the certificate or a
* reference to the certificate once it is issued. Non-technical
* steps include the processes followed to establish the
* certificate requesters identity.
* Upon completion of the technical and non-technical steps of the
* registration process, the user is said to be enrolled into the PKI.
* </p>
*
* <p>
* The purpose of this class is to provide the technical building
* blocks required to enroll a user in a PKI. This will allow a
* user to obtain a certificate that can be used in conjunction
* with the <code>sign</code> and <code>authenticate</code> methods
* in the <code>
* javax.microedition.securityservice.CMSMessageSignatureService
* </code> class.
* This can also be used for
* renewing and deleting certificates once they have expired.
* With this package it is possible to:
* <ul>
* <li>
* Obtain a certificate signing request that can be sent to a PKI.
* </li>
* <li>
* Add a certificate or certificate URI to a certificate store.
* </li>
* <li>
* Remove a certificate or certificate URI from a certificate store.
* </li>
* </ul>
* </p>
*
* <h2>Example</h2>
*
* <pre>
* // Parameters for certificate request message.
* String nameInfo = new String("CN=User Name");
* byte[] enrollmentRequest = null;
* int keyLength = 1024;
*
* // User friendly names and prompts.
* String securityElementID = new String("Bank XYZ");
* String securityElementPrompt = new String
* ("Please insert bank XYZ security element before proceeding");
* String friendlyName = new String("My Credential");
*
* // Certificate chain and URI from registration response.
* byte[] pkiPath;
* String uri;
*
*
* // Obtain a certificate enrollment request message.
* try {
* enrollmentRequest = UserCredentialManager.generateCSR
* (nameInfo, UserCredentialManager.ALGORITHM_RSA, keyLength,
* UserCredentialManager.KEY_USAGE_NON_REPUDIATION,
* securityElementID, securityElementPrompt, false);
*
* // Send it to a registration server.
* ...
* // Assign values for pkipath and certificate uri
* // from the registration response.
* ...
*
* // Store the certificate on the security element.
* UserCredentialManager.addCredential(friendlyName,
* pkiPath, uri);
* } catch (IllegalArgumentException iae) {
* iae.printStackTrace();
* } catch (NullPointerException npe) {
* npe.printStackTrace();
* } catch (CMSMessageSignatureServiceException cmse) {
* cmse.printStackTrace();
* } catch (UserCredentialManagerException pkie) {
* pkie.printStackTrace();
* }
*
* </pre>
* <p>
* <h2>Note regarding UI implementations</h2>
* </p>
* <p>
* User prompts and notifications should be implemented in such a way that:
* <ul>
* <li>
* the UI is distinguishable from a UI generated by external sources
* (for example J2ME applications).
* </li>
* <li>
* external sources are not able to modify the data presented to the user.
* </li>
* <li>
* external sources are not able to retrieve the PIN data.
* </li>
* </ul>
* </p>
*/
final public class UserCredentialManager
{
/**
* Algorithm identifier for an RSA signature key.
* This is the <code>String</code> representation of the
* OID identifying the RSA algorithm.
*/
public final static String ALGORITHM_RSA = "1.2.840.113549.1.1";
/**
* Algorithm identifier for a DSA signature key.
* This is the <code>String</code> representation of the
* OID identifying a DSA signature key.
*/
public final static String ALGORITHM_DSA = "1.2.840.10040.4.1";
/**
* Indicates a key used for authentication.
*/
public final static int KEY_USAGE_AUTHENTICATION = 0;
/**
* Indicates a key used for digital signatures.
*/
public final static int KEY_USAGE_NON_REPUDIATION = 1;
/**
* Indicates that key generation is supported
* on the platform.
*/
private static boolean keygen = false;
static {
String generation = Configuration
.getProperty("com.sun.satsa.keygen");
if (generation != null) {
keygen = generation.equals("true");
}
}
/**
* Constructor for the <code>UserCredentialManager</code> class.
*/
private UserCredentialManager() {
}
/**
* Creates a DER encoded PKCS#10 certificate enrollment request.
* <p>
* The implementation uses the <code>securityElementID</code>
* and the <code>securityElementPrompt</code> to
* choose an appropriate security element.
* If an appropriate
* security element cannot be found, a
* <code>UserCredentialManagerException</code> is thrown and
* the <code>getReason</code> method MUST return
* <code>SE_NOT_FOUND</code>.
* The implementation MUST use the <code>algorithm</code>,
* <code>keyLen</code>, and <code>keyUsage</code> parameters
* to select a specific key to use in signing the
* certificate request.
* If the algorithm is not supported or the specific key
* parameters can not be fulfilled, then a
* <code>UserCredentialManagerException</code> MUST be thrown
* and the <code>getReason</code> method MUST return
* <code>SE_NO_KEYS</code>.
* </p>
*
* <p>
* If the platform can select a security element and the security
* element contains multiple keys, it is up to the platform to
* select an appropriate key
* (when key generation is not forced).
*
* If a key is found that is not yet associated with a user
* certificate or a user certificate request, the platform MUST
* select such a key in preference to keys that are already
* associated with a user certificate or certificate request.
*
* If all keys are associated with a certificate or a certificate
* request, the implementation MUST select the key associated with
* a certificate request in preference to keys that are
* associated with a certificate.
*
* If all keys are already associated with a user certificate and
* key generation was not forced, the platform MAY select one
* of the existing keys for inclusion in the certificate signing
* request, depending on the security element policy.
* </p>
*
* <p>
* The application requests key generation by setting the
* <code>forceKeyGen</code> flag.
* If a key is requested of a security element that is not
* capable of key generation, a
* <code>UserCredentialManagerException</code> MUST be thrown
* and the <code>getReason</code> method MUST return
* <code>SE_NO_KEYGEN</code>. If the key can not be
* generated with the requested key parameters, a
* <code>UserCredentialManagerException</code> MUST be thrown
* and the <code>getReason</code> method MUST return
* <code>SE_NO_KEYS</code>.
* If the security element requires the user to specify a new PIN
* that is used to protect the keys to be generated, the implementation
* of this method is responsible for collecting the new PIN from the user.
* </p>
*
* <p>
* If a security element is found, but it contains no
* keys that can be used, then a
* <code>UserCredentialManagerException</code> MUST be thrown
* and the <code>getReason</code> method MUST return
* <code>SE_NO_KEYS</code>.
* If a security element is found, but all available
* keys have been associated with certificates and
* if the platform does not allow selection of keys already
* associated with certificates, then a
* <code>UserCredentialManagerException</code> MUST be thrown
* and the <code>getReason</code> method MUST return
* <code>SE_NO_UNASSOCIATED_KEYS</code>.
* </p>
* <p>
* If a security element can be selected and an appropriate
* key is available (either generated or already existing)
* the certification request is generated and formatted. The
* certification request will be formatted as a PKCS#10
* certificate request. The request may contain
* additional attributes.
* </p>
* <p>
* See "X.690 - Information technology - ASN.1 encoding rules:
* Specification of Basic Encoding Rules (BER),
* Canonical Encoding Rules (CER) and
* Distinguished Encoding Rules (DER)" at
* <a href=
* "http://www.itu.int/ITU-T/studygroups/com17/languages/">
* http://www.itu.int/ITU-T/studygroups/com17/languages/
* </a> for details about ASN.1 encoding rules.
*
* </p>
* <p>
* Generation of the certificate enrollment request and the key pair
* must be confirmed by the user. The user should have the option
* to view the detailed information of the key used in signing the
* certificate request, such as
* the key usage, key length, public key algorithm.
* This method returns <code>null</code> if the user cancels the
* certificate enrollment request.
* </p>
* <p>
* Authorization to generate certificate enrollment request is
* also subject to the policy
* of the underlying security element. If user authorization is required
* through the entry of PIN, the implementation of this method
* is responsible for collecting the PIN from the user. Incorrect
* PIN entry is handled by
* the implementation. The number of retries following incorrect
* PIN entry is
* governed by the security element policy. If the PIN is blocked due to an
* excessive number of incorrect PIN entries, the implementation
* must throw a
* <code>SecurityException</code> exception.
* </p>
* @param nameInfo the distinguished name
* to be included in the PKCS#10 certificate signing request.
* The distinguished name MUST follow the encoding rules of
* <a href="http://www.ietf.org/rfc/rfc2253.txt">
* RFC2253</a>. If <code>null</code> is passed as the
* parameter value, it is up to the implementation to
* choose an appropriate distinguished name (for example, the WIM
* serial number).
* If <code>nameInfo</code> is empty or not formatted according
* RFC2253 an <code>IllegalArgumentException</code> is thrown.
*
* @param algorithm the Object Identifier (OID) for the public key
* algorithm to use. (see
* <a href="http://www.ietf.org/rfc/rfc1778.txt">RFC 1778</a>)
* The static variables
* <code>UserCredentialManager.ALGORITHM_RSA</code> and
* <code>UserCredentialManager.ALGORITHM_DSA</code> may
* be used to indicate either RSA or DSA signature keys.
* If <code>algorithm</code> is empty or not formatted according
* RFC1778 an <code>IllegalArgumentException</code> is thrown.
* If the requested <code>algorithm</code> is not supported
* on the platform then a
* <code>UserCredentialManagerException</code> MUST be thrown
* and the <code>getReason</code> method MUST return
* <code>SE_NO_KEYS</code>.
*
* @param keyLen the key length (typically 1024 for RSA)
* If <code>keyLen</code> is incorrect an
* <code>IllegalArgumentException</code> is thrown.
*
* @param keyUsage the functionality for which the key is marked
* inside the security element. This may be one of
* <code>UserCredentialManager.KEY_USAGE_AUTHENTICATION</code>
* or
* <code>UserCredentialManager.KEY_USAGE_NON_REPUDIATION</code>.
* If <code>keyUsage</code> is incorrect an
* <code>IllegalArgumentException</code> is thrown.
*
* @param securityElementID identifies the security element on
* which the key resides or will be generated.
* If this parameter is
* <code>null</code> the implementation MUST choose the first
* available security element that meets the specified requirements.
* If no appropriate security element is found, the
* <code>securityElementPrompt</code> parameter MUST be used
* to guide the user on selecting the correct security element.
* If no security element can be selected, a
* <code>UserCredentialManagerException</code> is thrown and
* the <code>getReason</code> method MUST return
* <code>SE_NOT_FOUND</code>.
*
* @param securityElementPrompt guides a user to insert the
* correct security element, if the suitable security element is
* removable and not detected.
* If this parameter is set to <code>null</code>, a user prompt is not
* used to guide the user to select an appropriate security element.
*
* @param forceKeyGen if set to <code>true</code> a new key MUST be
* generated. If the security element does not support key generation
* it MUST throw an <code>UserCredentialManagerException</code> and
* the <code>getReason</code> method MUST return a
* <code>SE_NO_KEYGEN</code> error code.
* If set to <code>false</code> no key
* generation is required and an existing key may be used.
*
* @return DER encoded PKCS#10 certificate enrollment request, or
* <code>null</code> if the certificate
* enrollment request was cancelled by the user before completion.
* @throws IllegalArgumentException if the parameters are not valid
* @throws UserCredentialManagerException if an error occurs while
* generating the certificate request
* @throws SecurityException if the caller is not
* authorized to access the user certificate store
* @throws CMSMessageSignatureServiceException if an
* error occurs while signing the certificate request
*/
public static byte[] generateCSR(String nameInfo,
String algorithm,
int keyLen,
int keyUsage,
String securityElementID,
String securityElementPrompt,
boolean forceKeyGen)
throws UserCredentialManagerException,
CMSMessageSignatureServiceException
{
/* User requested a new key be generated. */
if (forceKeyGen) {
if (! UserCredentialManager.keygen) {
// Configuration parameter disabled key generation.
throw new UserCredentialManagerException
(UserCredentialManagerException.SE_NO_KEYGEN);
}
}
return com.sun.satsa.pki.PKIManager.generateCSR(nameInfo,
algorithm, keyLen, keyUsage, securityElementID,
securityElementPrompt, forceKeyGen);
}
/**
* Adds a user certificate or certificate
* URI to a certificate store.
* <p>
* A credential is registered using an ordered sequence of
* certificates, called a PKI Path.
* The PKI Path is defined in <A HREF=
* "ftp://ftp.bull.com/pub/OSIdirectory/DefectResolution/TechnicalCorrigenda/ApprovedTechnicalCorrigendaToX.509/8%7CX.509-TC3%284th%29.pdf">
* ITU-T RECOMMENDATION X.509 (2000) | ISO/IEC 9594-8:2001,
* Technical Corrigendum 1 (DTC 2) </A> and is used
* by the J2SE <A HREF=
* "http://java.sun.com/j2se/1.4.1/docs/guide/security/certpath/CertPathProgGuide.html#AppA">
* CertPath Encodings</A>.</p>
* <p>
* <strong>PkiPath:</strong> an ASN.1 DER encoded sequence of
* certificates, defined as follows:<pre>
* <code>PkiPath ::= SEQUENCE OF Certificate</code>
* </pre>
* Within the sequence, the order of certificates is such that the
* subject of the first certificate is the issuer of the second
* certificate, etc. Each certificate in PkiPath shall be
* unique. No certificate may appear more than once in a value of
* Certificate in PkiPath. The last certificate is the end entity
* user certificate.
* </p>
* <p>
* The use of the certificate URI is platform dependent.
* Some platforms may not store the user certificate, but may
* instead keep a copy of the URI.
* If only the URI is retained instead of the certificates
* included in the pkiPath, the implementation MUST parse the user
* certificate in the pkiPath to obtain relevant information such
* as the issuing CA name, the user certificate serial number, the
* public key, and user distinguished name. Some of these fields
* may be required by the underlying security element.
* The certificate URI parameter can be
* <code>null</code> in deployments where off device access to
* certificate storage is not supported.
* </p>
* <p>
* Some platforms MAY store the credential information with
* a specific security element, while other platforms MAY
* have a central repository for credentials. It is platform
* dependent where the information is maintained.
* </p>
* <p>
* Storing the requested credential must be confirmed by the
* user. The implementation must display the user friendly
* name of the certificate or the certificate URL. The user should
* have the option
* to view the detailed information of the credential, such as the
* certificate issuer, certificate subject, and certificate
* validity period.
* This method returns <code>false</code> if the user cancels the
* request to add the credential.
* </p>
* <p>
* Authorization to store the requested credential is also subject
* to the policy
* of the underlying security element or the platform. If user
* authorization is required
* through the entry of PIN, the implementation of this method
* is responsible for collecting the PIN from the user. Incorrect
* PIN entry is handled by
* the implementation. The number of retries following incorrect
* PIN entry is
* governed by the policy of the security element or the
* platform. If the PIN is blocked due to an
* excessive number of incorrect PIN entries, the implementation
* must throw a
* <code>SecurityException</code> exception.
* </p>
* If the requested certificate can not be stored, a
* <code>UserCredentialManagerException</code> is thrown and
* the <code>getReason</code> method MUST return
* <code>CREDENTIAL_NOT_SAVED</code>.
* @param certDisplayName the user friendly
* name associated with the certificate.
* If <code>certDisplayName</code> is <code>null</code> or
* an empty string an <code>IllegalArgumentException</code>
* is thrown. Applications MUST use unique user
* friendly names to make selection easier.
* If the <code>certDisplayName</code> is already
* registered, an <code>IllegalArgumentException</code>
* is thrown.
*
* @param pkiPath the DER encoded PKIPath containing user
* certificate and certificate authority certificates.
* If <code>pkiPath</code> is <code>null</code> or
* incorrectly formatted an <code>IllegalArgumentException</code>
* is thrown.
* If <code>pkiPath</code> is already registered,
* an <code>IllegalArgumentException</code> is thrown.
*
* @param uri a URI that resolves to a X.509v3 certificate.
* The uri can be <code>null</code>.
*
* @throws IllegalArgumentException if parameters are not
* valid
* @throws UserCredentialManagerException if an error occurs
* while adding a user credential
* @throws SecurityException if the caller is not
* authorized to add to the user certificate store
*
* @return <code>false</code> if the operation to add the
* credential was cancelled by the user
* before completion.
*/
public static boolean addCredential(String certDisplayName,
byte[] pkiPath, String uri)
throws UserCredentialManagerException {
return com.sun.satsa.pki.PKIManager.addCredential(certDisplayName,
pkiPath, uri);
}
/**
* Removes a certificate or certificate
* URI from a certificate store.
* <p>
* Removal of the credential from the certificate store
* must be confirmed by the user. The implementation must display
* the user friendly
* name of the certificate or the certificate URL. The user should
* have the option
* to view the detailed information of the credential, such as the
* certificate issuer, certificate subject, and certificate
* validity period.
* This method returns <code>false</code> if the user cancels the
* request to remove the credential.
* </p>
* <p>
* Authorization to remove the requested credential is also
* subject to the policy
* of the underlying security element or the platform. If user
* authorization is required
* through the entry of PIN, the implementation of this method
* is responsible for collecting the PIN from the user. Incorrect
* PIN entry is handled
* by the implementation. The number of retries following
* incorrect PIN entry is
* governed by the policy of the security element or the
* platform. If the PIN is blocked due to an
* excessive number of incorrect PIN entries, the implementation
* must throw a
* <code>SecurityException</code> exception.
* </p>
* @param certDisplayName the user friendly
* name associated with the certificate.
* If <code>certDisplayName</code> is <code>null</code> or
* an empty string an <code>IllegalArgumentException</code>
* is thrown.
*
* @param issuerAndSerialNumber the DER encoded ASN.1 structure
* that contains the certificate issuer and serial number as
* defined in <a href="http://www.ietf.org/rfc/rfc3369.txt">
* RFC 3369</a>.
* If <code>issuerAndSerialNumber</code> is <code>null</code> or
* not properly formatted according to RFC3369
* an <code>IllegalArgumentException</code> is thrown.
* If the requested certificate is not found, a
* <code>UserCredentialManagerException</code> is thrown and
* the <code>getReason</code> method MUST return
* <code>CREDENTIAL_NOT_FOUND</code>.
*
* @param securityElementID identifies the security element on
* which the key resides. If this parameter is
* <code>null</code> the implementation MUST choose the first
* available security element that meets the specified requirements.
* If no appropriate security element is found, the
* <code>securityElementPrompt</code> parameter MUST be used
* to guide the user on selecting the correct security element.
* If no security element can be selected, a
* <code>UserCredentialManagerException</code> is thrown and
* the <code>getReason</code> method MUST return
* <code>SE_NOT_FOUND</code>.
*
* @param securityElementPrompt guides the user to insert
* the correct security element if the security element is
* removable and not detected.
* If this parameter is set to <code>null</code>, no information
* regarding which security element to use is displayed to
* the user.
*
* @throws IllegalArgumentException if the parameters are not valid
* @throws UserCredentialManagerException if an error occurs
* while removing the credential
* @throws SecurityException if the caller is not
* authorized to remove from the user certificate store
* @return <code>false</code> if the operation to remove the
* credential was cancelled by the user
* before completion.
*/
public static boolean removeCredential(String certDisplayName,
byte[] issuerAndSerialNumber, String securityElementID,
String securityElementPrompt)
throws UserCredentialManagerException {
return com.sun.satsa.pki.PKIManager.removeCredential(
certDisplayName, issuerAndSerialNumber, securityElementID,
securityElementPrompt);
}
}