From 87199bff784ac4be9b00eed31b4d2d687aedf924 Mon Sep 17 00:00:00 2001 From: Jason Eric Klaes Hoetger Date: Sun, 3 Jan 2016 12:44:44 -0800 Subject: [PATCH] Replaced legacy ProxyServer's server certificate generation with equivalent from MITM module in order to remove legacy ProxyServer dependency on ancient version of Bouncy Castle. --- browsermob-core/pom.xml | 20 - .../proxy/selenium/CertificateCreator.java | 411 ------------------ .../bmp/proxy/selenium/KeyStoreManager.java | 243 ++--------- .../selenium/ServerCertificateCreator.java | 46 ++ .../bmp/mitm/RootCertificateGenerator.java | 2 +- 5 files changed, 86 insertions(+), 636 deletions(-) delete mode 100644 browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/CertificateCreator.java create mode 100644 browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/ServerCertificateCreator.java diff --git a/browsermob-core/pom.xml b/browsermob-core/pom.xml index b6ab59b31..35fefc957 100644 --- a/browsermob-core/pom.xml +++ b/browsermob-core/pom.xml @@ -144,12 +144,6 @@ 2.5 - - org.bouncycastle - bcprov-jdk15on - 1.47 - - dnsjava dnsjava @@ -183,20 +177,6 @@ net.lightbody.bmp mitm ${project.version} - - - net.lightbody.bmp - littleproxy - - - org.bouncycastle - bcprov-jdk15on - - - org.bouncycastle - bcpkix-jdk15on - - diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/CertificateCreator.java b/browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/CertificateCreator.java deleted file mode 100644 index 53b7aaa63..000000000 --- a/browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/CertificateCreator.java +++ /dev/null @@ -1,411 +0,0 @@ -package net.lightbody.bmp.proxy.selenium; - -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.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 javax.security.auth.x500.X500Principal; -import java.math.BigInteger; -import java.security.*; -import java.security.cert.*; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; - -/** - * 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", "unused" }) - public static X509Certificate generateStdSSLServerCertificate( - final PublicKey newPubKey, - final X509Certificate caCert, - final PrivateKey caPrivateKey, - final String subject) - 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); - v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + 30L * 60 * 60 * 24 * 30 * 12)); - 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"))); - -// v3CertGen.addExtension( -// X509Extensions.CRLDistributionPoints, -// false, -// new CRLDistPoint(new DistributionPoint[] {})); - - - - 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. - * @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) - throws CertificateParsingException, - SignatureException, - InvalidKeyException, - CertificateException, - NoSuchAlgorithmException, - NoSuchProviderException - { - if(extensionOidsNotToCopy == null) - { - extensionOidsNotToCopy = new HashSet(); - } - - 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)) { - 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)){ - v3CertGen.copyAndAddExtension(new DERObjectIdentifier(oid), false, originalCert); - } - } - } - - 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); - } - - /** - * 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() + 240 /* 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; - } - -} diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/KeyStoreManager.java b/browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/KeyStoreManager.java index 96c332969..06871d5bf 100644 --- a/browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/KeyStoreManager.java +++ b/browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/KeyStoreManager.java @@ -1,12 +1,35 @@ package net.lightbody.bmp.proxy.selenium; +import net.lightbody.bmp.mitm.keys.RSAKeyGenerator; import net.lightbody.bmp.proxy.jetty.log.LogFactory; import org.apache.commons.logging.Log; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import java.io.*; -import java.security.*; -import java.security.cert.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.security.InvalidKeyException; +import java.security.KeyPair; +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.SignatureException; +import java.security.UnrecoverableEntryException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateEncodingException; +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.HashMap; /** @@ -49,20 +72,13 @@ public class KeyStoreManager { private HashMap _rememberedPrivateKeys; private HashMap _mappedPublicKeys; private HashMap _certMap; - private HashMap _subjectMap; + private HashMap hostnameThumbprintMap; private final String KEYMAP_SER_FILE = "keymap.ser"; private final String PUB_KEYMAP_SER_FILE = "pubkeymap.ser"; public final String RSA_KEYGEN_ALGO = "RSA"; public final String DSA_KEYGEN_ALGO = "DSA"; - public final KeyPairGenerator _rsaKpg; - public final KeyPairGenerator _dsaKpg; - - private SecureRandom _sr; - - - private boolean persistImmediately = true; private File root; @@ -71,20 +87,6 @@ public class KeyStoreManager { public KeyStoreManager(File root) { this.root = root; - Security.insertProviderAt(new BouncyCastleProvider(), 2); - - _sr = new SecureRandom(); - - try - { - _rsaKpg = KeyPairGenerator.getInstance(RSA_KEYGEN_ALGO); - _dsaKpg = KeyPairGenerator.getInstance(DSA_KEYGEN_ALGO); - } - catch(Throwable t) - { - throw new Error(t); - } - try { File privKeys = new File(root, KEYMAP_SER_FILE); @@ -132,15 +134,9 @@ public KeyStoreManager(File root) { throw new Error(e); } - - - _rsaKpg.initialize(1024, _sr); - _dsaKpg.initialize(1024, _sr); - - try { - _ks = KeyStore.getInstance("PKCS12", "SunJSSE"); + _ks = KeyStore.getInstance("PKCS12"); reloadKeystore(); } @@ -197,13 +193,13 @@ public KeyStoreManager(File root) { if(!file.exists()) { - _subjectMap = new HashMap(); + hostnameThumbprintMap = new HashMap(); } else { ObjectInputStream in = new ObjectInputStream(new FileInputStream(file)); // Deserialize the object - _subjectMap = (HashMap)in.readObject(); + hostnameThumbprintMap = (HashMap)in.readObject(); in.close(); } @@ -237,43 +233,9 @@ private void reloadKeystore() throws FileNotFoundException, IOException, NoSuchA * Creates, writes and loads a new keystore and CA root certificate. */ protected void createKeystore() { - - java.security.cert.Certificate signingCert = null; - PrivateKey caPrivKey = null; - if(_caCert == null || _caPrivKey == null) { - try - { - log.debug("Keystore or signing cert & keypair not found. Generating..."); - - KeyPair caKeypair = getRSAKeyPair(); - caPrivKey = caKeypair.getPrivate(); - signingCert = CertificateCreator.createTypicalMasterCert(caKeypair); - - log.debug("Done generating signing cert"); - log.debug(signingCert); - - _ks.load(null, _keystorepass); - - _ks.setKeyEntry(_caPrivKeyAlias, caPrivKey, _keypassword, new java.security.cert.Certificate[] {signingCert}); - - File caKsFile = new File(root, _caPrivateKeystore); - - OutputStream os = new FileOutputStream(caKsFile); - _ks.store(os, _keystorepass); - - log.debug("Wrote keystore to: " + - caKsFile.getAbsolutePath()); - - _caCert = (X509Certificate)signingCert; - _caPrivKey = caPrivKey; - } - catch(Exception e) - { - log.error("Fatal error creating/storing keystore or signing cert.", e); - throw new Error(e); - } + throw new RuntimeException("Legacy ProxyServer implementation does not support dynamic CA generation"); } else { @@ -348,7 +310,6 @@ public synchronized X509Certificate getCertificateByAlias(final String alias) th /** * Returns the aliased certificate. Certificates are aliased by their hostname. * @see ThumbprintUtil - * @param alias * @return * @throws KeyStoreException * @throws UnrecoverableKeyException @@ -363,7 +324,7 @@ public synchronized X509Certificate getCertificateByAlias(final String alias) th */ public synchronized X509Certificate getCertificateByHostname(final String hostname) throws KeyStoreException, CertificateParsingException, InvalidKeyException, CertificateExpiredException, CertificateNotYetValidException, SignatureException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException, UnrecoverableKeyException{ - String alias = _subjectMap.get(getSubjectForHostname(hostname)); + String alias = hostnameThumbprintMap.get(hostname); if(alias != null) { return (X509Certificate)_ks.getCertificate(alias); @@ -409,99 +370,6 @@ public void setPersistImmediately(final boolean persistImmediately) { this.persistImmediately = persistImmediately; } - /** - * This method returns the duplicated certificate mapped to the passed in cert, or - * creates and returns one if no mapping has yet been performed. If a naked public - * key has already been mapped that matches the key in the cert, the already mapped - * keypair will be reused for the mapped cert. - * @param cert - * @return - * @throws CertificateEncodingException - * @throws InvalidKeyException - * @throws CertificateException - * @throws CertificateNotYetValidException - * @throws NoSuchAlgorithmException - * @throws NoSuchProviderException - * @throws SignatureException - * @throws KeyStoreException - * @throws UnrecoverableKeyException - */ - public synchronized X509Certificate getMappedCertificate(final X509Certificate cert) - throws CertificateEncodingException, - InvalidKeyException, - CertificateException, - CertificateNotYetValidException, - NoSuchAlgorithmException, - NoSuchProviderException, - SignatureException, - KeyStoreException, - UnrecoverableKeyException - { - - String thumbprint = ThumbprintUtil.getThumbprint(cert); - - String mappedCertThumbprint = _certMap.get(thumbprint); - - if(mappedCertThumbprint == null) - { - - // Check if we've already mapped this public key from a KeyValue - PublicKey mappedPk = getMappedPublicKey(cert.getPublicKey()); - PrivateKey privKey; - - if(mappedPk == null) - { - PublicKey pk = cert.getPublicKey(); - - String algo = pk.getAlgorithm(); - - KeyPair kp; - - if(algo.equals("RSA")) { - kp = getRSAKeyPair(); - } - else if(algo.equals("DSA")) { - kp = getDSAKeyPair(); - } - else - { - throw new InvalidKeyException("Key algorithm " + algo + " not supported."); - } - mappedPk = kp.getPublic(); - privKey = kp.getPrivate(); - - mapPublicKeys(cert.getPublicKey(), mappedPk); - } - else - { - privKey = getPrivateKey(mappedPk); - } - - - X509Certificate replacementCert = - CertificateCreator.mitmDuplicateCertificate( - cert, - mappedPk, - getSigningCert(), - getSigningPrivateKey()); - - addCertAndPrivateKey(null, replacementCert, privKey); - - mappedCertThumbprint = ThumbprintUtil.getThumbprint(replacementCert); - - _certMap.put(thumbprint, mappedCertThumbprint); - _certMap.put(mappedCertThumbprint, thumbprint); - _subjectMap.put(replacementCert.getSubjectX500Principal().getName(), thumbprint); - - if(persistImmediately) { - persist(); - } - return replacementCert; - } - return getCertificateByAlias(mappedCertThumbprint); - - } - /** * This method returns the mapped certificate for a hostname, or generates a "standard" * SSL server certificate issued by the CA to the supplied subject if no mapping has been @@ -523,24 +391,22 @@ else if(algo.equals("DSA")) { */ public X509Certificate getMappedCertificateForHostname(String hostname) throws CertificateParsingException, InvalidKeyException, CertificateExpiredException, CertificateNotYetValidException, SignatureException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException, KeyStoreException, UnrecoverableKeyException { - String subject = getSubjectForHostname(hostname); - - String thumbprint = _subjectMap.get(subject); + String thumbprint = hostnameThumbprintMap.get(hostname); if(thumbprint == null) { - KeyPair kp = getRSAKeyPair(); + KeyPair kp = new RSAKeyGenerator().generate(); - X509Certificate newCert = CertificateCreator.generateStdSSLServerCertificate(kp.getPublic(), + X509Certificate newCert = ServerCertificateCreator.generateStdSSLServerCertificate(kp, getSigningCert(), getSigningPrivateKey(), - subject); + hostname); addCertAndPrivateKey(hostname, newCert, kp.getPrivate()); thumbprint = ThumbprintUtil.getThumbprint(newCert); - _subjectMap.put(subject, thumbprint); + hostnameThumbprintMap.put(hostname, thumbprint); if(persistImmediately) { persist(); @@ -554,11 +420,6 @@ public X509Certificate getMappedCertificateForHostname(String hostname) throws C } - private String getSubjectForHostname(String hostname) { - String subject = "CN=" + hostname + ", OU=BrowserMob Proxy, O=Impersonated Certificate, L=Seattle, S=Washington, C=US"; - return subject; - } - private synchronized void persistCertMap() { try { ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File(root, CERTMAP_SER_FILE))); @@ -580,7 +441,7 @@ private synchronized void persistCertMap() { private synchronized void persistSubjectMap() { try { ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File(root, SUBJMAP_SER_FILE))); - out.writeObject(_subjectMap); + out.writeObject(hostnameThumbprintMap); out.flush(); out.close(); } catch (FileNotFoundException e) { @@ -612,31 +473,6 @@ public synchronized PrivateKey getPrivateKeyForLocalCert(final X509Certificate c return (PrivateKey)_ks.getKey(thumbprint, _keypassword); } - - /** - * Generate an RSA Key Pair - * @return - */ - public KeyPair getRSAKeyPair() - { - KeyPair kp = _rsaKpg.generateKeyPair(); - rememberKeyPair(kp); - return kp; - - } - - /** - * Generate a DSA Key Pair - * @return - */ - public KeyPair getDSAKeyPair() - { - KeyPair kp = _dsaKpg.generateKeyPair(); - rememberKeyPair(kp); - return kp; - } - - private synchronized void persistPublicKeyMap() { try { ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File(root, PUB_KEYMAP_SER_FILE))); @@ -691,7 +527,6 @@ public synchronized void mapPublicKeys(final PublicKey original, final PublicKey * later see an X509Data with the same public key, we shouldn't split this * in our MITM impl. So when creating a new cert, we should check if we've already * assigned a substitute key and re-use it, and vice-versa. - * @param pk * @return */ public synchronized PublicKey getMappedPublicKey(final PublicKey original) diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/ServerCertificateCreator.java b/browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/ServerCertificateCreator.java new file mode 100644 index 000000000..de5dd0358 --- /dev/null +++ b/browsermob-core/src/main/java/net/lightbody/bmp/proxy/selenium/ServerCertificateCreator.java @@ -0,0 +1,46 @@ +package net.lightbody.bmp.proxy.selenium; + +import net.lightbody.bmp.mitm.CertificateAndKey; +import net.lightbody.bmp.mitm.CertificateInfo; +import net.lightbody.bmp.mitm.CertificateInfoGenerator; +import net.lightbody.bmp.mitm.HostnameCertificateInfoGenerator; +import net.lightbody.bmp.mitm.tools.DefaultSecurityProviderTool; +import net.lightbody.bmp.mitm.tools.SecurityProviderTool; +import net.lightbody.bmp.mitm.util.MitmConstants; + +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.Collections; + +/** + * Utility to create server certificates for legacy {@link net.lightbody.bmp.proxy.ProxyServer} MITM. + */ +public class ServerCertificateCreator { + /** + * Use the default hostname-impersonating certificate info generator that the MITM module provides. + */ + private static final CertificateInfoGenerator CERT_INFO_GENERATOR = new HostnameCertificateInfoGenerator(); + + /** + * Use the default (JDK where available, otherwise BC) security provider to generate certificates. + */ + private static final SecurityProviderTool SECURITY_PROVIDER = new DefaultSecurityProviderTool(); + + public static X509Certificate generateStdSSLServerCertificate( + KeyPair newPublicAndPrivateKey, + X509Certificate caCert, + PrivateKey caPrivateKey, + String hostname) { + CertificateInfo certificateInfo = CERT_INFO_GENERATOR.generate(Collections.singletonList(hostname), null); + + CertificateAndKey newServerCert = SECURITY_PROVIDER.createServerCertificate( + certificateInfo, + caCert, + caPrivateKey, + newPublicAndPrivateKey, + MitmConstants.DEFAULT_MESSAGE_DIGEST); + + return newServerCert.getCertificate(); + } +} diff --git a/mitm/src/main/java/net/lightbody/bmp/mitm/RootCertificateGenerator.java b/mitm/src/main/java/net/lightbody/bmp/mitm/RootCertificateGenerator.java index 5f1877c4c..b7baa8e0c 100644 --- a/mitm/src/main/java/net/lightbody/bmp/mitm/RootCertificateGenerator.java +++ b/mitm/src/main/java/net/lightbody/bmp/mitm/RootCertificateGenerator.java @@ -2,9 +2,9 @@ import com.google.common.base.Supplier; import com.google.common.base.Suppliers; -import net.lightbody.bmp.mitm.tools.DefaultSecurityProviderTool; import net.lightbody.bmp.mitm.keys.KeyGenerator; import net.lightbody.bmp.mitm.keys.RSAKeyGenerator; +import net.lightbody.bmp.mitm.tools.DefaultSecurityProviderTool; import net.lightbody.bmp.mitm.tools.SecurityProviderTool; import net.lightbody.bmp.mitm.util.EncryptionUtil; import net.lightbody.bmp.mitm.util.MitmConstants;