Package org.snova.framework.util

Source Code of org.snova.framework.util.SslCertificateHelper

/**
* This file is part of the hyk-proxy-framework project.
* Copyright (c) 2011 Yin QiWen <yinqiwen@gmail.com>
*
* Description: BouncyCastleHelper.java
*
* @author yinqiwen [ 2011-5-8 | 11:27:39AM ]
*
*/
package org.snova.framework.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Date;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;
import java.util.WeakHashMap;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.security.auth.x500.X500Principal;

import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.jce.PrincipalUtil;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.MiscPEMGenerator;
import org.bouncycastle.util.io.pem.PemWriter;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snova.framework.config.SnovaConfiguration;

/**
*
*/
public class SslCertificateHelper
{
  protected static Logger logger = LoggerFactory
          .getLogger(SslCertificateHelper.class);
  static
  {
    Security.addProvider(new BouncyCastleProvider());
  }

  static PrivateKey caPriKey;
  static X509Certificate caCert;
  static Map<String, KeyStore> kstCache = new WeakHashMap<String, KeyStore>();
  public static final String KS_PASS = "hyk-proxy";
  public static final String CA_ALIAS = "RootCAPriKey";
  public static final String CLIENT_CERT_ALIAS = "FakeCertForClient";
  public static final String CA_FILE = "RootKeyStore.kst";

  public static PrivateKey getFakeRootCAPrivateKey()
  {
    loadFakeRootCA();
    return caPriKey;
  }

  public static X509Certificate getFakeRootCAX509Certificate()
  {
    loadFakeRootCA();
    return caCert;
  }

  private static final byte[] BUFFER = new byte[4096];

  /**
   * copy input to output stream - available in several StreamUtils or Streams
   * classes
   */
  public static void copy(InputStream input, OutputStream output)
          throws IOException
  {
    int bytesRead;
    while ((bytesRead = input.read(BUFFER)) != -1)
    {
      output.write(BUFFER, 0, bytesRead);
    }
  }

  private static File getFakeSSLCertFile(String host)
  {
    File confhome = new File(SnovaConfiguration.getHome(), "cert");
    if (!confhome.exists())
    {
      confhome.mkdir();
    }
    confhome = new File(confhome, "host");
    if (!confhome.exists())
    {
      confhome.mkdir();
    }
    File file = new File(confhome, host + ".kst");
    return file;
  }

  private static boolean loadFakeRootCA()
  {
    if (null == caPriKey || null == caCert)
    {
      try
      {
        KeyStore ks = KeyStore.getInstance("JKS");
        FileInputStream fis = new FileInputStream(new File(
                SnovaConfiguration.getHome() + "/cert",
                "RootKeyStore.kst"));
        ks.load(fis, KS_PASS.toCharArray());
        caCert = (X509Certificate) ks.getCertificate(CA_ALIAS);
        caPriKey = (PrivateKey) ks.getKey(CA_ALIAS,
                KS_PASS.toCharArray());
        fis.close();

      }
      catch (Exception e)
      {
        logger.error("Failed to load fake CA key store.", e);
        return false;
      }

    }
    return true;
  }

  private static KeyPair createRSAKeyPair() throws NoSuchAlgorithmException,
          NoSuchProviderException
  {
    KeyPairGenerator g = KeyPairGenerator.getInstance("RSA");
    SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
    rnd.setSeed(System.currentTimeMillis());
    g.initialize(2048, rnd);
    KeyPair keypair = g.genKeyPair();
    return keypair;

  }

