/*
 *   
 *
 * Copyright  1990-2006 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.midp.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 final 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 final 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 final boolean removeCredential(String certDisplayName,
        byte[] issuerAndSerialNumber, String securityElementID,
        String securityElementPrompt)
            throws UserCredentialManagerException {

        return com.sun.satsa.pki.PKIManager.removeCredential(
                certDisplayName, issuerAndSerialNumber, securityElementID,
                securityElementPrompt);
    }
}
