Package org.owasp.webscarab.plugin.proxy

Source Code of org.owasp.webscarab.plugin.proxy.SSLSocketFactoryFactory$HostKeyManager

package org.owasp.webscarab.plugin.proxy;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509KeyManager;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.operator.OperatorCreationException;

import org.owasp.webscarab.util.SunCertificateUtils;

public class SSLSocketFactoryFactory {

  /* set the date of issue to one month ago */
  private static final long DEFAULT_AGE = 30L * 24L * 60L * 60L * 1000L;
  private static final long DEFAULT_VALIDITY = 10L * 365L * 24L * 60L * 60L
      * 1000L;

  private static Logger logger = Logger
      .getLogger(SSLSocketFactoryFactory.class.getName());

  private static final String CA = "CA";

  private static X500Principal CA_NAME;

  static {
    try {
      CA_NAME = new X500Principal("cn=OWASP Custom CA for "
          + java.net.InetAddress.getLocalHost().getHostName()
          + " at " + new Date()
          + ",ou=OWASP Custom CA,o=OWASP,l=OWASP,st=OWASP,c=OWASP");
    } catch (IOException ioe) {
      ioe.printStackTrace();
      CA_NAME = null;
    }
  }

  private PrivateKey caKey;

  private X509Certificate[] caCerts;

  private String filename;

  private KeyStore keystore;

  private char[] password;

  private boolean reuseKeys = false;

  private Map<String, SSLContext> contextCache = new HashMap<String, SSLContext>();

  private Set<BigInteger> serials = new HashSet<BigInteger>();

  public SSLSocketFactoryFactory() throws GeneralSecurityException,
      IOException, OperatorCreationException {
    this(null, "JKS", "password".toCharArray());
  }

  public SSLSocketFactoryFactory(String filename, String type, char[] password)
      throws GeneralSecurityException, IOException, OperatorCreationException {
    this(filename, type, password, CA_NAME);
  }

  public SSLSocketFactoryFactory(String filename, String type,
      char[] password, X500Principal caName)
      throws GeneralSecurityException, IOException, OperatorCreationException {
    this.filename = filename;
    this.password = password;
    keystore = KeyStore.getInstance(type);
    File file = new File(filename);
    if (filename == null) {
      logger
          .info("No keystore provided, keys and certificates will be transient!");
    }
    if (file.exists()) {
      logger.fine("Loading keys from " + filename);
      InputStream is = new FileInputStream(file);
      keystore.load(is, password);
      caKey = (PrivateKey) keystore.getKey(CA, password);
      if (caKey == null) {
        logger.warning("Keystore does not contain an entry for '" + CA
            + "'");
      }
      caCerts = cast(keystore.getCertificateChain(CA));
      initSerials();
    } else {
      logger.info("Generating CA key");
      keystore.load(null, password);
      generateCA(caName);
    }
  }

  /**
   * Determines whether the public and private key generated for the CA will
   * be reused for other hosts as well.
   *
   * This is mostly just a performance optimisation, to save time generating a
   * key pair for each host. Paranoid clients may have an issue with this, in
   * theory.
   *
   * @param reuse
   *            true to reuse the CA key pair, false to generate a new key
   *            pair for each host
   */
  public void setReuseKeys(boolean reuse) {
    reuseKeys = reuse;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.owasp.proxy.daemon.CertificateProvider#getSocketFactory(java.lang
   * .String, int)
   */
  public synchronized SSLSocketFactory getSocketFactory(String host,
    X509Certificate baseCrt)
      throws IOException, GeneralSecurityException,
                        OperatorCreationException {
    SSLContext sslcontext = contextCache.get(host);
    if (sslcontext == null) {
      X509KeyManager km;
      if (!keystore.containsAlias(host)) {
        km = createKeyMaterial(host, baseCrt);
      } else {
        km = loadKeyMaterial(host);
      }
      sslcontext = SSLContext.getInstance("TLSv1");
      sslcontext.init(new KeyManager[] { km }, null, null);
      contextCache.put(host, sslcontext);
    }
    return sslcontext.getSocketFactory();
  }

  private X509Certificate[] cast(Certificate[] chain) {
    X509Certificate[] certs = new X509Certificate[chain.length];
    for (int i = 0; i < chain.length; i++) {
      certs[i] = (X509Certificate) chain[i];
    }
    return certs;
  }
 
  private X509KeyManager loadKeyMaterial(String host)
                throws GeneralSecurityException, IOException {
    X509Certificate[] certs = null;
    Certificate[] chain = keystore.getCertificateChain(host);
    if (chain != null) {
      certs = cast(chain);
    } else {
      throw new GeneralSecurityException(
          "Internal error: certificate chain for " + host
              + " not found!");
    }

    PrivateKey pk = (PrivateKey) keystore.getKey(host, password);
    if (pk == null) {
      throw new GeneralSecurityException(
          "Internal error: private key for " + host + " not found!");
    }
    return new HostKeyManager(host, pk, certs);
  }

  private void saveKeystore() {
    if (filename == null)
      return;
    try {
      OutputStream out = new FileOutputStream(filename);
      keystore.store(out, password);
      out.close();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    } catch (GeneralSecurityException gse) {
      gse.printStackTrace();
    }
  }

  private void generateCA(X500Principal caName)
      throws GeneralSecurityException, IOException,
                        OperatorCreationException {
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    keyGen.initialize(1024);
    KeyPair caPair = keyGen.generateKeyPair();
    caKey = caPair.getPrivate();
    PublicKey caPubKey = caPair.getPublic();
    Date begin = new Date();
    begin.setTime(begin.getTime() - DEFAULT_AGE);
    Date ends = new Date(begin.getTime() + DEFAULT_VALIDITY);

    X509Certificate cert = SunCertificateUtils.sign(caName, caPubKey,
        caName, caPubKey, caKey, begin, ends, BigInteger.ONE,
                                null);
    caCerts = new X509Certificate[] { cert };

    keystore.setKeyEntry(CA, caKey, password, caCerts);
    saveKeystore();
  }

  private void initSerials() throws GeneralSecurityException {
    Enumeration<String> e = keystore.aliases();
    while (e.hasMoreElements()) {
      String alias = e.nextElement();
      X509Certificate cert = (X509Certificate) keystore
          .getCertificate(alias);
      BigInteger serial = cert.getSerialNumber();
      serials.add(serial);
    }
  }

  protected X500Principal getSubjectPrincipal(String host) {
    return new X500Principal("cn=" + host + ",ou=UNTRUSTED,o=UNTRUSTED");
  }

  protected BigInteger getNextSerialNo() {
    BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
    while (serials.contains(serial))
      serial.add(BigInteger.ONE);
    serials.add(serial);
    return serial;
  }

  private X509KeyManager createKeyMaterial(String host, X509Certificate baseCrt)
      throws GeneralSecurityException, IOException, OperatorCreationException {
    KeyPair keyPair;

    if (reuseKeys) {
      keyPair = new KeyPair(caCerts[0].getPublicKey(), caKey);
    } else {
      KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
      keygen.initialize(1024);
      keyPair = keygen.generateKeyPair();
    }

    X500Principal subject = getSubjectPrincipal(host);
    Date begin = new Date();
    begin.setTime(begin.getTime() - DEFAULT_AGE);
    Date ends = new Date(begin.getTime() + DEFAULT_VALIDITY);

    X509Certificate cert = SunCertificateUtils.sign(subject, keyPair
        .getPublic(), caCerts[0].getSubjectX500Principal(), caCerts[0]
        .getPublicKey(), caKey, begin, ends, getNextSerialNo(),
        baseCrt);

    X509Certificate[] chain = new X509Certificate[caCerts.length + 1];
    System.arraycopy(caCerts, 0, chain, 1, caCerts.length);
    chain[0] = cert;

    PrivateKey pk = keyPair.getPrivate();

    keystore.setKeyEntry(host, pk, password, chain);
    saveKeystore();
    return new HostKeyManager(host, pk, chain);
  }

  private class HostKeyManager implements X509KeyManager {

    private String host;

    private PrivateKey pk;

    private X509Certificate[] certs;

    public HostKeyManager(String host, PrivateKey pk,
        X509Certificate[] certs) {
      this.host = host;
      this.pk = pk;
      this.certs = certs;
    }

    public String chooseClientAlias(String[] keyType, Principal[] issuers,
        Socket socket) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public String chooseServerAlias(String keyType, Principal[] issuers,
        Socket socket) {
      return host;
    }

    public X509Certificate[] getCertificateChain(String alias) {
      return certs;
    }

    public String[] getClientAliases(String keyType, Principal[] issuers) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public PrivateKey getPrivateKey(String alias) {
      return pk;
    }

    public String[] getServerAliases(String keyType, Principal[] issuers) {
      return new String[] { host };
    }

  }

}
TOP

Related Classes of org.owasp.webscarab.plugin.proxy.SSLSocketFactoryFactory$HostKeyManager

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.