  public static X509Certificate createCACert(KeyPair keypair)
          throws InvalidKeyException, IllegalStateException,
          NoSuchProviderException, NoSuchAlgorithmException,
          SignatureException, CertificateException
  {
    final Date startDate = Calendar.getInstance().getTime();
    final Date expireDate = new Date(startDate.getTime()
            + (100L * 365L * 24L * 60L * 60L * 1000L));
    // The Root CA serial number is '1'
    final BigInteger serialNumber = new BigInteger("1");

    final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
    // using the hash code of the user's name and home path, keeps anonymity
    // but also gives user a chance to distinguish between each other
    final X500Principal x500principal = new X500Principal(
            "CN = Snova Framework Root Fake CA, "
                    + "L = "
                    + Integer.toHexString(System.getProperty("user.name")
                            .hashCode())
                    + Integer.toHexString(System.getProperty("user.home")
                            .hashCode()) + ", "
                    + "O = Snova Root Fake CA, "
                    + "OU = Snova Root Fake CA, " + "C = XX");

    certGen.setSerialNumber(serialNumber);
    certGen.setSubjectDN(x500principal);
    certGen.setIssuerDN(x500principal);
    certGen.setNotBefore(startDate);
    certGen.setNotAfter(expireDate);
    certGen.setPublicKey(keypair.getPublic());
    certGen.setSignatureAlgorithm("SHA1withRSA");

    KeyStore ks = null;
    try
    {
      certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
              new SubjectKeyIdentifierStructure(keypair.getPublic()));
      certGen.addExtension(X509Extensions.BasicConstraints, false,
              new BasicConstraints(true));
      final X509Certificate cert = certGen.generate(keypair.getPrivate());
      return cert;
    }
    catch (final Exception e)
    {
      throw new IllegalStateException(
              "Errors during assembling root CA.", e);
    }
  }

  public static X509Certificate createClientCert(String host, PublicKey pubKey)
          throws Exception
  {
    if (!loadFakeRootCA())
    {
      return null;
    }
    // final KeyPair mykp = this.createKeyPair();
    // final PrivateKey privKey = mykp.getPrivate();
    // final PublicKey pubKey = mykp.getPublic();

    //
    // subjects name table.
    //
    final Hashtable<Object, String> attrs = new Hashtable<Object, String>();
    final Vector<Object> order = new Vector<Object>();

    attrs.put(X509Name.CN, host);
    attrs.put(X509Name.OU, "hyk-proxy Project");
    attrs.put(X509Name.O, "hyk-proxy");
    attrs.put(X509Name.C, "XX");
    attrs.put(X509Name.EmailAddress, "yinqiwen@gmail.com");

    order.addElement(X509Name.CN);
    order.addElement(X509Name.OU);
    order.addElement(X509Name.O);
    order.addElement(X509Name.C);
    order.addElement(X509Name.EmailAddress);

    //
    // create the certificate - version 3
    //
    final X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
    v3CertGen.reset();

    v3CertGen
            .setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
    v3CertGen.setIssuerDN(PrincipalUtil.getSubjectX509Principal(caCert));
    v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60
            * 60 * 24 * 30));
    v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + 100
            * (1000L * 60 * 60 * 24 * 30)));
    v3CertGen.setSubjectDN(new X509Principal(order, attrs));
    v3CertGen.setPublicKey(pubKey);
    v3CertGen.setSignatureAlgorithm("SHA1WithRSAEncryption");

    //
    // add the extensions
    //
    v3CertGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
            new SubjectKeyIdentifierStructure(pubKey));

    v3CertGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
            new AuthorityKeyIdentifierStructure(caCert.getPublicKey()));

    v3CertGen.addExtension(X509Extensions.BasicConstraints, true,
            new BasicConstraints(0));

    // X509Certificate cert = v3CertGen.generateX509Certificate(caPrivKey);
    final X509Certificate cert = v3CertGen.generate(caPriKey, "BC");
    cert.checkValidity(new Date());
    cert.verify(caCert.getPublicKey());

    // cert.verify(caCert.getPublicKey());
    // cert.getEncoded();

    return cert;
  }

  public static KeyStore getClientKeyStore(String host) throws Exception
  {
    if (kstCache.containsKey(host))
    {
      return kstCache.get(host);
    }
    KeyStore ks = KeyStore.getInstance("JKS");

    File fakeSslFile = getFakeSSLCertFile(host);
    InputStream is = fakeSslFile.exists() ? new FileInputStream(fakeSslFile)
            : null;
    //System.out.println("####" + fakeSslFile.getAbsolutePath());
    ks.load(is, null == is ? null : KS_PASS.toCharArray());

    if (null == is)
    {
      final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
      final SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
      random.setSeed(Long.toString(System.currentTimeMillis()).getBytes());
      keyGen.initialize(2048, random);
      final KeyPair keypair = keyGen.generateKeyPair();
      // KeyPair pair = createRSAKeyPair();
      X509Certificate cert = createClientCert(host, keypair.getPublic());
      ks.setKeyEntry(CLIENT_CERT_ALIAS, keypair.getPrivate(),
              KS_PASS.toCharArray(), new Certificate[] { cert, caCert });
      FileOutputStream fos = new FileOutputStream(fakeSslFile);
      ks.store(fos, KS_PASS.toCharArray());
    }
    else
    {
      is.close();
    }
    // ks.store(new FileOutputStream(kst_file), KS_PASS.toCharArray());
    kstCache.put(host, ks);
    return ks;
  }

  public static SSLContext getFakeSSLContext(String host, String port)
          throws Exception
  {
    long start1 = System.currentTimeMillis();
    KeyStore kst = SslCertificateHelper.getClientKeyStore(host);
    long start = System.currentTimeMillis();
    SSLContext sslContext = SSLContext.getInstance("TLS");
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");

    kmf.init(kst, SslCertificateHelper.KS_PASS.toCharArray());
    sslContext.init(kmf.getKeyManagers(), null, null);
    long end = System.currentTimeMillis();
    if (logger.isDebugEnabled())
    {
      logger.debug("Cost " + (end - start) + "ms to inti ssl context.");
      logger.debug("Cost " + (start - start1)
              + "ms to retrive key store.");
    }
    // sslparams.s
    // param.setSSLParameters(sslparams);
    return sslContext;
  }

  public static void main(String[] args) throws Exception
  {
    // X509V3CertificateGenerator c = new X509V3CertificateGenerator();
    KeyPair pair = createRSAKeyPair();
    X509Certificate cert = createCACert(pair);
    FileOutputStream fos = new FileOutputStream(CA_FILE);
    // KeyStore.
    // System.out.println("#####" + KeyStore.getDefaultType());
    KeyStore ks = KeyStore.getInstance("bks", "BC");
    ks.load(null, null);
    ks.setKeyEntry(CA_ALIAS, pair.getPrivate(), KS_PASS.toCharArray(),
            new Certificate[] { cert });
    ks.store(fos, KS_PASS.toCharArray());
    fos.close();
    ks = KeyStore.getInstance("bks", "BC");
    ks.load(new FileInputStream(CA_FILE), KS_PASS.toCharArray());
    Object obj = ks.getCertificate("RootCAPriKey");
    // final Certificate cert =
    // rootca.getCertificate(SslCertificateService.ZAPROXY_JKS_ALIAS);
    final PemWriter pw = new PemWriter(new FileWriter(
            "Fake-ACRoot-Certificate.cer"));
    pw.writeObject(new MiscPEMGenerator(cert));
    pw.flush();
  }
}
TOP

Related Classes of org.snova.framework.util.SslCertificateHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.