
org.littleshoot.proxy.mitm.CertificateSniffingMitmManager Maven / Gradle / Ivy
package org.littleshoot.proxy.mitm;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import org.littleshoot.proxy.MitmManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@link MitmManager} that uses the common name and subject alternative names
* from the upstream certificate to create a dynamic certificate with it.
*/
public class CertificateSniffingMitmManager implements MitmManager {
private static final Logger LOG = LoggerFactory
.getLogger(CertificateSniffingMitmManager.class);
private BouncyCastleSslEngineSource sslEngineSource;
public CertificateSniffingMitmManager() throws RootCertificateException {
this(new Authority());
}
public CertificateSniffingMitmManager(Authority authority)
throws RootCertificateException {
try {
sslEngineSource = new BouncyCastleSslEngineSource(authority, true,
true);
} catch (final Exception e) {
throw new RootCertificateException(
"Errors during assembling root CA.", e);
}
}
public SSLEngine serverSslEngine(String peerHost, int peerPort) {
return sslEngineSource.newSslEngine(peerHost, peerPort);
}
public SSLEngine clientSslEngineFor(SSLSession serverSslSession) {
try {
X509Certificate upstreamCert = getCertificateFromSession(serverSslSession);
// TODO store the upstream cert by commonName to review it later
// A reasons to not use the common name and the alternative names
// from upstream certificate from serverSslSession to create the
// dynamic certificate:
//
// It's not necessary. The host name is accepted by the browser.
//
String commonName = getCommonName(upstreamCert);
SubjectAlternativeNameHolder san = new SubjectAlternativeNameHolder();
san.addAll(upstreamCert.getSubjectAlternativeNames());
LOG.debug("Subject Alternative Names: {}", san);
return sslEngineSource.createCertForHost(commonName, san);
} catch (Exception e) {
throw new FakeCertificateException(
"Creation dynamic certificate failed", e);
}
}
private X509Certificate getCertificateFromSession(SSLSession sslSession)
throws SSLPeerUnverifiedException {
Certificate[] peerCerts = sslSession.getPeerCertificates();
Certificate peerCert = peerCerts[0];
// log.debug("Upstream Certificate: {}", peerCert);
if (peerCert instanceof java.security.cert.X509Certificate) {
return (java.security.cert.X509Certificate) peerCert;
}
throw new IllegalStateException(
"Required java.security.cert.X509Certificate, found: "
+ peerCert);
}
private String getCommonName(X509Certificate c) {
LOG.debug("Subject DN principal name: {}", c.getSubjectDN().getName());
for (String each : c.getSubjectDN().getName().split(",\\s*")) {
if (each.startsWith("CN=")) {
String result = each.substring(3);
LOG.debug("Common Name: {}", result);
return result;
}
}
throw new IllegalStateException("Missed CN in Subject DN: "
+ c.getSubjectDN());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy