// Copyright (C) 1997-2002 IAIK
// email: jce-info@iaik.tu-graz.ac.at
// 
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// $Header$
//

package testgenerator;

import iaik.asn1.CodingException;
import iaik.asn1.ObjectID;
import iaik.asn1.structures.AlgorithmID;
import iaik.asn1.structures.GeneralName;
import iaik.asn1.structures.GeneralNames;
import iaik.asn1.structures.Name;
import iaik.asn1.structures.PolicyInformation;
import iaik.asn1.structures.PolicyQualifierInfo;
import iaik.security.provider.IAIK;
import iaik.x509.SimpleChainVerifier;
import iaik.x509.X509Certificate;
import iaik.x509.X509ExtensionException;
import iaik.x509.extensions.AuthorityKeyIdentifier;
import iaik.x509.extensions.BasicConstraints;
import iaik.x509.extensions.CertificatePolicies;
import iaik.x509.extensions.KeyUsage;
import iaik.x509.extensions.SubjectAltName;
import iaik.x509.extensions.SubjectKeyIdentifier;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Random;

/**
 * Creates a default KeyStore in the current working directory.
 * These keys are used by many demos included in IAIK-JCE.
 * The aliases and the password for accessing the keys and
 * certificates can be found in {@link demo.keystore.CMSKeyStoreConstants CMSKeyStoreConstants}.
 *
 * @see CMSKeyStoreConstants
 */
public class SetupCMSKeyStore implements CMSKeyStoreConstants {

  // the keylength of the CA certificate shall be 1024
  private final static int CA_KEYLENGTH = 1024;

  // the key store to create
  KeyStore key_store;
  // the file where the key store shall be saved
  String keystore_file;
  // takes the existing keys from the KeyStore and only creates new certificates
  boolean create_only_certificates = true;

  // the private keys
  KeyPair ca_rsa = null;
  // RSA for signing
  KeyPair rsa512_sign = null;
  KeyPair rsa1024_sign = null;
  KeyPair rsa2048_sign = null;
  // RSA for encrypting
  KeyPair rsa512_crypt = null;
  KeyPair rsa1024_crypt = null;
  KeyPair rsa1024_crypt_ = null;
  KeyPair rsa2048_crypt = null;

  KeyPair ca_dsa = null;
  KeyPair dsa512 = null;
  KeyPair dsa1024 = null;
  KeyPair esdh512 = null;
  KeyPair esdh1024 = null;
  KeyPair esdh1024_ = null;
  KeyPair esdh2048 = null;

  // create RSA keys and certificates
  boolean create_rsa = true;
  // create DSA keys and certificates
  boolean create_dsa = true;
  // create ESDH keys and certificates
  boolean create_esdh = true;

  /**
   * Generate a KeyPair using the specified algorithm with the given size.
   *
   * @param algorithm the algorithm to use
   * @param bits the length of the key (modulus) in bits
   * @return the KeyPair
   */
	public static KeyPair generateKeyPair(String algorithm, int bits) 
	    throws NoSuchAlgorithmException {

		KeyPairGenerator generator = null;

		try {
		   generator = KeyPairGenerator.getInstance(algorithm, "IAIK"); 

		} catch (NoSuchProviderException ex) {
		  throw new NoSuchAlgorithmException("Provider IAIK not found!");
		}

		generator.initialize(bits);
		KeyPair kp = generator.generateKeyPair();

		return kp;
	}

  /**
   * Creates a certificate from the given values.
   *
   * @param subject the subject of the certificate
   * @param publicKey the public key to include
   * @param issuer the issuer of the certificate
   * @param privateKey the private key for signing the certificate
   * @param algorithm the signature algorithm to use
   */
  public static X509Certificate createCertificate(Name subject, PublicKey publicKey, 
      Name issuer, PrivateKey privateKey, AlgorithmID algorithm, byte[] keyID, boolean forSigning) {

    // create a new certificate
    X509Certificate cert = new X509Certificate();

    try {
      // set the values
      cert.setSerialNumber(new BigInteger(20, new Random()));
      cert.setSubjectDN(subject);
      cert.setPublicKey(publicKey);
      cert.setIssuerDN(issuer);

      GregorianCalendar date = new GregorianCalendar();
      date.add(Calendar.DATE, -1);
      // not before now
      cert.setValidNotBefore(date.getTime());

      if (issuer.equals(subject)) {
        date.add(Calendar.MONTH, 12); 
        BasicConstraints basicConstraints = new BasicConstraints(true);
        cert.addExtension(basicConstraints);
        KeyUsage keyUsage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign);
        cert.addExtension(keyUsage);
      } else { 
        date.add(Calendar.MONTH, 11);
        KeyUsage keyUsage = null;
        if (forSigning) {
          keyUsage = new KeyUsage(KeyUsage.digitalSignature |
                                  KeyUsage.nonRepudiation);
        } else {                           
          keyUsage = new KeyUsage(KeyUsage.keyEncipherment |
                                  KeyUsage.dataEncipherment);
        }                          
        cert.addExtension(keyUsage);
        AuthorityKeyIdentifier authID = new AuthorityKeyIdentifier();
        authID.setKeyIdentifier(keyID);
        cert.addExtension(authID);
        GeneralNames generalNames = new GeneralNames();
        generalNames.addName(new GeneralName(GeneralName.rfc822Name, "smimetest@iaik.at"));
        generalNames.addName(new GeneralName(GeneralName.rfc822Name, "smimetest@iaik.tu-graz.ac.at"));
        SubjectAltName subjectAltName = new SubjectAltName(generalNames);
        cert.addExtension(subjectAltName);
      }
      String explicitText = "This certificate only may be used for test purposes";
      PolicyQualifierInfo policyQualifier = new PolicyQualifierInfo(null, null, explicitText);
      PolicyInformation[] policyInformations = 
        { new PolicyInformation(new ObjectID("1.3.6.1.4.1.2706.17.0.11.1.1"),
                              new PolicyQualifierInfo[] { policyQualifier }) };
      CertificatePolicies certPolicies = new CertificatePolicies(policyInformations);                        
      
      SubjectKeyIdentifier subjectKeyID = new SubjectKeyIdentifier(cert.getPublicKey());
      cert.addExtension(subjectKeyID);
        
      cert.addExtension(certPolicies);                              
      cert.setValidNotAfter(date.getTime());
      // and sign the certificate
      cert.sign(algorithm ,privateKey);
    } catch (CertificateException ex) {
      throw new RuntimeException("Error creating the certificate: "+ex.getMessage());
    } catch (InvalidKeyException ex) {
      throw new RuntimeException("Error creating the certificate: "+ex.getMessage());
    } catch (NoSuchAlgorithmException ex) {
      throw new RuntimeException("Error creating the certificate: "+ex.getMessage());
    } catch (X509ExtensionException ex) {
      throw new RuntimeException("Error adding extension: "+ex.getMessage());   
    } catch (CodingException ex) {
      throw new RuntimeException("Error adding SubjectKeyIdentifier extension: "+ex.getMessage());   
    }     
/*
    System.out.println(cert.toString(true));
    iaik.utils.Util.waitKey();
*/    

    return cert;
  }

  /**
   * Load or create a KeyStore and initialize it.
   */
  private void initializeKeyStore() {

    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    String line;

    try {
      // default directory is the current user dir
      String keystore_dir = System.getProperty("user.dir");
      File ks = new File(keystore_dir, KS_FILENAME);

      // KeyStore does already exist
      if (ks.exists()) {
        keystore_file = ks.getAbsolutePath();
        if (create_only_certificates) {
          System.out.println("Create only new certificates from already existing keys!");
        }
        else {
          System.out.println("Existing KeyStore will be deleted!");
        }
        System.out.println("KeyStore: "+keystore_file);
      }
      else {
        // there is no KeyStore -> create also new keys
        create_only_certificates = false;
      
        while (true) {
          System.out.print("Create new KeyStore in directory: "+keystore_dir+" [y]");
          line = reader.readLine();
          if (line.length() == 0 || line.equals("y")) {
            ks = new File(keystore_dir, KS_FILENAME);
            keystore_file = ks.getAbsolutePath();
            System.out.println("KeyStore will be saved to: "+keystore_file);
            break;
          }
          System.out.print("Enter directory: ");
          keystore_dir = reader.readLine();
        }
      }
      
      // get a new KeyStore onject
      key_store = KeyStore.getInstance("IAIKKeyStore");
      
      if (create_only_certificates) {
        // take private keys from existing KeyStore
        key_store.load(new FileInputStream(ks), KS_PASSWORD);
      }
      else {
        // create a new KeyStore
        key_store.load(null, null);
      }
      
    } catch (Exception ex) {
      System.out.println("Error creating new IAIK KeyStore!");
      throw new RuntimeException("Error creating new KeyStore: "+ex.getMessage());
    }
  }

  /**
   * Save the KeyStore to disk.
   */
  private void saveKeyStore() {
    try {
      // write the KeyStore to disk
      FileOutputStream os = new FileOutputStream(keystore_file);
      key_store.store(os, KS_PASSWORD);
      os.close();
    } catch (Exception ex) {
      System.out.println("Error saving KeyStore!");
      ex.printStackTrace();
    }
  }

  /**
   * Add the private key and the certificate chain to the key store.
   */
  public void addToKeyStore(KeyPair keyPair, X509Certificate[] chain, String alias) throws KeyStoreException {
    key_store.setKeyEntry(alias, keyPair.getPrivate(), KS_PASSWORD, chain);
  }
  
  /**
   * Returns a KeyPair form the KeyStore.
   */
  private KeyPair getKeyPair(String type) throws Exception {
    PrivateKey privKey = (PrivateKey)key_store.getKey(type, KS_PASSWORD);
    PublicKey pubKey = key_store.getCertificateChain(type)[0].getPublicKey();
    return new KeyPair(pubKey, privKey);
  }

  /**
   * Get all private keys from the KeyStore.
   */
  private void getPrivateKeys() {
    // RSA    
    try {
      ca_rsa = getKeyPair(CA_RSA);
      // for signing
      rsa512_sign = getKeyPair(RSA_512_SIGN);
      rsa1024_sign = getKeyPair(RSA_1024_SIGN);
      rsa2048_sign = getKeyPair(RSA_2048_SIGN);
      // for encrypting
      rsa512_crypt = getKeyPair(RSA_512_CRYPT);
      rsa1024_crypt = getKeyPair(RSA_1024_CRYPT);
      rsa1024_crypt_ = getKeyPair(RSA_1024_CRYPT_);
      rsa2048_crypt = getKeyPair(RSA_2048_CRYPT);
    } catch (Exception ex) {
      System.out.println("Unable to get RSA keys from KeyStore.");
      ex.printStackTrace();
      create_rsa = false;
    }
    // DSA
    try {
      ca_dsa = getKeyPair(CA_DSA);
      dsa512 = getKeyPair(DSA_512);
      dsa1024 = getKeyPair(DSA_1024);
    } catch (Exception ex) {
      System.out.println("Unable to get DSA keys from KeyStore.");
      ex.printStackTrace();
      create_dsa = false;
    }
    // ESDH
    try {
      esdh512 = getKeyPair(ESDH_512);
      esdh1024 = getKeyPair(ESDH_1024);
      esdh1024_ = getKeyPair(ESDH_1024_);
      esdh2048 = getKeyPair(ESDH_2048);
    } catch (Exception ex) {
      System.out.println("Unable to get ESDH keys from KeyStore.");
      ex.printStackTrace();
      create_esdh = false;
    }
  }

  /**
   * Gernerate new prviate keys.
   */
  private void generatePrivateKeys() {
    try {
  	  // first create the KeyPairs
  	  if (create_rsa) {
  	    try {
          System.out.println("generate RSA KeyPair for CA certificate ["+CA_KEYLENGTH+" bits]...");
  	      ca_rsa = generateKeyPair("RSA", CA_KEYLENGTH);
          System.out.println("Generate RSA signing keys...");
          System.out.println("generate RSA KeyPair for a test certificate [512 bits]...");
    	  rsa512_sign = generateKeyPair("RSA", 512);
          System.out.println("generate RSA KeyPair for a test certificate [1024 bits]...");
    	  rsa1024_sign = generateKeyPair("RSA", 1024);
          System.out.println("generate RSA KeyPair for a test certificate [2048 bits]...");
    	  rsa2048_sign = generateKeyPair("RSA", 2048);
       	  System.out.println("Generate RSA encryption keys...");
          System.out.println("generate RSA KeyPair for a test certificate [512 bits]...");
    	  rsa512_crypt = generateKeyPair("RSA", 512);
          System.out.println("generate RSA KeyPair for a test certificate [1024 bits]...");
    	  rsa1024_crypt = generateKeyPair("RSA", 1024);
    	  System.out.println("generate second RSA KeyPair for a test certificate [1024 bits]...");
    	  rsa1024_crypt_ = generateKeyPair("RSA", 1024);  
          System.out.println("generate RSA KeyPair for a test certificate [2048 bits]...");
    	  rsa2048_crypt = generateKeyPair("RSA", 2048);  
  	    } catch (NoSuchAlgorithmException ex) {
          create_rsa = false;
          System.out.println("No implementation for RSA! RSA certificates are not created!\n");
  	    }
  	  }
      if (create_dsa) {
  	    try {
          System.out.println("generate DSA KeyPair for CA certificate ["+CA_KEYLENGTH+" bits]...");
  	      ca_dsa = generateKeyPair("DSA", CA_KEYLENGTH);
          System.out.println("generate DSA KeyPair for a test certificate [512 bits]...");
    	  dsa512 = generateKeyPair("DSA", 512);
          System.out.println("generate DSA KeyPair for a test certificate [1024 bits]...");
    	  dsa1024 = generateKeyPair("DSA", 1024);
  	    } catch (NoSuchAlgorithmException ex) {
          create_dsa = false;
          System.out.println("No implementation for DSA! DSA certificates are not created!\n");
  	    }
      }
      
      if (create_esdh) {
        try {
          System.out.println("generate ESDH KeyPair for a test certificate [512 bits]...");
    	  esdh512 = generateKeyPair("ESDH", 512);
          System.out.println("generate ESDH KeyPair for a test certificate [1024 bits]...");
    	  esdh1024 = generateKeyPair("ESDH", 1024);
    	  System.out.println("generate ESDH KeyPair for a test certificate [1024 bits]...");
    	  esdh1024_ = generateKeyPair("ESDH", 1024);
          System.out.println("generate ESDH KeyPair for a test certificate [2048 bits]...");
    	  esdh2048 = generateKeyPair("ESDH", 2048);
  	    } catch (NoSuchAlgorithmException ex) {
          create_esdh = false;
          System.out.println("No implementation for ESDH! ESDH certificates are not created!\n");
  	    }
  	  }  
    } catch (Exception ex) {
      System.out.println("Exception: "+ex);
    }
  }

  public void generateCertificates() {

    try {

      // Now create the certificates
      Name issuer = new Name();
      issuer.addRDN(ObjectID.country, "AT");
      issuer.addRDN(ObjectID.organization ,"IAIK");
      issuer.addRDN(ObjectID.organizationalUnit ,"JavaSecurity");

      Name subject = new Name();
      subject.addRDN(ObjectID.country, "AT");
      subject.addRDN(ObjectID.organization ,"IAIK");
      subject.addRDN(ObjectID.organizationalUnit ,"JavaSecurity");

      //
      // create self signed CA certs
      //
      X509Certificate caRSA = null;
      X509Certificate caDSA = null;
      X509Certificate[] chain = new X509Certificate[1];
      // for verifying the created certificates
      SimpleChainVerifier verifier = new SimpleChainVerifier();

      if (create_rsa) {
        issuer.addRDN(ObjectID.commonName ,"IAIK RSA Test CA");
        System.out.println("create self signed RSA CA certificate...");
        caRSA = createCertificate(issuer, ca_rsa.getPublic(),
              issuer, ca_rsa.getPrivate(), AlgorithmID.sha1WithRSAEncryption, null, true);
        // verify the self signed certificate
        caRSA.verify();
        // set the CA cert as trusted root
        verifier.addTrustedCertificate(caRSA);
        chain[0] = caRSA;
        addToKeyStore(ca_rsa, chain, CA_RSA);
        issuer.removeRDN(ObjectID.commonName);
      }

      if (create_dsa) {
        issuer.addRDN(ObjectID.commonName ,"IAIK DSA Test CA");
        System.out.println("create self signed DSA CA certificate...");
        caDSA = createCertificate(issuer, ca_dsa.getPublic(),
            issuer, ca_dsa.getPrivate(), AlgorithmID.dsaWithSHA, null, true);
        // verify the self signed certificate
        caDSA.verify();
        // set the CA cert as trusted root
        verifier.addTrustedCertificate(caDSA);
        chain[0] = caDSA;
        addToKeyStore(ca_dsa, chain, CA_DSA);
        issuer.removeRDN(ObjectID.commonName);
      }

      //
      // create certificates
      //
      chain = new X509Certificate[2];
            
      // create a RSA certificate
      if (create_rsa) {
        issuer.addRDN(ObjectID.commonName ,"IAIK RSA Test CA");
        SubjectKeyIdentifier subjectKeyID = (SubjectKeyIdentifier)caRSA.getExtension(SubjectKeyIdentifier.oid);
        // 512
         // for signing
        System.out.println("Create RSA demo certificates to be used for signing...");
      
        // 512
        subject.addRDN(ObjectID.commonName, "RSA 512 bit Demo Signing Certificate");
        System.out.println("create 512 bit RSA demo certificate...");
        chain[0] = createCertificate(subject, rsa512_sign.getPublic(),
              issuer, ca_rsa.getPrivate(), AlgorithmID.sha1WithRSAEncryption, subjectKeyID.get(), true);
        chain[1] = caRSA;
        // and verify the chain
        verifier.verifyChain(chain);
        addToKeyStore(rsa512_sign, chain, RSA_512_SIGN);
        subject.removeRDN(ObjectID.commonName);
        
        // 1024
      
        subject.addRDN(ObjectID.commonName ,"RSA 1024 bit Demo Signing Certificate");
        System.out.println("create 1024 bit RSA demo certificate...");
        chain[0] = createCertificate(subject, rsa1024_sign.getPublic(),
              issuer, ca_rsa.getPrivate(), AlgorithmID.sha1WithRSAEncryption, subjectKeyID.get(), true);
        chain[1] = caRSA;
        verifier.verifyChain(chain);
        addToKeyStore(rsa1024_sign, chain, RSA_1024_SIGN);
        subject.removeRDN(ObjectID.commonName);
      
        // 2048
      
        subject.addRDN(ObjectID.commonName ,"RSA 2048 bit Demo Signing Certificate");
        System.out.println("create 2048 bit RSA demo certificate...");
        chain[0] = createCertificate(subject, rsa2048_sign.getPublic(),
              issuer, ca_rsa.getPrivate(), AlgorithmID.sha1WithRSAEncryption, subjectKeyID.get(), true);
        chain[1] = caRSA;
        verifier.verifyChain(chain);
       
        addToKeyStore(rsa2048_sign, chain, RSA_2048_SIGN);
        subject.removeRDN(ObjectID.commonName);
      
        // for encrypting
        System.out.println("Create RSA demo certificates to be used for encryption...");
        // 512
        subject.addRDN(ObjectID.commonName, "RSA 512 bit Demo Encryption Certificate");
        System.out.println("create 512 bit RSA demo certificate...");
        chain[0] = createCertificate(subject, rsa512_crypt.getPublic(),
              issuer, ca_rsa.getPrivate(), AlgorithmID.sha1WithRSAEncryption, subjectKeyID.get(), false);
        chain[1] = caRSA;
        // and verify the chain
        verifier.verifyChain(chain);
        addToKeyStore(rsa512_crypt, chain, RSA_512_CRYPT);
        subject.removeRDN(ObjectID.commonName);
 
        // 1024
      
        subject.addRDN(ObjectID.commonName ,"RSA 1024 bit Demo Encryption Certificate");
        System.out.println("create 1024 bit RSA demo certificate...");
        chain[0] = createCertificate(subject, rsa1024_crypt.getPublic(),
              issuer, ca_rsa.getPrivate(), AlgorithmID.sha1WithRSAEncryption, subjectKeyID.get(), false);
        chain[1] = caRSA;
        verifier.verifyChain(chain);
        addToKeyStore(rsa1024_crypt, chain, RSA_1024_CRYPT);
        
        System.out.println("create second 1024 bit RSA demo Encryption certificate...");
        chain[0] = createCertificate(subject, rsa1024_crypt_.getPublic(),
              issuer, ca_rsa.getPrivate(), AlgorithmID.sha1WithRSAEncryption, subjectKeyID.get(), false);
        chain[1] = caRSA;
        verifier.verifyChain(chain);
        addToKeyStore(rsa1024_crypt_, chain, RSA_1024_CRYPT_);
        subject.removeRDN(ObjectID.commonName);
      
        // 2048
       
        subject.addRDN(ObjectID.commonName ,"RSA 2048 bit Demo Encryption Certificate");
        System.out.println("create 2048 bit RSA demo certificate...");
        chain[0] = createCertificate(subject, rsa2048_crypt.getPublic(),
              issuer, ca_rsa.getPrivate(), AlgorithmID.sha1WithRSAEncryption, subjectKeyID.get(), false);
        chain[1] = caRSA;
        verifier.verifyChain(chain);
        addToKeyStore(rsa2048_crypt, chain, RSA_2048_CRYPT);
        subject.removeRDN(ObjectID.commonName);        
        issuer.removeRDN(ObjectID.commonName);
      }
      
      // create a DSA test certificate
      if (create_dsa) {
        issuer.addRDN(ObjectID.commonName ,"IAIK DSA Test CA");
        // 512
        subject.addRDN(ObjectID.commonName ,"DSA 512 bit Demo Certificate");
        System.out.println("create 512 bit DSA demo certificate...");
        SubjectKeyIdentifier subjectKeyID = (SubjectKeyIdentifier)caDSA.getExtension(SubjectKeyIdentifier.oid);
        chain[0] = createCertificate(subject, dsa512.getPublic(),
              issuer, ca_dsa.getPrivate(), AlgorithmID.dsaWithSHA, subjectKeyID.get(), true);
        subject.removeRDN(ObjectID.commonName);
        chain[1] = caDSA;
        verifier.verifyChain(chain);
        
        addToKeyStore(dsa512, chain, DSA_512);
        // 1024
        subject.addRDN(ObjectID.commonName ,"DSA 1024 bit Demo Certificate");
        System.out.println("create 1024 bit DSA demo certificate...");
        chain[0] = createCertificate(subject, dsa1024.getPublic(),
              issuer, ca_dsa.getPrivate(), AlgorithmID.dsaWithSHA, subjectKeyID.get(), true);
        subject.removeRDN(ObjectID.commonName);
        chain[1] = caDSA;
        verifier.verifyChain(chain);
        addToKeyStore(dsa1024, chain, DSA_1024);
        issuer.removeRDN(ObjectID.commonName);
      }
      
      // create a ESDH test certificate
      if (create_esdh) {
        issuer.addRDN(ObjectID.commonName ,"IAIK DSA Test CA");
        // 512
        subject.addRDN(ObjectID.commonName ,"ESDH 512 bit Demo Certificate");
        System.out.println("create 512 bit ESDH demo certificate...");
        SubjectKeyIdentifier subjectKeyID = (SubjectKeyIdentifier)caDSA.getExtension(SubjectKeyIdentifier.oid);
        chain[0] = createCertificate(subject, esdh512.getPublic(),
              issuer, ca_dsa.getPrivate(), AlgorithmID.dsaWithSHA, subjectKeyID.get(), false);
        subject.removeRDN(ObjectID.commonName);
        chain[1] = caDSA;
        verifier.verifyChain(chain);
        addToKeyStore(esdh512, chain, ESDH_512);
        // 1024
        subject.addRDN(ObjectID.commonName ,"ESDH 1024 bit Demo Certificate 1");
        System.out.println("create 1024 bit ESDH demo certificate...");
        chain[0] = createCertificate(subject, esdh1024.getPublic(),
              issuer, ca_dsa.getPrivate(), AlgorithmID.dsaWithSHA, subjectKeyID.get(), false);
        subject.removeRDN(ObjectID.commonName);
        chain[1] = caDSA;
        verifier.verifyChain(chain);
        addToKeyStore(esdh1024, chain, ESDH_1024);
        // 1024
        subject.addRDN(ObjectID.commonName ,"ESDH 1024 bit Demo Certificate 2");
        System.out.println("create second 1024 bit ESDH demo certificate...");
        chain[0] = createCertificate(subject, esdh1024_.getPublic(),
              issuer, ca_dsa.getPrivate(), AlgorithmID.dsaWithSHA, subjectKeyID.get(), false);
        subject.removeRDN(ObjectID.commonName);
        chain[1] = caDSA;
        verifier.verifyChain(chain);
        addToKeyStore(esdh1024_, chain, ESDH_1024_);
        // 2048
        subject.addRDN(ObjectID.commonName ,"ESDH 2048 bit Demo Certificate");
        System.out.println("create 2048 bit ESDH demo certificate...");
        chain[0] = createCertificate(subject, esdh2048.getPublic(),
              issuer, ca_dsa.getPrivate(), AlgorithmID.dsaWithSHA, subjectKeyID.get(), false);
        subject.removeRDN(ObjectID.commonName);
        chain[1] = caDSA;
        verifier.verifyChain(chain);
        addToKeyStore(esdh2048, chain, ESDH_2048);
        issuer.removeRDN(ObjectID.commonName);
      }

      System.out.println("\nCertificates created!");
 
    } catch (Exception ex) {
      System.out.println("Exception: "+ex);
    }
  }

  public static void start() {
  	SetupCMSKeyStore suks = new SetupCMSKeyStore();
    suks.initializeKeyStore();
    if (suks.create_only_certificates) {
    	suks.getPrivateKeys();
    }
    else {
  	  suks.generatePrivateKeys();
  	}
  	suks.generateCertificates();
    suks.saveKeyStore();
  }
  
  /**
   * Creates the test certificates.
   */
  public static void main(String arg[]) throws IOException {

  	IAIK.addAsProvider(true);
    start();    
    System.in.read();
  }
}