org.bouncycastle.tls.AbstractTlsClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of impersonator Show documentation
Show all versions of impersonator Show documentation
Spoof TLS/JA3/JA4 and HTTP/2 fingerprints in Java
package org.bouncycastle.tls;
import org.bouncycastle.tls.crypto.TlsCrypto;
import org.bouncycastle.util.Integers;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Vector;
/**
* Base class for a TLS client.
*/
public abstract class AbstractTlsClient
extends AbstractTlsPeer
implements TlsClient
{
protected TlsClientContext context;
protected ProtocolVersion[] protocolVersions;
protected int[] cipherSuites;
protected Vector supportedGroups;
protected Vector supportedSignatureAlgorithms;
protected Vector supportedSignatureAlgorithmsCert;
public AbstractTlsClient(TlsCrypto crypto)
{
super(crypto);
}
protected boolean allowUnexpectedServerExtension(Integer extensionType, byte[] extensionData)
throws IOException
{
switch (extensionType.intValue())
{
case ExtensionType.supported_groups:
/*
* Exception added based on field reports that some servers do send this, although the
* Supported Elliptic Curves Extension is clearly intended to be client-only. If
* present, we still require that it is a valid EllipticCurveList.
*/
TlsExtensionsUtils.readSupportedGroupsExtension(extensionData);
return true;
case ExtensionType.ec_point_formats:
/*
* Exception added based on field reports that some servers send this even when they
* didn't negotiate an ECC cipher suite. If present, we still require that it is a valid
* ECPointFormatList.
*/
TlsExtensionsUtils.readSupportedPointFormatsExtension(extensionData);
return true;
default:
return false;
}
}
protected Vector getNamedGroupRoles()
{
Vector namedGroupRoles = TlsUtils.getNamedGroupRoles(getCipherSuites());
Vector sigAlgs = supportedSignatureAlgorithms, sigAlgsCert = supportedSignatureAlgorithmsCert;
if ((null == sigAlgs || TlsUtils.containsAnySignatureAlgorithm(sigAlgs, SignatureAlgorithm.ecdsa))
|| (null != sigAlgsCert && TlsUtils.containsAnySignatureAlgorithm(sigAlgsCert, SignatureAlgorithm.ecdsa)))
{
TlsUtils.addToSet(namedGroupRoles, NamedGroupRole.ecdsa);
}
return namedGroupRoles;
}
protected void checkForUnexpectedServerExtension(Map serverExtensions, Integer extensionType)
throws IOException
{
byte[] extensionData = TlsUtils.getExtensionData(serverExtensions, extensionType);
if (extensionData != null && !allowUnexpectedServerExtension(extensionType, extensionData))
{
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
}
/**
* RFC 9146 DTLS connection ID.
*
* The default {@link #getClientExtensions()} implementation calls this to get the connection_id extension the
* client will send. As future communication doesn't include the connection IDs length, this should either
* be fixed-length or include the connection ID's length. (see explanation in RFC 9146 4. "cid:")
* @return The connection ID to use.
*/
protected byte[] getNewConnectionID()
{
return null;
}
public TlsPSKIdentity getPSKIdentity() throws IOException
{
return null;
}
public TlsSRPIdentity getSRPIdentity() throws IOException
{
return null;
}
public TlsDHGroupVerifier getDHGroupVerifier()
{
return new DefaultTlsDHGroupVerifier();
}
public TlsSRPConfigVerifier getSRPConfigVerifier()
{
return new DefaultTlsSRPConfigVerifier();
}
protected Vector getCertificateAuthorities()
{
return null;
}
protected Vector getProtocolNames()
{
return null;
}
protected CertificateStatusRequest getCertificateStatusRequest()
{
return new CertificateStatusRequest(CertificateStatusType.ocsp, new OCSPStatusRequest(null, null));
}
/**
* @return a {@link Vector} of {@link CertificateStatusRequestItemV2} (or null).
*/
protected Vector getMultiCertStatusRequest()
{
return null;
}
protected Vector getSNIServerNames()
{
return null;
}
/**
* The default {@link #getClientExtensions()} implementation calls this to determine which named
* groups to include in the supported_groups extension for the ClientHello.
*
* @param namedGroupRoles
* The {@link NamedGroupRole named group roles} for which there should be at
* least one supported group. By default this is inferred from the offered cipher
* suites and signature algorithms.
* @return a {@link Vector} of {@link Integer}. See {@link NamedGroup} for group constants.
*/
protected Vector getSupportedGroups(Vector namedGroupRoles)
{
TlsCrypto crypto = getCrypto();
Vector supportedGroups = new Vector();
if (namedGroupRoles.contains(Integers.valueOf(NamedGroupRole.ecdh)))
{
TlsUtils.addIfSupported(supportedGroups, crypto,
new int[]{ NamedGroup.x25519, NamedGroup.x448 });
}
if (namedGroupRoles.contains(Integers.valueOf(NamedGroupRole.ecdh)) ||
namedGroupRoles.contains(Integers.valueOf(NamedGroupRole.ecdsa)))
{
TlsUtils.addIfSupported(supportedGroups, crypto,
new int[]{ NamedGroup.secp256r1, NamedGroup.secp384r1 });
}
if (namedGroupRoles.contains(Integers.valueOf(NamedGroupRole.dh)))
{
TlsUtils.addIfSupported(supportedGroups, crypto,
new int[]{ NamedGroup.ffdhe2048, NamedGroup.ffdhe3072, NamedGroup.ffdhe4096 });
}
return supportedGroups;
}
protected Vector getSupportedSignatureAlgorithms()
{
return TlsUtils.getDefaultSupportedSignatureAlgorithms(context);
}
protected Vector getSupportedSignatureAlgorithmsCert()
{
return null;
}
protected Vector getTrustedCAIndication()
{
return null;
}
protected short[] getAllowedClientCertificateTypes()
{
return null;
}
protected short[] getAllowedServerCertificateTypes()
{
return null;
}
public void init(TlsClientContext context)
{
this.context = context;
this.protocolVersions = getSupportedVersions();
this.cipherSuites = getSupportedCipherSuites();
}
public ProtocolVersion[] getProtocolVersions()
{
return protocolVersions;
}
public int[] getCipherSuites()
{
return cipherSuites;
}
public void notifyHandshakeBeginning() throws IOException
{
super.notifyHandshakeBeginning();
this.supportedGroups = null;
this.supportedSignatureAlgorithms = null;
this.supportedSignatureAlgorithmsCert = null;
}
public TlsSession getSessionToResume()
{
return null;
}
public Vector getExternalPSKs()
{
return null;
}
public boolean isFallback()
{
/*
* RFC 7507 4. The TLS_FALLBACK_SCSV cipher suite value is meant for use by clients that
* repeat a connection attempt with a downgraded protocol (perform a "fallback retry") in
* order to work around interoperability problems with legacy servers.
*/
return false;
}
public Map getClientExtensions()
throws IOException
{
Map clientExtensions = new LinkedHashMap<>();
boolean offeringTLSv13Plus = false;
boolean offeringPreTLSv13 = false;
boolean offeringDTLSv12 = false;
{
ProtocolVersion[] supportedVersions = getProtocolVersions();
for (int i = 0; i < supportedVersions.length; ++i)
{
ProtocolVersion supportedVersion = supportedVersions[i];
if (TlsUtils.isTLSv13(supportedVersion))
{
offeringTLSv13Plus = true;
}
else
{
offeringPreTLSv13 = true;
}
offeringDTLSv12 |= ProtocolVersion.DTLSv12.equals(supportedVersion);
}
}
Vector protocolNames = getProtocolNames();
if (protocolNames != null)
{
TlsExtensionsUtils.addALPNExtensionClient(clientExtensions, protocolNames);
}
Vector sniServerNames = getSNIServerNames();
if (sniServerNames != null)
{
TlsExtensionsUtils.addServerNameExtensionClient(clientExtensions, sniServerNames);
}
CertificateStatusRequest statusRequest = getCertificateStatusRequest();
if (statusRequest != null)
{
TlsExtensionsUtils.addStatusRequestExtension(clientExtensions, statusRequest);
}
if (offeringTLSv13Plus)
{
Vector certificateAuthorities = getCertificateAuthorities();
if (certificateAuthorities != null)
{
TlsExtensionsUtils.addCertificateAuthoritiesExtension(clientExtensions, certificateAuthorities);
}
}
if (offeringPreTLSv13)
{
// TODO Shouldn't add if no offered cipher suite uses a block cipher?
TlsExtensionsUtils.addEncryptThenMACExtension(clientExtensions);
Vector statusRequestV2 = getMultiCertStatusRequest();
if (statusRequestV2 != null)
{
TlsExtensionsUtils.addStatusRequestV2Extension(clientExtensions, statusRequestV2);
}
Vector trustedCAKeys = getTrustedCAIndication();
if (trustedCAKeys != null)
{
TlsExtensionsUtils.addTrustedCAKeysExtensionClient(clientExtensions, trustedCAKeys);
}
}
ProtocolVersion clientVersion = context.getClientVersion();
/*
* RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior to 1.2.
* Clients MUST NOT offer it if they are offering prior versions.
*/
if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(clientVersion))
{
Vector supportedSigAlgs = getSupportedSignatureAlgorithms();
if (null != supportedSigAlgs && !supportedSigAlgs.isEmpty())
{
this.supportedSignatureAlgorithms = supportedSigAlgs;
TlsExtensionsUtils.addSignatureAlgorithmsExtension(clientExtensions, supportedSigAlgs);
}
Vector supportedSigAlgsCert = getSupportedSignatureAlgorithmsCert();
if (null != supportedSigAlgsCert && !supportedSigAlgsCert.isEmpty())
{
this.supportedSignatureAlgorithmsCert = supportedSigAlgsCert;
TlsExtensionsUtils.addSignatureAlgorithmsCertExtension(clientExtensions, supportedSigAlgsCert);
}
}
Vector namedGroupRoles = getNamedGroupRoles();
Vector supportedGroups = getSupportedGroups(namedGroupRoles);
if (supportedGroups != null && !supportedGroups.isEmpty())
{
this.supportedGroups = supportedGroups;
TlsExtensionsUtils.addSupportedGroupsExtension(clientExtensions, supportedGroups);
}
if (offeringPreTLSv13)
{
if (namedGroupRoles.contains(Integers.valueOf(NamedGroupRole.ecdh))
|| namedGroupRoles.contains(Integers.valueOf(NamedGroupRole.ecdsa)))
{
TlsExtensionsUtils.addSupportedPointFormatsExtension(clientExtensions, new short[]{ ECPointFormat.uncompressed });
}
}
{
/*
* RFC 7250 4.1. If the client has no remaining certificate types to send in the client hello, other than
* the default X.509 type, it MUST omit the client_certificate_type extension [..].
*/
short[] clientCertTypes = getAllowedClientCertificateTypes();
if (clientCertTypes != null &&
TlsUtils.containsNot(clientCertTypes, 0, clientCertTypes.length, CertificateType.X509))
{
TlsExtensionsUtils.addClientCertificateTypeExtensionClient(clientExtensions, clientCertTypes);
}
}
{
/*
* RFC 7250 4.1. If the client has no remaining certificate types to send in the client hello, other than
* the default X.509 certificate type, it MUST omit the entire server_certificate_type extension [..].
*/
short[] serverCertTypes = getAllowedServerCertificateTypes();
if (serverCertTypes != null &&
TlsUtils.containsNot(serverCertTypes, 0, serverCertTypes.length, CertificateType.X509))
{
TlsExtensionsUtils.addServerCertificateTypeExtensionClient(clientExtensions, serverCertTypes);
}
}
if (offeringDTLSv12)
{
/*
* RFC 9146 3. When a DTLS session is resumed or renegotiated, the "connection_id" extension is
* negotiated afresh.
*/
byte[] clientConnectionID = getNewConnectionID();
if (clientConnectionID != null)
{
TlsExtensionsUtils.addConnectionIDExtension(clientExtensions, clientConnectionID);
}
}
return clientExtensions;
}
public Vector getEarlyKeyShareGroups()
{
/*
* RFC 8446 4.2.8. Each KeyShareEntry value MUST correspond to a group offered in the
* "supported_groups" extension and MUST appear in the same order. However, the values MAY
* be a non-contiguous subset of the "supported_groups" extension and MAY omit the most
* preferred groups.
*/
if (null == supportedGroups || supportedGroups.isEmpty())
{
return null;
}
if (supportedGroups.contains(Integers.valueOf(NamedGroup.x25519)))
{
return TlsUtils.vectorOfOne(Integers.valueOf(NamedGroup.x25519));
}
if (supportedGroups.contains(Integers.valueOf(NamedGroup.secp256r1)))
{
return TlsUtils.vectorOfOne(Integers.valueOf(NamedGroup.secp256r1));
}
return TlsUtils.vectorOfOne(supportedGroups.elementAt(0));
}
public boolean shouldUseCompatibilityMode()
{
return true;
}
public void notifyServerVersion(ProtocolVersion serverVersion)
throws IOException
{
}
public void notifySessionToResume(TlsSession session)
{
}
public void notifySessionID(byte[] sessionID)
{
}
public void notifySelectedCipherSuite(int selectedCipherSuite)
{
}
public void notifySelectedPSK(TlsPSK selectedPSK) throws IOException
{
}
@Override
public void processServerExtensions(Map serverExtensions)
throws IOException
{
if (null == serverExtensions)
{
return;
}
SecurityParameters securityParameters = context.getSecurityParametersHandshake();
boolean isTLSv13 = TlsUtils.isTLSv13(securityParameters.getNegotiatedVersion());
if (isTLSv13)
{
/*
* NOTE: From TLS 1.3 the protocol classes are strict about what extensions can appear.
*/
}
else
{
/*
* RFC 5246 7.4.1.4.1. Servers MUST NOT send this extension.
*/
checkForUnexpectedServerExtension(serverExtensions, TlsExtensionsUtils.EXT_signature_algorithms);
checkForUnexpectedServerExtension(serverExtensions, TlsExtensionsUtils.EXT_signature_algorithms_cert);
checkForUnexpectedServerExtension(serverExtensions, TlsExtensionsUtils.EXT_supported_groups);
int selectedCipherSuite = securityParameters.getCipherSuite();
if (TlsECCUtils.isECCCipherSuite(selectedCipherSuite))
{
// We only support uncompressed format, this is just to validate the extension, if present.
TlsExtensionsUtils.getSupportedPointFormatsExtension(serverExtensions);
}
else
{
checkForUnexpectedServerExtension(serverExtensions, TlsExtensionsUtils.EXT_ec_point_formats);
}
/*
* RFC 7685 3. The server MUST NOT echo the extension.
*/
checkForUnexpectedServerExtension(serverExtensions, TlsExtensionsUtils.EXT_padding);
}
}
public void processServerSupplementalData(Vector serverSupplementalData)
throws IOException
{
if (serverSupplementalData != null)
{
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
}
public Vector getClientSupplementalData()
throws IOException
{
return null;
}
public void notifyNewSessionTicket(NewSessionTicket newSessionTicket)
throws IOException
{
}
}