mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

matthew_swift
28.47.2010 f2160f4bd1c8ac67e5a86a6710d431e8932877f9
sdk/src/com/sun/opends/sdk/util/Platform.java
@@ -28,6 +28,7 @@
package com.sun.opends.sdk.util;
import static com.sun.opends.sdk.messages.Messages.*;
import java.io.*;
@@ -41,611 +42,793 @@
import org.opends.sdk.LocalizableMessage;
/**
 * Provides a wrapper class that collects all of the JVM vendor
 * and JDK version specific code in a single place.
 *
 * Provides a wrapper class that collects all of the JVM vendor and JDK version
 * specific code in a single place.
 */
public final class Platform {
public final class Platform
{
   //Prefix that determines which security package to use.
    private static String pkgPrefix;
  /**
   * Default platform class.
   */
  private static class DefaultPlatformIMPL extends PlatformIMPL
  {
    // normalize method.
    private static final Method NORMALIZE;
    // Normalized form method.
    private static final Object FORM_NFKC;
    //IBM security package doesn't appear to support PCKS10, this flags turns
    //off support for that.
    private static boolean certReqAllowed;
    static
    {
    //The two security package prefixes (IBM and SUN).
    private static final String IBM_SEC = "com.ibm.security";
    private static final String SUN_SEC = "sun.security";
    private static final PlatformIMPL IMPL;
    static {
     String vendor = System.getProperty("java.vendor");
     String ver = System.getProperty("java.version");
      if(vendor.startsWith("IBM"))
      Method normalize = null;
      Object formNFKC = null;
      try
      {
        pkgPrefix = IBM_SEC;
        certReqAllowed = false;
        if(ver.startsWith("1.5"))
        final Class<?> normalizer = Class.forName("java.text.Normalizer");
        final Class<?> normalizerForm = Class
            .forName("java.text.Normalizer$Form");
        normalize = normalizer.getMethod("normalize", CharSequence.class,
            normalizerForm);
        formNFKC = normalizerForm.getField("NFKD").get(null);
      }
      catch (final Exception ex)
      {
        // Do not use Normalizer. The values are already set to null.
      }
      NORMALIZE = normalize;
      FORM_NFKC = formNFKC;
    }
    @Override
    public void normalize(final StringBuilder buffer)
    {
      try
      {
        final String normal = (String) NORMALIZE
            .invoke(null, buffer, FORM_NFKC);
        buffer.replace(0, buffer.length(), normal);
      }
      catch (final Exception ex)
      {
        // Don't do anything. buffer should be used.
      }
    }
  }
  /**
   * IBM JDK 5 platform class.
   */
  private static class IBM5PlatformIMPL extends PlatformIMPL
  {
    @Override
    public void normalize(final StringBuilder buffer)
    {
      // No implementation.
    }
  }
  /**
   * Platform base class. Performs all of the certificate management functions.
   */
  private abstract static class PlatformIMPL
  {
    // Key size, key algorithm and signature algorithms used.
    private static final int KEY_SIZE = 1024;
    private static final String KEY_ALGORITHM = "rsa";
    private static final String SIG_ALGORITHM = "SHA1WithRSA";
    // Time values used in validity calculations.
    private static final int SEC_IN_DAY = 24 * 60 * 60;
    private static final int DEFAULT_VALIDITY = 90 * SEC_IN_DAY;
    // These two are used to build certificate request files.
    private static final String TMPFILE_PREFIX = "CertificateManager-";
    private static final String TMPFILE_EXT = ".csr";
    // Methods pulled from the classes.
    private static final String ENCODE_SIGN_METHOD = "encodeAndSign";
    private static final String GENERATE_METHOD = "generate";
    private static final String GET_PRIVATE_KEY_METHOD = "getPrivateKey";
    private static final String GET_SELFSIGNED_CERT_METHOD = "getSelfCertificate";
    private static final String PRINT_METHOD = "print";
    // Classes needed to manage certificates.
    private static Class<?> certKeyGenClass, x500NameClass, x500SignerClass,
        pkcs10Class;
    // Constructors for each of the above classes.
    private static Constructor<?> certKeyGenCons, x500NameCons, x500SignerCons,
        pkcs10Cons;
    static
    {
      final String x509pkg = pkgPrefix + ".x509";
      final String pkcs10Pkg = pkgPrefix + ".pkcs";
      final String certAndKeyGen = x509pkg + ".CertAndKeyGen";
      final String x500Name = x509pkg + ".X500Name";
      final String x500Signer = x509pkg + ".X500Signer";
      try
      {
        certKeyGenClass = Class.forName(certAndKeyGen);
        x500NameClass = Class.forName(x500Name);
        x500SignerClass = Class.forName(x500Signer);
        if (certReqAllowed)
        {
          IMPL = new IBM5PlatformIMPL();
          final String pkcs10 = pkcs10Pkg + ".PKCS10";
          pkcs10Class = Class.forName(pkcs10);
          pkcs10Cons = pkcs10Class.getConstructor(PublicKey.class);
        }
        certKeyGenCons = certKeyGenClass.getConstructor(String.class,
            String.class);
        x500NameCons = x500NameClass.getConstructor(String.class);
        x500SignerCons = x500SignerClass.getConstructor(Signature.class,
            x500NameClass);
      }
      catch (final ClassNotFoundException e)
      {
        final LocalizableMessage msg = ERR_CERTMGR_CLASS_NOT_FOUND.get(e
            .getMessage());
        throw new ExceptionInInitializerError(msg.toString());
      }
      catch (final SecurityException e)
      {
        final LocalizableMessage msg = ERR_CERTMGR_SECURITY.get(e.getMessage());
        throw new ExceptionInInitializerError(msg.toString());
      }
      catch (final NoSuchMethodException e)
      {
        final LocalizableMessage msg = ERR_CERTMGR_NO_METHOD
            .get(e.getMessage());
        throw new ExceptionInInitializerError(msg.toString());
      }
    }
    protected PlatformIMPL()
    {
    }
    /**
     * Add the certificate in the specified path to the specified keystore,
     * creating the keystore using the specified type and path if it the
     * keystore doesn't exist.
     *
     * @param ks
     *          The keystore to add the certificate to, may be null if it
     *          doesn't exist.
     * @param ksType
     *          The type to use if the keystore is created.
     * @param ksPath
     *          The path to the keystore if it is created.
     * @param alias
     *          The alias to store the certificate under.
     * @param pwd
     *          The password to use in saving the certificate.
     * @param certPath
     *          The path to the file containing the certificate.
     * @throws KeyStoreException
     *           If an error occurred adding the certificate to the keystore.
     */
    public final void addCertificate(KeyStore ks, final String ksType,
        final String ksPath, final String alias, final char[] pwd,
        final String certPath) throws KeyStoreException
    {
      try
      {
        final CertificateFactory cf = CertificateFactory.getInstance("X509");
        final InputStream inStream = new FileInputStream(certPath);
        if (ks == null)
        {
          ks = KeyStore.getInstance(ksType);
          ks.load(null, pwd);
        }
        // Do not support certificate replies.
        if (ks.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class))
        {
          final LocalizableMessage msg = ERR_CERTMGR_CERT_REPLIES_INVALID
              .get(alias);
          throw new KeyStoreException(msg.toString());
        }
        else if (!ks.containsAlias(alias)
            || ks
                .entryInstanceOf(alias, KeyStore.TrustedCertificateEntry.class))
        {
          trustedCert(alias, cf, ks, inStream);
        }
        else
        {
          IMPL = new DefaultPlatformIMPL();
          final LocalizableMessage msg = ERR_CERTMGR_ALIAS_INVALID.get(alias);
          throw new KeyStoreException(msg.toString());
        }
        final FileOutputStream fileOutStream = new FileOutputStream(ksPath);
        ks.store(fileOutStream, pwd);
        fileOutStream.close();
        inStream.close();
      }
      catch (final Exception e)
      {
        final LocalizableMessage msg = ERR_CERTMGR_ADD_CERT.get(alias, e
            .getMessage());
        throw new KeyStoreException(msg.toString());
      }
    }
    /**
     * Delete the specified alias from the specified keystore.
     *
     * @param ks
     *          The keystore to delete the alias from.
     * @param ksPath
     *          The path to the keystore.
     * @param alias
     *          The alias to use in the request generation.
     * @param pwd
     *          The keystore password to use.
     * @throws KeyStoreException
     *           If an error occurred deleting the alias.
     */
    public final void deleteAlias(final KeyStore ks, final String ksPath,
        final String alias, final char[] pwd) throws KeyStoreException
    {
      try
      {
        if (ks == null)
        {
          final LocalizableMessage msg = ERR_CERTMGR_KEYSTORE_NONEXISTANT.get();
          throw new KeyStoreException(msg.toString());
        }
        ks.deleteEntry(alias);
        final FileOutputStream fs = new FileOutputStream(ksPath);
        ks.store(fs, pwd);
        fs.close();
      }
      catch (final Exception e)
      {
        final LocalizableMessage msg = ERR_CERTMGR_DELETE_ALIAS.get(alias, e
            .getMessage());
        throw new KeyStoreException(msg.toString());
      }
    }
    /**
     * Generate a certificate request. Note that this methods checks if the
     * certificate request generation is allowed and throws an exception if it
     * isn't supported. Some vendors JDKs aren't compatible with Sun's
     * certificate request generation classes so they aren't supported.
     *
     * @param ks
     *          The keystore to use in the request creation.
     * @param ksType
     *          The keystore type.
     * @param ksPath
     *          The path to the keystore.
     * @param alias
     *          The alias to use in the request generation.
     * @param pwd
     *          The keystore password to use.
     * @param dn
     *          A dn string to use as the certificate subject.
     * @return A file object pointing at the created certificate request.
     * @throws KeyStoreException
     *           If the certificate request failed.
     */
    public final File generateCertificateRequest(final KeyStore ks,
        final String ksType, final String ksPath, final String alias,
        final char[] pwd, final String dn) throws KeyStoreException
    {
      if (!certReqAllowed)
      {
        final String vendor = System.getProperty("java.vendor");
        final LocalizableMessage msg = ERR_CERTMGR_CERT_SIGN_REQ_NOT_SUPPORTED
            .get(vendor);
        throw new KeyStoreException(msg.toString());
      }
      final KeyStore keyStore = generateSelfSignedCertificate(ks, ksType,
          ksPath, alias, pwd, dn, DEFAULT_VALIDITY);
      File csrFile;
      try
      {
        csrFile = File.createTempFile(TMPFILE_PREFIX, TMPFILE_EXT);
        csrFile.deleteOnExit();
        final PrintStream printStream = new PrintStream(new FileOutputStream(
            csrFile.getAbsolutePath()));
        if (keyStore == null)
        {
          final LocalizableMessage msg = ERR_CERTMGR_KEYSTORE_NONEXISTANT.get();
          throw new KeyStoreException(msg.toString());
        }
        final PrivateKey privateKey = getPrivateKey(keyStore, alias, pwd);
        if (privateKey == null)
        {
          final LocalizableMessage msg = ERR_CERTMGR_PRIVATE_KEY.get(alias);
          throw new KeyStoreException(msg.toString());
        }
        final Certificate cert = keyStore.getCertificate(alias);
        if (cert == null)
        {
          final LocalizableMessage msg = ERR_CERTMGR_ALIAS_NO_CERTIFICATE
              .get(alias);
          throw new KeyStoreException(msg.toString());
        }
        final Signature signature = Signature.getInstance(SIG_ALGORITHM);
        signature.initSign(privateKey);
        final Object request = pkcs10Cons.newInstance(cert.getPublicKey());
        final Object subject = x500NameCons.newInstance(dn);
        final Object signer = x500SignerCons.newInstance(signature, subject);
        final Method encodeAndSign = pkcs10Class.getMethod(ENCODE_SIGN_METHOD,
            x500SignerClass);
        final Method print = pkcs10Class.getMethod(PRINT_METHOD,
            PrintStream.class);
        encodeAndSign.invoke(request, signer);
        print.invoke(request, printStream);
        printStream.close();
      }
      catch (final Exception e)
      {
        final LocalizableMessage msg = ERR_CERTMGR_CERT_REQUEST.get(alias, e
            .getMessage());
        throw new KeyStoreException(msg.toString());
      }
      return csrFile;
    }
    /**
     * Generate a self-signed certificate using the specified alias, dn string
     * and validity period. If the keystore does not exist, create it using the
     * specified type and path.
     *
     * @param ks
     *          The keystore to save the certificate in. May be null if it does
     *          not exist.
     * @param ksType
     *          The keystore type to use if the keystore is created.
     * @param ksPath
     *          The path to the keystore if the keystore is created.
     * @param alias
     *          The alias to store the certificate under.
     * @param pwd
     *          The password to us in saving the certificate.
     * @param dn
     *          The dn string used as the certificate subject.
     * @param validity
     *          The validity of the certificate in days.
     * @return The keystore that the self-signed certificate was stored in.
     * @throws KeyStoreException
     *           If the self-signed certificate cannot be generated.
     */
    public final KeyStore generateSelfSignedCertificate(KeyStore ks,
        final String ksType, final String ksPath, final String alias,
        final char[] pwd, final String dn, final int validity)
        throws KeyStoreException
    {
      try
      {
        if (ks == null)
        {
          ks = KeyStore.getInstance(ksType);
          ks.load(null, pwd);
        }
        else if (ks.containsAlias(alias))
        {
          final LocalizableMessage msg = ERR_CERTMGR_ALIAS_ALREADY_EXISTS
              .get(alias);
          throw new KeyStoreException(msg.toString());
        }
        final Object keypair = certKeyGenCons.newInstance(KEY_ALGORITHM,
            SIG_ALGORITHM);
        final Object subject = x500NameCons.newInstance(dn);
        final Method certAndKeyGenGenerate = certKeyGenClass.getMethod(
            GENERATE_METHOD, int.class);
        certAndKeyGenGenerate.invoke(keypair, KEY_SIZE);
        final Method certAndKeyGetPrivateKey = certKeyGenClass
            .getMethod(GET_PRIVATE_KEY_METHOD);
        final PrivateKey privatevKey = (PrivateKey) certAndKeyGetPrivateKey
            .invoke(keypair);
        final Certificate[] certificateChain = new Certificate[1];
        final Method getSelfCertificate = certKeyGenClass.getMethod(
            GET_SELFSIGNED_CERT_METHOD, x500NameClass, long.class);
        final int days = validity * SEC_IN_DAY;
        certificateChain[0] = (Certificate) getSelfCertificate.invoke(keypair,
            subject, days);
        ks.setKeyEntry(alias, privatevKey, pwd, certificateChain);
        final FileOutputStream fileOutStream = new FileOutputStream(ksPath);
        ks.store(fileOutStream, pwd);
        fileOutStream.close();
      }
      catch (final Exception e)
      {
        final LocalizableMessage msg = ERR_CERTMGR_GEN_SELF_SIGNED_CERT.get(
            alias, e.getMessage());
        throw new KeyStoreException(msg.toString());
      }
      return ks;
    }
    /**
     * Normalize the data in the specified buffer.
     *
     * @param buffer
     *          The buffer to normalize.
     */
    public abstract void normalize(StringBuilder buffer);
    /**
     * Returns the private key associated with specified alias and keystore. The
     * keystore was already checked for existance.
     *
     * @param ks
     *          The keystore to get the private key from, it must exist.
     * @param alias
     *          The alias to get the private key of.
     * @param pwd
     *          The password used to get the key from the keystore.
     * @return The private key of related to the alias.
     * @throws KeyStoreException
     *           If the alias is not in the keystore, the entry related to the
     *           alias is not of
     */
    private PrivateKey getPrivateKey(final KeyStore ks, final String alias,
        final char[] pwd) throws KeyStoreException
    {
      PrivateKey key = null;
      try
      {
        if (!ks.containsAlias(alias))
        {
          final LocalizableMessage msg = ERR_CERTMGR_ALIAS_DOES_NOT_EXIST
              .get(alias);
          throw new KeyStoreException(msg.toString());
        }
        if (!ks.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)
            && !ks.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class))
        {
          final LocalizableMessage msg = ERR_CERTMGR_ALIAS_INVALID_ENTRY_TYPE
              .get(alias);
          throw new KeyStoreException(msg.toString());
        }
        key = (PrivateKey) ks.getKey(alias, pwd);
      }
      catch (final Exception e)
      {
        final LocalizableMessage msg = ERR_CERTMGR_GET_KEY.get(alias, e
            .getMessage());
        throw new KeyStoreException(msg.toString());
      }
      return key;
    }
    /**
     * Check that the issuer and subject DNs match.
     *
     * @param cert
     *          The certificate to examine.
     * @return {@code true} if the certificate is self-signed.
     */
    private boolean isSelfSigned(final X509Certificate cert)
    {
      return cert.getSubjectDN().equals(cert.getIssuerDN());
    }
    /**
     * Generate a x509 certificate from the input stream. Verification is done
     * only if it is self-signed.
     *
     * @param alias
     *          The alias to save the certificate under.
     * @param cf
     *          The x509 certificate factory.
     * @param ks
     *          The keystore to add the certificate in.
     * @param in
     *          The input stream to read the certificate from.
     * @throws KeyStoreException
     *           If the alias exists already in the keystore, if the self-signed
     *           certificate didn't verify, or the certificate could not be
     *           stored.
     */
    private void trustedCert(final String alias, final CertificateFactory cf,
        final KeyStore ks, final InputStream in) throws KeyStoreException
    {
      try
      {
        if (ks.containsAlias(alias) == true)
        {
          final LocalizableMessage msg = ERR_CERTMGR_ALIAS_ALREADY_EXISTS
              .get(alias);
          throw new KeyStoreException(msg.toString());
        }
        final X509Certificate cert = (X509Certificate) cf
            .generateCertificate(in);
        if (isSelfSigned(cert))
        {
          cert.verify(cert.getPublicKey());
        }
        ks.setCertificateEntry(alias, cert);
      }
      catch (final Exception e)
      {
        final LocalizableMessage msg = ERR_CERTMGR_TRUSTED_CERT.get(alias, e
            .getMessage());
        throw new KeyStoreException(msg.toString());
      }
    }
  }
  /**
   * Sun 5 JDK platform class.
   */
  private static class Sun5PlatformIMPL extends PlatformIMPL
  {
    // normalize method.
    private static final Method NORMALIZE;
    // Normalized form method.
    private static final Object FORM_NFKC;
    static
    {
      Method normalize = null;
      Object formNFKC = null;
      try
      {
        final Class<?> normalizer = Class.forName("sun.text.Normalizer");
        formNFKC = normalizer.getField("DECOMP_COMPAT").get(null);
        final Class<?> normalizerForm = Class
            .forName("sun.text.Normalizer$Mode");
        normalize = normalizer.getMethod("normalize", String.class,
            normalizerForm, Integer.TYPE);
      }
      catch (final Exception ex)
      {
        // Do not use Normalizer. The values are already set to null.
      }
      NORMALIZE = normalize;
      FORM_NFKC = formNFKC;
    }
    @Override
    public void normalize(final StringBuilder buffer)
    {
      try
      {
        final String normal = (String) NORMALIZE.invoke(null,
            buffer.toString(), FORM_NFKC, 0);
        buffer.replace(0, buffer.length(), normal);
      }
      catch (final Exception ex)
      {
        // Don't do anything. buffer should be used.
      }
    }
  }
  // Prefix that determines which security package to use.
  private static String pkgPrefix;
  // IBM security package doesn't appear to support PCKS10, this flags turns
  // off support for that.
  private static boolean certReqAllowed;
  // The two security package prefixes (IBM and SUN).
  private static final String IBM_SEC = "com.ibm.security";
  private static final String SUN_SEC = "sun.security";
  private static final PlatformIMPL IMPL;
  static
  {
    final String vendor = System.getProperty("java.vendor");
    final String ver = System.getProperty("java.version");
    if (vendor.startsWith("IBM"))
    {
      pkgPrefix = IBM_SEC;
      certReqAllowed = false;
      if (ver.startsWith("1.5"))
      {
        IMPL = new IBM5PlatformIMPL();
      }
      else
      {
        pkgPrefix = SUN_SEC;
        certReqAllowed = true;
        if(ver.startsWith("1.5"))
        {
         IMPL = new Sun5PlatformIMPL();
        }
        else
        {
          IMPL = new DefaultPlatformIMPL();
        }
        IMPL = new DefaultPlatformIMPL();
      }
    }
   /**
    * Platform base class. Performs all of the certificate management functions.
    */
    private abstract static class PlatformIMPL {
        //Key size, key algorithm and signature algorithms used.
        private static final  int KEY_SIZE = 1024;
        private static final String KEY_ALGORITHM = "rsa";
        private static final String SIG_ALGORITHM = "SHA1WithRSA";
        //Time values used in validity calculations.
        private static final int SEC_IN_DAY = 24 * 60 * 60;
        private static final int DEFAULT_VALIDITY = 90 * SEC_IN_DAY;
        //These two are used to build certificate request files.
        private static final String TMPFILE_PREFIX = "CertificateManager-";
        private static final String TMPFILE_EXT = ".csr";
        //Methods pulled from the classes.
        private static final String ENCODE_SIGN_METHOD = "encodeAndSign";
        private static final String GENERATE_METHOD = "generate";
        private static final String GET_PRIVATE_KEY_METHOD = "getPrivateKey";
        private static final String GET_SELFSIGNED_CERT_METHOD =
                                                          "getSelfCertificate";
        private static final String PRINT_METHOD = "print";
        //Classes needed to manage certificates.
        private static Class<?> certKeyGenClass, X500NameClass,
                                X500SignerClass, PKCS10Class;
        //Constructors for each of the above classes.
        private static Constructor<?> certKeyGenCons, X500NameCons,
                                      X500SignerCons, pkcs10Cons;
        static {
          String x509pkg = pkgPrefix + ".x509";
          String pkcs10Pkg = pkgPrefix + ".pkcs";
          String certAndKeyGen=  x509pkg + ".CertAndKeyGen";
          String X500Name =  x509pkg + ".X500Name";
          String X500Signer = x509pkg + ".X500Signer";
          try {
            certKeyGenClass = Class.forName(certAndKeyGen);
            X500NameClass = Class.forName(X500Name);
            X500SignerClass = Class.forName(X500Signer);
            if(certReqAllowed) {
              String pkcs10 = pkcs10Pkg + ".PKCS10";
              PKCS10Class = Class.forName(pkcs10);
              pkcs10Cons = PKCS10Class.getConstructor(PublicKey.class);
            }
            certKeyGenCons =
                    certKeyGenClass.getConstructor(String.class, String.class);
            X500NameCons = X500NameClass.getConstructor(String.class);
            X500SignerCons =
                 X500SignerClass.getConstructor(Signature.class, X500NameClass);
          } catch (ClassNotFoundException e) {
            LocalizableMessage msg = ERR_CERTMGR_CLASS_NOT_FOUND.get(e.getMessage());
            throw new ExceptionInInitializerError(msg.toString());
          } catch (SecurityException e) {
            LocalizableMessage msg = ERR_CERTMGR_SECURITY.get(e.getMessage());
            throw new ExceptionInInitializerError(msg.toString());
          } catch (NoSuchMethodException e) {
            LocalizableMessage msg = ERR_CERTMGR_NO_METHOD.get(e.getMessage());
            throw new ExceptionInInitializerError(msg.toString());
          }
        }
        protected PlatformIMPL() {}
        /**
         * Generate a certificate request. Note that this methods checks if
         * the certificate request generation is allowed and throws an
         * exception if it isn't supported. Some vendors JDKs aren't compatible
         * with Sun's certificate request generation classes so they aren't
         * supported.
         *
         * @param ks The keystore to use in the request creation.
         * @param ksType The keystore type.
         * @param ksPath The path to the keystore.
         * @param alias The alias to use in the request generation.
         * @param pwd The keystore password to use.
         * @param dn A dn string to use as the certificate subject.
         *
         * @return A file object pointing at the created certificate request.
         * @throws KeyStoreException If the certificate request failed.
         */
        public final File
        generateCertificateRequest(KeyStore ks, String ksType, String ksPath,
            String alias, char[] pwd, String dn) throws KeyStoreException {
          if(!certReqAllowed) {
            String vendor = System.getProperty("java.vendor");
            LocalizableMessage msg =
              ERR_CERTMGR_CERT_SIGN_REQ_NOT_SUPPORTED.get(vendor);
            throw new KeyStoreException(msg.toString());
          }
          KeyStore keyStore = generateSelfSignedCertificate(ks, ksType, ksPath,
                                            alias, pwd, dn, DEFAULT_VALIDITY);
          File csrFile;
          try {
            csrFile = File.createTempFile(TMPFILE_PREFIX, TMPFILE_EXT);
            csrFile.deleteOnExit();
            PrintStream printStream =
              new PrintStream(new FileOutputStream(csrFile.getAbsolutePath()));
            if(keyStore == null) {
              LocalizableMessage msg = ERR_CERTMGR_KEYSTORE_NONEXISTANT.get();
              throw new KeyStoreException(msg.toString());
            }
            PrivateKey privateKey = getPrivateKey(keyStore, alias, pwd);
            if(privateKey == null) {
              LocalizableMessage msg =  ERR_CERTMGR_PRIVATE_KEY.get(alias);
              throw new KeyStoreException(msg.toString());
            }
            Certificate cert = keyStore.getCertificate(alias);
            if(cert == null) {
              LocalizableMessage msg = ERR_CERTMGR_ALIAS_NO_CERTIFICATE.get(alias);
              throw new KeyStoreException(msg.toString());
            }
            Signature signature = Signature.getInstance(SIG_ALGORITHM);
            signature.initSign(privateKey);
            Object request = pkcs10Cons.newInstance(cert.getPublicKey());
            Object subject = X500NameCons.newInstance(dn);
            Object signer =
              X500SignerCons.newInstance(signature, subject);
            Method encodeAndSign =
              PKCS10Class.getMethod(ENCODE_SIGN_METHOD, X500SignerClass);
            Method print =
              PKCS10Class.getMethod(PRINT_METHOD, PrintStream.class);
            encodeAndSign.invoke(request, signer);
            print.invoke(request, printStream);
            printStream.close();
          } catch (Exception e) {
            LocalizableMessage msg = ERR_CERTMGR_CERT_REQUEST.get(alias,e.getMessage());
            throw new KeyStoreException(msg.toString());
          }
          return csrFile;
        }
        /**
         * Delete the specified alias from the specified keystore.
         *
         * @param ks The keystore to delete the alias from.
         * @param ksPath The path to the keystore.
         * @param alias The alias to use in the request generation.
         * @param pwd The keystore password to use.
         *
         * @throws KeyStoreException If an error occurred deleting the alias.
         */
        public final void deleteAlias(KeyStore ks, String ksPath,
            String alias, char[] pwd) throws KeyStoreException {
              try {
                  if(ks == null) {
                      LocalizableMessage msg = ERR_CERTMGR_KEYSTORE_NONEXISTANT.get();
                      throw new KeyStoreException(msg.toString());
                  }
                  ks.deleteEntry(alias);
                  FileOutputStream fs = new FileOutputStream(ksPath);
                  ks.store(fs, pwd);
                  fs.close();
              } catch (Exception e) {
                  LocalizableMessage msg =
                      ERR_CERTMGR_DELETE_ALIAS.get(alias,e.getMessage());
                  throw new KeyStoreException(msg.toString());
              }
        }
        /**
         * Add the certificate in the specified path to the specified keystore,
         * creating the keystore using the specified type and path if it the
         * keystore doesn't exist.
         *
         * @param ks The keystore to add the certificate to, may be null if it
         *           doesn't exist.
         * @param ksType The type to use if the keystore is created.
         * @param ksPath The path to the keystore if it is created.
         * @param alias The alias to store the certificate under.
         * @param pwd The password to use in saving the certificate.
         * @param certPath The path to the file containing the certificate.
         * @throws KeyStoreException If an error occurred adding the
         *                           certificate to the keystore.
         */
        public final void addCertificate(KeyStore ks, String ksType,
            String ksPath, String alias, char[] pwd, String certPath)
        throws KeyStoreException {
          try {
            CertificateFactory cf = CertificateFactory.getInstance("X509");
            InputStream inStream = new FileInputStream(certPath);
            if(ks == null) {
              ks = KeyStore.getInstance(ksType);
              ks.load(null, pwd);
            }
            //Do not support certificate replies.
            if (ks.entryInstanceOf(alias ,KeyStore.PrivateKeyEntry.class)) {
              LocalizableMessage msg = ERR_CERTMGR_CERT_REPLIES_INVALID.get(alias);
              throw new KeyStoreException(msg.toString());
            } else if(!ks.containsAlias(alias) ||
                ks.entryInstanceOf(alias,
                    KeyStore.TrustedCertificateEntry.class))
              trustedCert(alias, cf, ks, inStream);
            else {
              LocalizableMessage msg = ERR_CERTMGR_ALIAS_INVALID.get(alias);
              throw new KeyStoreException(msg.toString());
            }
            FileOutputStream fileOutStream = new FileOutputStream(ksPath);
            ks.store(fileOutStream, pwd);
            fileOutStream.close();
            inStream.close();
          } catch (Exception e) {
            LocalizableMessage msg =
              ERR_CERTMGR_ADD_CERT.get(alias, e.getMessage());
            throw new KeyStoreException(msg.toString());
          }
        }
        /**
         * Generate a self-signed certificate using the specified alias, dn
         * string and validity period. If the keystore does not exist, create it
         * using the specified type and path.
         *
         * @param ks The keystore to save the certificate in. May be null if it
         *           does not exist.
         * @param ksType The keystore type to use if the keystore is created.
         * @param ksPath The path to the keystore if the keystore is created.
         * @param alias The alias to store the certificate under.
         * @param pwd The password to us in saving the certificate.
         * @param dn The dn string used as the certificate subject.
         * @param validity The validity of the certificate in days.
         * @return The keystore that the self-signed certificate was stored in.
         *
         * @throws KeyStoreException If the self-signed certificate cannot be
         *                           generated.
         */
        public final
        KeyStore generateSelfSignedCertificate(KeyStore ks, String ksType,
            String ksPath, String alias, char[] pwd, String dn, int validity)
        throws KeyStoreException {
          try {
            if(ks == null) {
              ks = KeyStore.getInstance(ksType);
              ks.load(null, pwd);
            } else if(ks.containsAlias(alias)) {
              LocalizableMessage msg = ERR_CERTMGR_ALIAS_ALREADY_EXISTS.get(alias);
              throw new KeyStoreException(msg.toString());
            }
            Object keypair =
              certKeyGenCons.newInstance(KEY_ALGORITHM, SIG_ALGORITHM);
            Object subject = X500NameCons.newInstance(dn);
            Method certAndKeyGenGenerate =
              certKeyGenClass.getMethod(GENERATE_METHOD, int.class);
            certAndKeyGenGenerate.invoke(keypair, KEY_SIZE);
            Method certAndKeyGetPrivateKey =
              certKeyGenClass.getMethod(GET_PRIVATE_KEY_METHOD);
            PrivateKey privatevKey =
              (PrivateKey) certAndKeyGetPrivateKey.invoke(keypair);
            Certificate[] certificateChain = new Certificate[1];
            Method getSelfCertificate =
              certKeyGenClass.getMethod(GET_SELFSIGNED_CERT_METHOD,
                                        X500NameClass,long.class);
            int days = validity * SEC_IN_DAY;
            certificateChain[0] =
              (Certificate) getSelfCertificate.invoke(keypair, subject, days);
            ks.setKeyEntry(alias, privatevKey, pwd, certificateChain);
            FileOutputStream fileOutStream = new FileOutputStream(ksPath);
            ks.store(fileOutStream, pwd);
            fileOutStream.close();
          } catch (Exception e) {
            LocalizableMessage msg =
                   ERR_CERTMGR_GEN_SELF_SIGNED_CERT.get(alias, e.getMessage());
            throw new KeyStoreException(msg.toString());
          }
          return ks;
        }
        /**
         * Generate a x509 certificate from the input stream. Verification is
         * done only if it is self-signed.
         *
         * @param alias The alias to save the certificate under.
         * @param cf The x509 certificate factory.
         * @param ks The keystore to add the certificate in.
         * @param in The input stream to read the certificate from.
         * @throws KeyStoreException If the alias exists already in the
         *         keystore, if the self-signed certificate didn't verify, or
         *         the certificate could not be stored.
         */
        private void trustedCert(String alias, CertificateFactory cf,
             KeyStore ks, InputStream in) throws KeyStoreException {
          try {
            if (ks.containsAlias(alias) == true) {
              LocalizableMessage msg = ERR_CERTMGR_ALIAS_ALREADY_EXISTS.get(alias);
              throw new KeyStoreException(msg.toString());
            }
            X509Certificate cert = (X509Certificate) cf.generateCertificate(in);
            if (isSelfSigned(cert))
              cert.verify(cert.getPublicKey());
            ks.setCertificateEntry(alias, cert);
          } catch (Exception e) {
            LocalizableMessage msg =
              ERR_CERTMGR_TRUSTED_CERT.get(alias,e.getMessage());
            throw new KeyStoreException(msg.toString());
          }
        }
        /**
         * Check that the issuer and subject DNs match.
         *
         * @param cert The certificate to examine.
         * @return {@code true} if the certificate is self-signed.
         */
        private boolean isSelfSigned(X509Certificate cert) {
          return cert.getSubjectDN().equals(cert.getIssuerDN());
        }
        /**
         * Returns the private key associated with specified alias and keystore.
         * The keystore was already checked for existance.
         *
         * @param ks The keystore to get the private key from, it must exist.
         * @param alias The alias to get the private key of.
         * @param pwd The password used to get the key from the keystore.
         * @return The private key of related to the alias.
         *
         * @throws KeyStoreException If the alias is not in the keystore, the
         *    entry related to the alias is not of
         */
        private PrivateKey getPrivateKey(KeyStore ks, String alias, char[] pwd)
        throws KeyStoreException  {
            PrivateKey key = null;
            try {
                if(!ks.containsAlias(alias)) {
                    LocalizableMessage msg = ERR_CERTMGR_ALIAS_DOES_NOT_EXIST.get(alias);
                    throw new KeyStoreException(msg.toString());
                }
                if(!ks.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class) &&
                  !ks.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) {
                    LocalizableMessage msg =
                                ERR_CERTMGR_ALIAS_INVALID_ENTRY_TYPE.get(alias);
                    throw new KeyStoreException(msg.toString());
                }
                key = (PrivateKey)ks.getKey(alias, pwd);
            } catch (Exception  e) {
                LocalizableMessage msg =
                    ERR_CERTMGR_GET_KEY.get(alias,e.getMessage());
                throw new KeyStoreException(msg.toString());
            }
            return key;
        }
        /**
         * Normalize the data in the specified buffer.
         *
         * @param buffer The buffer to normalize.
         */
         public abstract void normalize(StringBuilder buffer);
    }
    //Prevent instantiation.
    private Platform() {}
    /**
     * Add the certificate in the specified path to the provided keystore;
     * creating the keystore with the provided type and path if it doesn't
     * exist.
     *
     * @param ks The keystore to add the certificate to, may be null if it
     *           doesn't exist.
     * @param ksType The type to use if the keystore is created.
     * @param ksPath The path to the keystore if it is created.
     * @param alias The alias to store the certificate under.
     * @param pwd The password to use in saving the certificate.
     * @param certPath The path to the file containing the certificate.
     *
     * @throws KeyStoreException If an error occurred adding the
     *                           certificate to the keystore.
     */
    public static void addCertificate(KeyStore ks, String ksType, String ksPath,
        String alias, char[] pwd, String certPath) throws KeyStoreException {
        IMPL.addCertificate(ks,ksType, ksPath, alias, pwd, certPath);
    }
    /**
     * Delete the specified alias from the provided keystore.
     *
     * @param ks The keystore to delete the alias from.
     * @param ksPath The path to the keystore.
     * @param alias The alias to use in the request generation.
     * @param pwd The keystore password to use.
     *
     * @throws KeyStoreException If an error occurred deleting the alias.
     */
    public static void deleteAlias(KeyStore ks, String ksPath, String alias,
        char[] pwd) throws KeyStoreException {
        IMPL.deleteAlias(ks, ksPath, alias, pwd);
    }
    /**
     * Generate a certificate request using the specified parameters.
     *
     * @param ks The keystore to use in the request creation.
     * @param ksType The keystore type.
     * @param ksPath The path to the keystore.
     * @param alias The alias to use in the request generation.
     * @param pwd The keystore password to use.
     * @param dn A dn string to use as the certificate subject.
     * @return A file object pointing at the created certificate request.
     *
     * @throws KeyStoreException If the certificate request failed.
     */
    public static File generateCertificateRequest(KeyStore ks, String ksType,
        String ksPath, String alias, char[] pwd, String dn)
    throws KeyStoreException {
        return IMPL.generateCertificateRequest(ks, ksType, ksPath, alias,
                                               pwd, dn);
    }
    /**
     * Generate a self-signed certificate using the specified alias, dn
     * string and validity period. If the keystore does not exist, it will be
     * created using the specified keystore type and path.
     *
     * @param ks The keystore to save the certificate in. May be null if it
     *           does not exist.
     * @param ksType The keystore type to use if the keystore is created.
     * @param ksPath The path to the keystore if the keystore is created.
     * @param alias The alias to store the certificate under.
     * @param pwd The password to us in saving the certificate.
     * @param dn The dn string used as the certificate subject.
     * @param validity The validity of the certificate in days.
     *
     * @throws KeyStoreException If the self-signed certificate cannot be
     *                           generated.
     */
    public static void generateSelfSignedCertificate(KeyStore ks, String ksType,
        String ksPath, String alias, char[] pwd, String dn, int validity)
    throws KeyStoreException {
        IMPL.generateSelfSignedCertificate(ks, ksType, ksPath, alias, pwd, dn,
                                      validity);
    }
    /**
     * Sun 5 JDK platform class.
     */
    private static class Sun5PlatformIMPL extends PlatformIMPL {
       //normalize method.
      private static final Method NORMALIZE;
      //Normalized form method.
      private static final Object FORM_NFKC;
      static {
        Method normalize = null;
        Object formNFKC = null;
        try {
          Class<?> normalizer = Class.forName("sun.text.Normalizer");
          formNFKC = normalizer.getField("DECOMP_COMPAT").get(null);
          Class<?> normalizerForm = Class.forName("sun.text.Normalizer$Mode");
          normalize = normalizer.getMethod("normalize", String.class,
                 normalizerForm, Integer.TYPE);
        }
        catch (Exception ex) {
        // Do not use Normalizer. The values are already set to null.
        }
      NORMALIZE = normalize;
      FORM_NFKC = formNFKC;
     }
      @Override
      public void normalize(StringBuilder buffer) {
        try {
          String normal =
               (String) NORMALIZE.invoke(null, buffer.toString(), FORM_NFKC,0);
          buffer.replace(0,buffer.length(),normal);
        }
        catch(Exception ex) {
          //Don't do anything. buffer should be used.
        }
    else
    {
      pkgPrefix = SUN_SEC;
      certReqAllowed = true;
      if (ver.startsWith("1.5"))
      {
        IMPL = new Sun5PlatformIMPL();
      }
   }
    /**
     * Default platform class.
     */
     private static class DefaultPlatformIMPL extends PlatformIMPL {
       //normalize method.
      private static final Method NORMALIZE;
      //Normalized form method.
      private static final Object FORM_NFKC;
      static {
        Method normalize = null;
        Object formNFKC = null;
        try {
          Class<?> normalizer = Class.forName("java.text.Normalizer");
          Class<?> normalizerForm = Class.forName("java.text.Normalizer$Form");
          normalize = normalizer.getMethod("normalize", CharSequence.class,
                normalizerForm);
          formNFKC = normalizerForm.getField("NFKD").get(null);
        }
        catch (Exception ex) {
        // Do not use Normalizer. The values are already set to null.
        }
        NORMALIZE = normalize;
        FORM_NFKC = formNFKC;
     }
      @Override
      public void normalize(StringBuilder buffer) {
        try {
          String normal = (String) NORMALIZE.invoke(null, buffer, FORM_NFKC);
          buffer.replace(0,buffer.length(),normal);
        }
        catch(Exception ex) {
          //Don't do anything. buffer should be used.
        }
      else
      {
        IMPL = new DefaultPlatformIMPL();
      }
   }
   /**
    * IBM JDK 5 platform class.
    */
   private static class IBM5PlatformIMPL extends PlatformIMPL {
    @Override
    public void normalize(StringBuilder buffer) {
      //No implementation.
    }
   }
  }
   /**
    * Normalize the specified buffer.
    *
    * @param buffer The buffer to normalize.
    */
   public static void normalize(StringBuilder buffer) {
     IMPL.normalize(buffer);
   }
   /**
    * Test if a platform java vendor property starts with the specified
    * vendor string.
    *
    * @param vendor The vendor to check for.
    * @return {@code true} if the java vendor starts with the specified vendor
    *         string.
    */
   public static boolean isVendor(String vendor) {
     String javaVendor = System.getProperty("java.vendor");
     return javaVendor.startsWith(vendor);
   }
  /**
   * Add the certificate in the specified path to the provided keystore;
   * creating the keystore with the provided type and path if it doesn't exist.
   *
   * @param ks
   *          The keystore to add the certificate to, may be null if it doesn't
   *          exist.
   * @param ksType
   *          The type to use if the keystore is created.
   * @param ksPath
   *          The path to the keystore if it is created.
   * @param alias
   *          The alias to store the certificate under.
   * @param pwd
   *          The password to use in saving the certificate.
   * @param certPath
   *          The path to the file containing the certificate.
   * @throws KeyStoreException
   *           If an error occurred adding the certificate to the keystore.
   */
  public static void addCertificate(final KeyStore ks, final String ksType,
      final String ksPath, final String alias, final char[] pwd,
      final String certPath) throws KeyStoreException
  {
    IMPL.addCertificate(ks, ksType, ksPath, alias, pwd, certPath);
  }
  /**
   * Delete the specified alias from the provided keystore.
   *
   * @param ks
   *          The keystore to delete the alias from.
   * @param ksPath
   *          The path to the keystore.
   * @param alias
   *          The alias to use in the request generation.
   * @param pwd
   *          The keystore password to use.
   * @throws KeyStoreException
   *           If an error occurred deleting the alias.
   */
  public static void deleteAlias(final KeyStore ks, final String ksPath,
      final String alias, final char[] pwd) throws KeyStoreException
  {
    IMPL.deleteAlias(ks, ksPath, alias, pwd);
  }
  /**
   * Generate a certificate request using the specified parameters.
   *
   * @param ks
   *          The keystore to use in the request creation.
   * @param ksType
   *          The keystore type.
   * @param ksPath
   *          The path to the keystore.
   * @param alias
   *          The alias to use in the request generation.
   * @param pwd
   *          The keystore password to use.
   * @param dn
   *          A dn string to use as the certificate subject.
   * @return A file object pointing at the created certificate request.
   * @throws KeyStoreException
   *           If the certificate request failed.
   */
  public static File generateCertificateRequest(final KeyStore ks,
      final String ksType, final String ksPath, final String alias,
      final char[] pwd, final String dn) throws KeyStoreException
  {
    return IMPL.generateCertificateRequest(ks, ksType, ksPath, alias, pwd, dn);
  }
  /**
   * Generate a self-signed certificate using the specified alias, dn string and
   * validity period. If the keystore does not exist, it will be created using
   * the specified keystore type and path.
   *
   * @param ks
   *          The keystore to save the certificate in. May be null if it does
   *          not exist.
   * @param ksType
   *          The keystore type to use if the keystore is created.
   * @param ksPath
   *          The path to the keystore if the keystore is created.
   * @param alias
   *          The alias to store the certificate under.
   * @param pwd
   *          The password to us in saving the certificate.
   * @param dn
   *          The dn string used as the certificate subject.
   * @param validity
   *          The validity of the certificate in days.
   * @throws KeyStoreException
   *           If the self-signed certificate cannot be generated.
   */
  public static void generateSelfSignedCertificate(final KeyStore ks,
      final String ksType, final String ksPath, final String alias,
      final char[] pwd, final String dn, final int validity)
      throws KeyStoreException
  {
    IMPL.generateSelfSignedCertificate(ks, ksType, ksPath, alias, pwd, dn,
        validity);
  }
  /**
   * Test if a platform java vendor property starts with the specified vendor
   * string.
   *
   * @param vendor
   *          The vendor to check for.
   * @return {@code true} if the java vendor starts with the specified vendor
   *         string.
   */
  public static boolean isVendor(final String vendor)
  {
    final String javaVendor = System.getProperty("java.vendor");
    return javaVendor.startsWith(vendor);
  }
  /**
   * Normalize the specified buffer.
   *
   * @param buffer
   *          The buffer to normalize.
   */
  public static void normalize(final StringBuilder buffer)
  {
    IMPL.normalize(buffer);
  }
  // Prevent instantiation.
  private Platform()
  {
  }
}