package net.lightbody.bmp.mitm; import com.google.common.collect.ObjectArrays; import com.google.common.io.Files; import net.lightbody.bmp.mitm.exception.UncheckedIOException; import net.lightbody.bmp.mitm.util.TrustUtil; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.KeyStore; import java.security.cert.X509Certificate; import java.util.List; /** * A source of trusted root certificate authorities. Provides static methods to obtain default trust sources: *
* TrustSource customTrustSource = TrustSource.empty()
* .add(myX509Certificate)
* .add(pemFileContainingMyCA)
* .add(javaKeyStore);
*
*
* Note: This class is immutable, so calls to add() will return a new instance, rather than modifying the existing instance.
*/
public class TrustSource {
/**
* The default TrustSource. To obtain this TrustSource, use {@link #defaultTrustSource()}.
*/
private static final TrustSource DEFAULT_TRUST_SOURCE = TrustSource.javaTrustSource().add(TrustSource.builtinTrustSource());
/**
* The root CAs this TrustSource trusts.
*/
private final X509Certificate[] trustedCAs;
/**
* Creates a TrustSource that contains no trusted certificates. For public use, see {@link #empty()}.
*/
protected TrustSource() {
this(TrustUtil.EMPTY_CERTIFICATE_ARRAY);
}
/**
* Creates a TrustSource that considers only the specified certificates as "trusted". For public use,
* use {@link #empty()} followed by {@link #add(X509Certificate...)}.
*
* @param trustedCAs root CAs to trust
*/
protected TrustSource(X509Certificate... trustedCAs) {
if (trustedCAs == null) {
this.trustedCAs = TrustUtil.EMPTY_CERTIFICATE_ARRAY;
} else {
this.trustedCAs = trustedCAs;
}
}
/**
* Returns the X509 certificates considered "trusted" by this TrustSource. This method will not return null, but
* may return an empty array.
*/
public X509Certificate[] getTrustedCAs() {
return trustedCAs;
}
/**
* Returns a TrustSource that contains no trusted CAs. Can be used in conjunction with the add() methods to build
* a TrustSource containing custom CAs from a variety of sources (PEM files, KeyStores, etc.).
*/
public static TrustSource empty() {
return new TrustSource();
}
/**
* Returns a TrustSource containing the default trusted CAs. By default, contains both the JVM's trusted CAs and the
* built-in trusted CAs (Firefox's trusted CAs).
*/
public static TrustSource defaultTrustSource() {
return DEFAULT_TRUST_SOURCE;
}
/**
* Returns a TrustSource containing only the builtin trusted CAs and does not include the JVM's trusted CAs.
* See {@link TrustUtil#getBuiltinTrustedCAs()}.
*/
public static TrustSource builtinTrustSource() {
return new TrustSource(TrustUtil.getBuiltinTrustedCAs());
}
/**
* Returns a TrustSource containing the default CAs trusted by this JVM. See {@link TrustUtil#getJavaTrustedCAs()}.
*/
public static TrustSource javaTrustSource() {
return new TrustSource(TrustUtil.getJavaTrustedCAs());
}
/**
* Returns a new TrustSource containing the same trusted CAs as this TrustSource, plus zero or more CAs contained in
* the PEM-encoded String. The String may contain multiple certificates and may contain comments or other non-PEM-encoded
* text, as long as the PEM-encoded certificates are delimited by appropriate BEGIN_CERTIFICATE and END_CERTIFICATE
* text blocks.
*
* @param trustedPemEncodedCAs String containing PEM-encoded certificates to trust
* @return a new TrustSource containing this TrustSource's trusted CAs plus the CAs in the specified String
*/
public TrustSource add(String trustedPemEncodedCAs) {
if (trustedPemEncodedCAs == null) {
throw new IllegalArgumentException("PEM-encoded trusted CA String cannot be null");
}
X509Certificate[] trustedCertificates = TrustUtil.readX509CertificatesFromPem(trustedPemEncodedCAs);
return add(trustedCertificates);
}
/**
* Returns a new TrustSource containing the same trusted CAs as this TrustSource, plus zero or more additional
* trusted X509Certificates. If trustedCertificates is null or empty, returns this same TrustSource.
*
* @param trustedCertificates X509Certificates of CAs to trust
* @return a new TrustSource containing this TrustSource's trusted CAs plus the specified CAs
*/
public TrustSource add(X509Certificate... trustedCertificates) {
if (trustedCertificates == null || trustedCertificates.length == 0) {
return this;
}
X509Certificate[] newTrustedCAs = ObjectArrays.concat(trustedCAs, trustedCertificates, X509Certificate.class);
return new TrustSource(newTrustedCAs);
}
/**
* Returns a new TrustSource containing the same trusted CAs as this TrustSource, plus all trusted certificate
* entries from the specified trustStore. This method will only add trusted certificate entries from the specified
* KeyStore (i.e. entries of type {@link java.security.KeyStore.TrustedCertificateEntry}; private keys will be
* ignored. The trustStore may be in JKS or PKCS12 format.
*
* @param trustStore keystore containing trusted certificate entries
* @return a new TrustSource containing this TrustSource's trusted CAs plus trusted certificate entries from the keystore
*/
public TrustSource add(KeyStore trustStore) {
if (trustStore == null) {
throw new IllegalArgumentException("Trust store cannot be null");
}
List