<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.1" />

AbstractTlsContext

abstract class AbstractTlsContext : TlsContext
using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Tls.Crypto; using Org.BouncyCastle.Utilities; using System; using System.Threading; namespace Org.BouncyCastle.Tls { internal abstract class AbstractTlsContext : TlsContext { private static long counter = DateTime.UtcNow.Ticks; private readonly TlsCrypto m_crypto; private readonly int m_connectionEnd; private readonly TlsNonceGenerator m_nonceGenerator; private SecurityParameters m_securityParameters; private ProtocolVersion[] m_clientSupportedVersions; private ProtocolVersion m_clientVersion; private ProtocolVersion m_rsaPreMasterSecretVersion; private TlsSession m_session; private object m_userObject; private bool m_connected; internal bool IsConnected { get { lock (this) { return m_connected; } } } internal bool IsHandshaking { get { lock (this) { return !m_connected && m_securityParameters != null; } } } public TlsCrypto Crypto => m_crypto; public virtual TlsNonceGenerator NonceGenerator => m_nonceGenerator; public SecurityParameters SecurityParameters { get { lock (this) { return m_securityParameters; } } } public abstract bool IsServer { get; } public virtual ProtocolVersion[] ClientSupportedVersions => m_clientSupportedVersions; public virtual ProtocolVersion ClientVersion => m_clientVersion; public virtual ProtocolVersion RsaPreMasterSecretVersion => m_rsaPreMasterSecretVersion; public virtual ProtocolVersion ServerVersion => SecurityParameters.NegotiatedVersion; public virtual TlsSession ResumableSession { get { TlsSession session = Session; if (session == null || !session.IsResumable) return null; return session; } } public virtual TlsSession Session => m_session; public virtual object UserObject { get { return m_userObject; } set { m_userObject = value; } } private static long NextCounterValue() { return Interlocked.Increment(ref counter); } private unsafe static TlsNonceGenerator CreateNonceGenerator(TlsCrypto crypto, int connectionEnd) { Span<byte> span = new Span<byte>(stackalloc byte[16], 16); Pack.UInt64_To_BE((ulong)NextCounterValue(), span); Pack.UInt64_To_BE((ulong)DateTime.UtcNow.Ticks, span.Slice(8, span.Length - 8)); span[0] &= 127; span[0] |= (byte)(connectionEnd << 7); return crypto.CreateNonceGenerator(span); } internal AbstractTlsContext(TlsCrypto crypto, int connectionEnd) { m_crypto = crypto; m_connectionEnd = connectionEnd; m_nonceGenerator = CreateNonceGenerator(crypto, connectionEnd); } internal void HandshakeBeginning(TlsPeer peer) { lock (this) { if (m_securityParameters != null) throw new TlsFatalAlert(80, "Handshake already started"); m_securityParameters = new SecurityParameters(); m_securityParameters.m_entity = m_connectionEnd; } peer.NotifyHandshakeBeginning(); } internal void HandshakeComplete(TlsPeer peer, TlsSession session) { lock (this) { if (m_securityParameters == null) throw new TlsFatalAlert(80); m_session = session; m_connected = true; } peer.NotifyHandshakeComplete(); } internal void SetClientSupportedVersions(ProtocolVersion[] clientSupportedVersions) { m_clientSupportedVersions = clientSupportedVersions; } internal void SetClientVersion(ProtocolVersion clientVersion) { m_clientVersion = clientVersion; } internal void SetRsaPreMasterSecretVersion(ProtocolVersion rsaPreMasterSecretVersion) { m_rsaPreMasterSecretVersion = rsaPreMasterSecretVersion; } public virtual byte[] ExportChannelBinding(int channelBinding) { if (!IsConnected) throw new InvalidOperationException("Export of channel bindings unavailable before handshake completion"); SecurityParameters securityParameters = SecurityParameters; if (3 == channelBinding) return ExportKeyingMaterial("EXPORTER-Channel-Binding", TlsUtilities.EmptyBytes, 32); if (!TlsUtilities.IsTlsV13(securityParameters.NegotiatedVersion)) { switch (channelBinding) { case 0: { byte[] tlsServerEndPoint = securityParameters.TlsServerEndPoint; if (!TlsUtilities.IsNullOrEmpty(tlsServerEndPoint)) return Arrays.Clone(tlsServerEndPoint); return null; } case 1: return Arrays.Clone(securityParameters.TlsUnique); default: throw new NotSupportedException(); } } return null; } public virtual byte[] ExportEarlyKeyingMaterial(string asciiLabel, byte[] context, int length) { if (!IsConnected) throw new InvalidOperationException("Export of early key material only available during handshake"); SecurityParameters securityParameters = SecurityParameters; return ExportKeyingMaterial13(CheckEarlyExportSecret(securityParameters.EarlyExporterMasterSecret), securityParameters.PrfCryptoHashAlgorithm, asciiLabel, context, length); } public virtual byte[] ExportKeyingMaterial(string asciiLabel, byte[] context, int length) { if (!IsConnected) throw new InvalidOperationException("Export of key material unavailable before handshake completion"); SecurityParameters securityParameters = SecurityParameters; if (!securityParameters.IsExtendedMasterSecret) throw new InvalidOperationException("Export of key material requires extended_master_secret"); if (TlsUtilities.IsTlsV13(securityParameters.NegotiatedVersion)) return ExportKeyingMaterial13(CheckExportSecret(securityParameters.ExporterMasterSecret), securityParameters.PrfCryptoHashAlgorithm, asciiLabel, context, length); byte[] seed = TlsUtilities.CalculateExporterSeed(securityParameters, context); return TlsUtilities.Prf(securityParameters, CheckExportSecret(securityParameters.MasterSecret), asciiLabel, seed, length).Extract(); } protected virtual byte[] ExportKeyingMaterial13(TlsSecret secret, int cryptoHashAlgorithm, string asciiLabel, byte[] context, int length) { if (context == null) context = TlsUtilities.EmptyBytes; else if (!TlsUtilities.IsValidUint16(context.Length)) { throw new ArgumentException("must have length less than 2^16 (or be null)", "context"); } TlsHash tlsHash = Crypto.CreateHash(cryptoHashAlgorithm); byte[] array = tlsHash.CalculateHash(); TlsSecret secret2 = TlsUtilities.DeriveSecret(SecurityParameters, secret, asciiLabel, array); byte[] context2 = array; if (context.Length != 0) { tlsHash.Update(context, 0, context.Length); context2 = tlsHash.CalculateHash(); } return TlsCryptoUtilities.HkdfExpandLabel(secret2, cryptoHashAlgorithm, "exporter", context2, length).Extract(); } protected virtual TlsSecret CheckEarlyExportSecret(TlsSecret secret) { if (secret == null) throw new InvalidOperationException("Export of early key material not available for this handshake"); return secret; } protected virtual TlsSecret CheckExportSecret(TlsSecret secret) { if (secret == null) throw new InvalidOperationException("Export of key material only available from NotifyHandshakeComplete()"); return secret; } } }