All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.tls.AbstractTlsClient Maven / Gradle / Ivy

Go to download

The Bouncy Castle Java APIs for the TLS, including a JSSE provider. The APIs are designed primarily to be used in conjunction with the BC LTS provider but may also be used with other providers providing cryptographic services.

There is a newer version: 2.73.7
Show 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 { } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy