123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- #pragma warning disable
- using System;
- using System.Collections;
- using System.IO;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
- namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Tls
- {
- /// <summary>Base class for a TLS client.</summary>
- public abstract class AbstractTlsClient
- : AbstractTlsPeer, TlsClient
- {
- protected TlsClientContext m_context;
- protected ProtocolVersion[] m_protocolVersions;
- protected int[] m_cipherSuites;
- protected IList m_supportedGroups;
- protected IList m_supportedSignatureAlgorithms;
- protected IList m_supportedSignatureAlgorithmsCert;
- protected AbstractTlsClient(TlsCrypto crypto)
- : base(crypto)
- {
- }
- /// <exception cref="IOException"/>
- protected virtual bool AllowUnexpectedServerExtension(int extensionType, byte[] extensionData)
- {
- switch (extensionType)
- {
- 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.
- */
- TlsExtensionsUtilities.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.
- */
- TlsExtensionsUtilities.ReadSupportedPointFormatsExtension(extensionData);
- return true;
- default:
- return false;
- }
- }
- protected virtual IList GetNamedGroupRoles()
- {
- IList namedGroupRoles = TlsUtilities.GetNamedGroupRoles(GetCipherSuites());
- IList sigAlgs = m_supportedSignatureAlgorithms, sigAlgsCert = m_supportedSignatureAlgorithmsCert;
- if ((null == sigAlgs || TlsUtilities.ContainsAnySignatureAlgorithm(sigAlgs, SignatureAlgorithm.ecdsa))
- || (null != sigAlgsCert
- && TlsUtilities.ContainsAnySignatureAlgorithm(sigAlgsCert, SignatureAlgorithm.ecdsa)))
- {
- TlsUtilities.AddToSet(namedGroupRoles, NamedGroupRole.ecdsa);
- }
- return namedGroupRoles;
- }
- /// <exception cref="IOException"/>
- protected virtual void CheckForUnexpectedServerExtension(IDictionary serverExtensions, int extensionType)
- {
- byte[] extensionData = TlsUtilities.GetExtensionData(serverExtensions, extensionType);
- if (extensionData != null && !AllowUnexpectedServerExtension(extensionType, extensionData))
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- /// <exception cref="IOException"/>
- public virtual TlsPskIdentity GetPskIdentity()
- {
- return null;
- }
- /// <exception cref="IOException"/>
- public virtual TlsSrpIdentity GetSrpIdentity()
- {
- return null;
- }
- public virtual TlsDHGroupVerifier GetDHGroupVerifier()
- {
- return new DefaultTlsDHGroupVerifier();
- }
- public virtual TlsSrpConfigVerifier GetSrpConfigVerifier()
- {
- return new DefaultTlsSrpConfigVerifier();
- }
- protected virtual IList GetCertificateAuthorities()
- {
- return null;
- }
- protected virtual IList GetProtocolNames()
- {
- return null;
- }
- protected virtual CertificateStatusRequest GetCertificateStatusRequest()
- {
- return new CertificateStatusRequest(CertificateStatusType.ocsp, new OcspStatusRequest(null, null));
- }
- /// <returns>an <see cref="IList"/> of <see cref="CertificateStatusRequestItemV2"/> (or null).</returns>
- protected virtual IList GetMultiCertStatusRequest()
- {
- return null;
- }
- protected virtual IList GetSniServerNames()
- {
- return null;
- }
- /// <summary>The default <see cref="GetClientExtensions"/> implementation calls this to determine which named
- /// groups to include in the supported_groups extension for the ClientHello.</summary>
- /// <param name="namedGroupRoles">The <see cref="NamedGroupRole">named group roles</see> for which there should
- /// be at least one supported group. By default this is inferred from the offered cipher suites and signature
- /// algorithms.</param>
- /// <returns>an <see cref="IList"/> of <see cref="Int32"/>. See <see cref="NamedGroup"/> for group constants.
- /// </returns>
- protected virtual IList GetSupportedGroups(IList namedGroupRoles)
- {
- TlsCrypto crypto = Crypto;
- IList supportedGroups = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList();
- if (namedGroupRoles.Contains(NamedGroupRole.ecdh))
- {
- TlsUtilities.AddIfSupported(supportedGroups, crypto,
- new int[]{ NamedGroup.x25519, NamedGroup.x448 });
- }
- if (namedGroupRoles.Contains(NamedGroupRole.ecdh) ||
- namedGroupRoles.Contains(NamedGroupRole.ecdsa))
- {
- TlsUtilities.AddIfSupported(supportedGroups, crypto,
- new int[]{ NamedGroup.secp256r1, NamedGroup.secp384r1 });
- }
- if (namedGroupRoles.Contains(NamedGroupRole.dh))
- {
- TlsUtilities.AddIfSupported(supportedGroups, crypto,
- new int[]{ NamedGroup.ffdhe2048, NamedGroup.ffdhe3072, NamedGroup.ffdhe4096 });
- }
- return supportedGroups;
- }
- protected virtual IList GetSupportedSignatureAlgorithms()
- {
- return TlsUtilities.GetDefaultSupportedSignatureAlgorithms(m_context);
- }
- protected virtual IList GetSupportedSignatureAlgorithmsCert()
- {
- return null;
- }
- protected virtual IList GetTrustedCAIndication()
- {
- return null;
- }
- public virtual void Init(TlsClientContext context)
- {
- this.m_context = context;
- this.m_protocolVersions = GetSupportedVersions();
- this.m_cipherSuites = GetSupportedCipherSuites();
- }
- public override ProtocolVersion[] GetProtocolVersions()
- {
- return m_protocolVersions;
- }
- public override int[] GetCipherSuites()
- {
- return m_cipherSuites;
- }
- /// <exception cref="IOException"/>
- public override void NotifyHandshakeBeginning()
- {
- base.NotifyHandshakeBeginning();
- this.m_supportedGroups = null;
- this.m_supportedSignatureAlgorithms = null;
- this.m_supportedSignatureAlgorithmsCert = null;
- }
- public virtual TlsSession GetSessionToResume()
- {
- return null;
- }
- public virtual IList GetExternalPsks()
- {
- return null;
- }
- public virtual bool 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;
- }
- /// <exception cref="IOException"/>
- public virtual IDictionary GetClientExtensions()
- {
- IDictionary clientExtensions = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateHashtable();
- bool offeringTlsV13Plus = false;
- bool offeringPreTlsV13 = false;
- {
- ProtocolVersion[] supportedVersions = GetProtocolVersions();
- for (int i = 0; i < supportedVersions.Length; ++i)
- {
- if (TlsUtilities.IsTlsV13(supportedVersions[i]))
- {
- offeringTlsV13Plus = true;
- }
- else
- {
- offeringPreTlsV13 = true;
- }
- }
- }
- IList protocolNames = GetProtocolNames();
- if (protocolNames != null)
- {
- TlsExtensionsUtilities.AddAlpnExtensionClient(clientExtensions, protocolNames);
- }
- IList sniServerNames = GetSniServerNames();
- if (sniServerNames != null)
- {
- TlsExtensionsUtilities.AddServerNameExtensionClient(clientExtensions, sniServerNames);
- }
- CertificateStatusRequest statusRequest = GetCertificateStatusRequest();
- if (statusRequest != null)
- {
- TlsExtensionsUtilities.AddStatusRequestExtension(clientExtensions, statusRequest);
- }
- if (offeringTlsV13Plus)
- {
- IList certificateAuthorities = GetCertificateAuthorities();
- if (certificateAuthorities != null)
- {
- TlsExtensionsUtilities.AddCertificateAuthoritiesExtension(clientExtensions, certificateAuthorities);
- }
- }
- if (offeringPreTlsV13)
- {
- // TODO Shouldn't add if no offered cipher suite uses a block cipher?
- TlsExtensionsUtilities.AddEncryptThenMacExtension(clientExtensions);
- IList statusRequestV2 = GetMultiCertStatusRequest();
- if (statusRequestV2 != null)
- {
- TlsExtensionsUtilities.AddStatusRequestV2Extension(clientExtensions, statusRequestV2);
- }
- IList trustedCAKeys = GetTrustedCAIndication();
- if (trustedCAKeys != null)
- {
- TlsExtensionsUtilities.AddTrustedCAKeysExtensionClient(clientExtensions, trustedCAKeys);
- }
- }
- ProtocolVersion clientVersion = m_context.ClientVersion;
- /*
- * 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 (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
- {
- IList supportedSigAlgs = GetSupportedSignatureAlgorithms();
- if (null != supportedSigAlgs && supportedSigAlgs.Count > 0)
- {
- this.m_supportedSignatureAlgorithms = supportedSigAlgs;
- TlsExtensionsUtilities.AddSignatureAlgorithmsExtension(clientExtensions, supportedSigAlgs);
- }
- IList supportedSigAlgsCert = GetSupportedSignatureAlgorithmsCert();
- if (null != supportedSigAlgsCert && supportedSigAlgsCert.Count > 0)
- {
- this.m_supportedSignatureAlgorithmsCert = supportedSigAlgsCert;
- TlsExtensionsUtilities.AddSignatureAlgorithmsCertExtension(clientExtensions, supportedSigAlgsCert);
- }
- }
- IList namedGroupRoles = GetNamedGroupRoles();
- IList supportedGroups = GetSupportedGroups(namedGroupRoles);
- if (supportedGroups != null && supportedGroups.Count > 0)
- {
- this.m_supportedGroups = supportedGroups;
- TlsExtensionsUtilities.AddSupportedGroupsExtension(clientExtensions, supportedGroups);
- }
- if (offeringPreTlsV13)
- {
- if (namedGroupRoles.Contains(NamedGroupRole.ecdh) ||
- namedGroupRoles.Contains(NamedGroupRole.ecdsa))
- {
- TlsExtensionsUtilities.AddSupportedPointFormatsExtension(clientExtensions,
- new short[]{ ECPointFormat.uncompressed });
- }
- }
- return clientExtensions;
- }
- public virtual IList 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 == m_supportedGroups || m_supportedGroups.Count < 1)
- return null;
- if (m_supportedGroups.Contains(NamedGroup.x25519))
- return TlsUtilities.VectorOfOne(NamedGroup.x25519);
- if (m_supportedGroups.Contains(NamedGroup.secp256r1))
- return TlsUtilities.VectorOfOne(NamedGroup.secp256r1);
- return TlsUtilities.VectorOfOne(m_supportedGroups[0]);
- }
- /// <exception cref="IOException"/>
- public virtual void NotifyServerVersion(ProtocolVersion serverVersion)
- {
- }
- public virtual void NotifySessionToResume(TlsSession session)
- {
- }
- public virtual void NotifySessionID(byte[] sessionID)
- {
- }
- public virtual void NotifySelectedCipherSuite(int selectedCipherSuite)
- {
- }
- /// <exception cref="IOException"/>
- public virtual void NotifySelectedPsk(TlsPsk selectedPsk)
- {
- }
- /// <exception cref="IOException"/>
- public virtual void ProcessServerExtensions(IDictionary serverExtensions)
- {
- if (null == serverExtensions)
- return;
- SecurityParameters securityParameters = m_context.SecurityParameters;
- bool isTlsV13 = TlsUtilities.IsTlsV13(securityParameters.NegotiatedVersion);
- 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, ExtensionType.signature_algorithms);
- CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.signature_algorithms_cert);
- CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.supported_groups);
- int selectedCipherSuite = securityParameters.CipherSuite;
- if (TlsEccUtilities.IsEccCipherSuite(selectedCipherSuite))
- {
- // We only support uncompressed format, this is just to validate the extension, if present.
- TlsExtensionsUtilities.GetSupportedPointFormatsExtension(serverExtensions);
- }
- else
- {
- CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.ec_point_formats);
- }
- /*
- * RFC 7685 3. The server MUST NOT echo the extension.
- */
- CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.padding);
- }
- }
- /// <exception cref="IOException"/>
- public virtual void ProcessServerSupplementalData(IList serverSupplementalData)
- {
- if (serverSupplementalData != null)
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- public abstract TlsAuthentication GetAuthentication();
- /// <exception cref="IOException"/>
- public virtual IList GetClientSupplementalData()
- {
- return null;
- }
- /// <exception cref="IOException"/>
- public virtual void NotifyNewSessionTicket(NewSessionTicket newSessionTicket)
- {
- }
- }
- }
- #pragma warning restore
- #endif
|