All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cybervillains.ca.CertificateCreator Maven / Gradle / Ivy

Go to download

Selenium automates browsers. That's it! What you do with that power is entirely up to you.

There is a newer version: 3.9.1
Show newest version
package cybervillains.ca;

import org.bouncycastle.asn1.DEREncodable;
import org.bouncycastle.asn1.DEREncodableVector;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;

import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.security.auth.x500.X500Principal;

/**
 * Methods for creating certificates.
 * 
 * *************************************************************************************** Copyright
 * (c) 2007, Information Security Partners, LLC All rights reserved.
 * 
 * In a special exception, Selenium/OpenQA is allowed to use this code under the Apache License 2.0.
 * 
 * @author Brad Hill
 * 
 */
public class CertificateCreator {


  private static final HashSet clientCertOidsNeverToCopy = new HashSet();
  private static final HashSet clientCertDefaultOidsNotToCopy = new HashSet();

  /**
   * The default key generation algorithm for this package is RSA.
   */
  public static final String KEYGEN_ALGO = "RSA";

  /**
   * The default sign algorithm for this package is SHA1 with RSA.
   */
  public static final String SIGN_ALGO = "SHA1withRSA";


  /**
   * X.509 OID for Subject Key Identifier Extension - Replaced when duplicating a cert.
   */
  public static final String OID_SUBJECT_KEY_IDENTIFIER = "2.5.29.14";

  /**
   * X.509 OID for Subject Authority Key Identifier - Replaced when duplicating a cert.
   */
  public static final String OID_AUTHORITY_KEY_IDENTIFIER = "2.5.29.35";

  /**
   * X.509 OID for Issuer Alternative Name - Omitted when duplicating a cert by default.
   */
  public static final String OID_ISSUER_ALTERNATIVE_NAME = "2.5.29.8";

  /**
   * X.509 OID for Issuer Alternative Name 2 - Omitted when duplicating a cert by default.
   */
  public static final String OID_ISSUER_ALTERNATIVE_NAME_2 = "2.5.29.18";

  /**
   * X.509 OID for Certificate Revocation List Distribution Point - Omitted when duplicating a cert
   * by default.
   */
  public static final String OID_CRL_DISTRIBUTION_POINT = "2.5.28.31";

  /**
   * X.509 OID for Authority Information Access - Omitted when duplicating a cert by default.
   */
  public static final String OID_AUTHORITY_INFO_ACCESS = "1.3.6.1.5.5.7.1.1";

  /**
   * X.509 OID for Additional CA Issuers for AIA - Omitted when duplicating a cert by default.
   */
  public static final String OID_ID_AD_CAISSUERS = "1.3.6.1.5.5.7.48.2";


  static
  {
    clientCertOidsNeverToCopy.add(OID_SUBJECT_KEY_IDENTIFIER);
    clientCertOidsNeverToCopy.add(OID_AUTHORITY_KEY_IDENTIFIER);

    clientCertDefaultOidsNotToCopy.add(OID_ISSUER_ALTERNATIVE_NAME);
    clientCertDefaultOidsNotToCopy.add(OID_ISSUER_ALTERNATIVE_NAME_2);
    clientCertDefaultOidsNotToCopy.add(OID_CRL_DISTRIBUTION_POINT);
    clientCertDefaultOidsNotToCopy.add(OID_AUTHORITY_INFO_ACCESS);
  }


