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 bctls-jdk14 Show documentation
Show all versions of bctls-jdk14 Show documentation
The Bouncy Castle Java APIs for TLS and DTLS.
The newest version!
package org.bouncycastle.tls;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;
import org.bouncycastle.tls.crypto.TlsCrypto;
import org.bouncycastle.util.Integers;
/**
* 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(Hashtable 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 Hashtable getClientExtensions()
throws IOException
{
Hashtable clientExtensions = new Hashtable();
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
{
}
public void processServerExtensions(Hashtable 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
{
}
}