  /**
   * Utility method for generating a "standard" server certificate. Recognized by most browsers as
   * valid for SSL/TLS. These certificates are generated de novo, not from a template, so they will
   * not retain the structure of the original certificate and may not be suitable for applications
   * that require Extended Validation/High Assurance SSL or other distinct extensions or EKU.
   * 
   * @param newPubKey
   * @param caCert
   * @param caPrivateKey
   * @param hostname
   * @return
   * @throws CertificateParsingException
   * @throws SignatureException
   * @throws InvalidKeyException
   * @throws CertificateExpiredException
   * @throws CertificateNotYetValidException
   * @throws CertificateException
   * @throws NoSuchAlgorithmException
   * @throws NoSuchProviderException
   */
  @SuppressWarnings("deprecation")
  public static X509Certificate generateStdSSLServerCertificate(
      final PublicKey newPubKey,
      final X509Certificate caCert,
      final PrivateKey caPrivateKey,
      final String subject,
      final String certificateRevocationListPath)
      throws CertificateParsingException,
      SignatureException,
      InvalidKeyException,
      CertificateExpiredException,
      CertificateNotYetValidException,
      CertificateException,
      NoSuchAlgorithmException,
      NoSuchProviderException
  {
    X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();

    v3CertGen.setSubjectDN(new X500Principal(subject));
    v3CertGen.setSignatureAlgorithm(CertificateCreator.SIGN_ALGO);
    v3CertGen.setPublicKey(newPubKey);
    // 5 years in the future
    v3CertGen
        .setNotAfter(new Date(System.currentTimeMillis() + 1000L * 60 * 60 * 24 * 30 * 12 * 5));
    // 1 year in the past
    v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30 * 12));
    v3CertGen.setIssuerDN(caCert.getSubjectX500Principal());

    // Firefox actually tracks serial numbers within a CA and refuses to validate if it sees
    // duplicates
    // This is not a secure serial number generator, (duh!) but it's good enough for our purposes.
    v3CertGen.setSerialNumber(new BigInteger(Long.toString(System.currentTimeMillis())));

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

    v3CertGen.addExtension(
        X509Extensions.SubjectKeyIdentifier,
        false,
        new SubjectKeyIdentifierStructure(newPubKey));


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

    // Firefox 2 disallows these extensions in an SSL server cert. IE7 doesn't care.
    // v3CertGen.addExtension(
    // X509Extensions.KeyUsage,
    // false,
    // new KeyUsage(KeyUsage.dataEncipherment | KeyUsage.digitalSignature ) );


    DEREncodableVector typicalSSLServerExtendedKeyUsages = new DEREncodableVector();

    typicalSSLServerExtendedKeyUsages.add(new DERObjectIdentifier(
        ExtendedKeyUsageConstants.serverAuth));
    typicalSSLServerExtendedKeyUsages.add(new DERObjectIdentifier(
        ExtendedKeyUsageConstants.clientAuth));
    typicalSSLServerExtendedKeyUsages.add(new DERObjectIdentifier(
        ExtendedKeyUsageConstants.netscapeServerGatedCrypto));
    typicalSSLServerExtendedKeyUsages.add(new DERObjectIdentifier(
        ExtendedKeyUsageConstants.msServerGatedCrypto));

    v3CertGen.addExtension(
        X509Extensions.ExtendedKeyUsage,
        false,
        new DERSequence(typicalSSLServerExtendedKeyUsages));

    // Disabled by default. Left in comments in case this is desired.
    //
    // v3CertGen.addExtension(
    // X509Extensions.AuthorityInfoAccess,
    // false,
    // new AuthorityInformationAccess(new DERObjectIdentifier(OID_ID_AD_CAISSUERS),
    // new GeneralName(GeneralName.uniformResourceIdentifier, "http://" + subject + "/aia")));

    if (certificateRevocationListPath != null) {
      /* Safari on Windows requires a CRL and validates it */
      DistributionPoint crl = new DistributionPoint(new DistributionPointName(
          DistributionPointName.FULL_NAME, new GeneralName(
              GeneralName.uniformResourceIdentifier, certificateRevocationListPath)),
          null, null);
      v3CertGen.addExtension(
          X509Extensions.CRLDistributionPoints,
          false,
          new CRLDistPoint(new DistributionPoint[] {crl}));
    }



    X509Certificate cert = v3CertGen.generate(caPrivateKey, "BC");

    return cert;
  }

  /**
   * This method creates an X509v3 certificate based on an an existing certificate. It attempts to
   * create as faithful a copy of the existing certificate as possible by duplicating all
   * certificate extensions.
   * 
   * If you are testing an application that makes use of additional certificate extensions (e.g.
   * logotype, S/MIME capabilities) this method will preserve those fields.
   * 
   * You may optionally include a set of OIDs not to copy from the original certificate. The most
   * common reason to do this would be to remove fields that would cause inconsistency, such as
   * Authority Info Access or Issuer Alternative Name where these are not defined for the MITM
   * authority certificate.
   * 
   * OIDs 2.5.29.14 : Subject Key Identifier and 2.5.29.35 : Authority Key Identifier, are never
   * copied, but generated directly based on the input keys and certificates.
   * 
   * You may also optionally include maps of custom extensions which will be added to or replace
   * extensions with the same OID on the original certificate for the the MITM certificate.
   * 
   * FUTURE WORK: JDK 1.5 is very strict in parsing extensions. In particular, known extensions that
   * include URIs must parse to valid URIs (including URL encoding all non-valid URI characters) or
   * the extension will be rejected and not available to copy to the MITM certificate. Will need to
   * directly extract these as ASN.1 fields and re-insert (hopefully BouncyCastle will handle them)
   * 
   * 
   * @param originalCert The original certificate to duplicate.
   * @param newPubKey The new public key for the MITM certificate.
   * @param caCert The certificate of the signing authority fot the MITM certificate.
   * @param caPrivateKey The private key of the signing authority.
   * @param extensionOidsNotToCopy An optional list of certificate extension OIDs not to copy to the
   *        MITM certificate.
   * @param criticalCustomExtensions An optional map of critical extension OIDs to add/replace on
   *        the MITM certificate.
   * @param noncriticalCustomExtensions An optional map of non-critical extension OIDs to
   *        add/replace on the MITM certificate.
   * @return The new MITM certificate.
   * @throws CertificateParsingException
   * @throws SignatureException
   * @throws InvalidKeyException
   * @throws CertificateExpiredException
   * @throws CertificateNotYetValidException
   * @throws CertificateException
   * @throws NoSuchAlgorithmException
   * @throws NoSuchProviderException
   */
  public static X509Certificate mitmDuplicateCertificate(final X509Certificate originalCert,
      final PublicKey newPubKey,
      final X509Certificate caCert,
      final PrivateKey caPrivateKey,
      Set extensionOidsNotToCopy,
      Map criticalCustomExtensions,
      Map noncriticalCustomExtensions)
      throws CertificateParsingException,
      SignatureException,
      InvalidKeyException,
      CertificateException,
      NoSuchAlgorithmException,
      NoSuchProviderException
  {
    if (extensionOidsNotToCopy == null)
    {
      extensionOidsNotToCopy = new HashSet();
    }
    if (noncriticalCustomExtensions == null)
    {
      noncriticalCustomExtensions = new HashMap();
    }
    if (criticalCustomExtensions == null)
    {
      criticalCustomExtensions = new HashMap();
    }

    X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();

    v3CertGen.setSubjectDN(originalCert.getSubjectX500Principal());
    v3CertGen.setSignatureAlgorithm(CertificateCreator.SIGN_ALGO); // needs to be the same as the
                                                                   // signing cert, not the copied
                                                                   // cert
    v3CertGen.setPublicKey(newPubKey);
    v3CertGen.setNotAfter(originalCert.getNotAfter());
    v3CertGen.setNotBefore(originalCert.getNotBefore());
    v3CertGen.setIssuerDN(caCert.getSubjectX500Principal());
    v3CertGen.setSerialNumber(originalCert.getSerialNumber());

    // copy other extensions:
    Set critExts = originalCert.getCriticalExtensionOIDs();

    // get extensions returns null, not an empty set!
    if (critExts != null) {
      for (String oid : critExts) {
        if (!clientCertOidsNeverToCopy.contains(oid)
            && !extensionOidsNotToCopy.contains(oid)
            && !criticalCustomExtensions.containsKey(oid)) {
          v3CertGen.copyAndAddExtension(new DERObjectIdentifier(oid), true, originalCert);
        }
      }
    }
    Set nonCritExs = originalCert.getNonCriticalExtensionOIDs();

    if (nonCritExs != null) {
      for (String oid : nonCritExs) {

        if (!clientCertOidsNeverToCopy.contains(oid)
            && !extensionOidsNotToCopy.contains(oid)
            && !noncriticalCustomExtensions.containsKey(oid)) {
          v3CertGen.copyAndAddExtension(new DERObjectIdentifier(oid), false, originalCert);
        }
      }
    }

    for (Map.Entry customExtension : criticalCustomExtensions.entrySet()) {
      v3CertGen.addExtension(customExtension.getKey(), true, customExtension.getValue());
    }

    for (Map.Entry customExtension : noncriticalCustomExtensions.entrySet()) {
      v3CertGen.addExtension(customExtension.getKey(), false, customExtension.getValue());
    }

    v3CertGen.addExtension(
        X509Extensions.SubjectKeyIdentifier,
        false,
        new SubjectKeyIdentifierStructure(newPubKey));


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

    X509Certificate cert = v3CertGen.generate(caPrivateKey, "BC");

    // For debugging purposes.
    // cert.checkValidity(new Date());
    // cert.verify(caCert.getPublicKey());

    return cert;
  }

  /**
   * Convenience method for the most common case of certificate duplication.
   * 
   * This method will not add any custom extensions and won't copy the extensions 2.5.29.8 : Issuer
   * Alternative Name, 2.5.29.18 : Issuer Alternative Name 2, 2.5.29.31 : CRL Distribution Point or
   * 1.3.6.1.5.5.7.1.1 : Authority Info Access, if they are present.
   * 
   * @param originalCert
   * @param newPubKey
   * @param caCert
   * @param caPrivateKey
   * @return
   * @throws CertificateParsingException
   * @throws SignatureException
   * @throws InvalidKeyException
   * @throws CertificateExpiredException
   * @throws CertificateNotYetValidException
   * @throws CertificateException
   * @throws NoSuchAlgorithmException
   * @throws NoSuchProviderException
   */
  public static X509Certificate mitmDuplicateCertificate(final X509Certificate originalCert,
      final PublicKey newPubKey,
      final X509Certificate caCert,
      final PrivateKey caPrivateKey)
      throws CertificateParsingException, SignatureException, InvalidKeyException,
      CertificateExpiredException, CertificateNotYetValidException, CertificateException,
      NoSuchAlgorithmException, NoSuchProviderException
  {
    return mitmDuplicateCertificate(originalCert, newPubKey, caCert, caPrivateKey,
        clientCertDefaultOidsNotToCopy, null, null);
  }

  /**
   * Creates a typical Certification Authority (CA) certificate.
   * 
   * @param keyPair
   * @throws SecurityException
   * @throws InvalidKeyException
   * @throws NoSuchProviderException
   * @throws NoSuchAlgorithmException
   * @throws CertificateException
   */
  @SuppressWarnings("deprecation")
  public static X509Certificate createTypicalMasterCert(final KeyPair keyPair)
      throws SignatureException, InvalidKeyException, SecurityException, CertificateException,
      NoSuchAlgorithmException, NoSuchProviderException
  {

    X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();

    X509Principal issuer =
        new X509Principal("O=CyberVillians.com,OU=CyberVillians Certification Authority,C=US");

    // Create
    v3CertGen.setSerialNumber(BigInteger.valueOf(1));
    v3CertGen.setIssuerDN(issuer);
    v3CertGen.setSubjectDN(issuer);

    // Set validity period
    v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 12 /* months */*
        (1000L * 60 * 60 * 24 * 30)));
    v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + 48 /* months */*
        (1000L * 60 * 60 * 24 * 30)));

    // Set signature algorithm & public key
    v3CertGen.setPublicKey(keyPair.getPublic());
    v3CertGen.setSignatureAlgorithm(CertificateCreator.SIGN_ALGO);

    // Add typical extensions for signing cert
    v3CertGen.addExtension(
        X509Extensions.SubjectKeyIdentifier,
        false,
        new SubjectKeyIdentifierStructure(keyPair.getPublic()));

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

    v3CertGen.addExtension(
        X509Extensions.KeyUsage,
        false,
        new KeyUsage(KeyUsage.cRLSign | KeyUsage.keyCertSign));

    DEREncodableVector typicalCAExtendedKeyUsages = new DEREncodableVector();

    typicalCAExtendedKeyUsages.add(new DERObjectIdentifier(ExtendedKeyUsageConstants.serverAuth));
    typicalCAExtendedKeyUsages.add(new DERObjectIdentifier(ExtendedKeyUsageConstants.OCSPSigning));
    typicalCAExtendedKeyUsages.add(new DERObjectIdentifier(
        ExtendedKeyUsageConstants.verisignUnknown));

    v3CertGen.addExtension(
        X509Extensions.ExtendedKeyUsage,
        false,
        new DERSequence(typicalCAExtendedKeyUsages));

    X509Certificate cert = v3CertGen.generate(keyPair.getPrivate(), "BC");

    cert.checkValidity(new Date());

    cert.verify(keyPair.getPublic());

    return cert;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy