using System; using System.Collections; using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Macs; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Date; using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Crypto.Tls; public abstract class TlsUtilities { public static readonly byte[] EmptyBytes = new byte[0]; public static readonly short[] EmptyShorts = new short[0]; public static readonly int[] EmptyInts = new int[0]; public static readonly long[] EmptyLongs = new long[0]; internal static readonly byte[] SSL_CLIENT = new byte[4] { 67, 76, 78, 84 }; internal static readonly byte[] SSL_SERVER = new byte[4] { 83, 82, 86, 82 }; internal static readonly byte[][] SSL3_CONST = GenSsl3Const(); public static void CheckUint8(int i) { if (!IsValidUint8(i)) { throw new TlsFatalAlert(80); } } public static void CheckUint8(long i) { if (!IsValidUint8(i)) { throw new TlsFatalAlert(80); } } public static void CheckUint16(int i) { if (!IsValidUint16(i)) { throw new TlsFatalAlert(80); } } public static void CheckUint16(long i) { if (!IsValidUint16(i)) { throw new TlsFatalAlert(80); } } public static void CheckUint24(int i) { if (!IsValidUint24(i)) { throw new TlsFatalAlert(80); } } public static void CheckUint24(long i) { if (!IsValidUint24(i)) { throw new TlsFatalAlert(80); } } public static void CheckUint32(long i) { if (!IsValidUint32(i)) { throw new TlsFatalAlert(80); } } public static void CheckUint48(long i) { if (!IsValidUint48(i)) { throw new TlsFatalAlert(80); } } public static void CheckUint64(long i) { if (!IsValidUint64(i)) { throw new TlsFatalAlert(80); } } public static bool IsValidUint8(int i) { return (i & 0xFF) == i; } public static bool IsValidUint8(long i) { return (i & 0xFF) == i; } public static bool IsValidUint16(int i) { return (i & 0xFFFF) == i; } public static bool IsValidUint16(long i) { return (i & 0xFFFF) == i; } public static bool IsValidUint24(int i) { return (i & 0xFFFFFF) == i; } public static bool IsValidUint24(long i) { return (i & 0xFFFFFF) == i; } public static bool IsValidUint32(long i) { return (i & 0xFFFFFFFFu) == i; } public static bool IsValidUint48(long i) { return (i & 0xFFFFFFFFFFFFL) == i; } public static bool IsValidUint64(long i) { return true; } public static bool IsSsl(TlsContext context) { return context.ServerVersion.IsSsl; } public static bool IsTlsV11(ProtocolVersion version) { return ProtocolVersion.TLSv11.IsEqualOrEarlierVersionOf(version.GetEquivalentTLSVersion()); } public static bool IsTlsV11(TlsContext context) { return IsTlsV11(context.ServerVersion); } public static bool IsTlsV12(ProtocolVersion version) { return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(version.GetEquivalentTLSVersion()); } public static bool IsTlsV12(TlsContext context) { return IsTlsV12(context.ServerVersion); } public static void WriteUint8(byte i, Stream output) { output.WriteByte(i); } public static void WriteUint8(byte i, byte[] buf, int offset) { buf[offset] = i; } public static void WriteUint16(int i, Stream output) { output.WriteByte((byte)(i >> 8)); output.WriteByte((byte)i); } public static void WriteUint16(int i, byte[] buf, int offset) { buf[offset] = (byte)(i >> 8); buf[offset + 1] = (byte)i; } public static void WriteUint24(int i, Stream output) { output.WriteByte((byte)(i >> 16)); output.WriteByte((byte)(i >> 8)); output.WriteByte((byte)i); } public static void WriteUint24(int i, byte[] buf, int offset) { buf[offset] = (byte)(i >> 16); buf[offset + 1] = (byte)(i >> 8); buf[offset + 2] = (byte)i; } public static void WriteUint32(long i, Stream output) { output.WriteByte((byte)(i >> 24)); output.WriteByte((byte)(i >> 16)); output.WriteByte((byte)(i >> 8)); output.WriteByte((byte)i); } public static void WriteUint32(long i, byte[] buf, int offset) { buf[offset] = (byte)(i >> 24); buf[offset + 1] = (byte)(i >> 16); buf[offset + 2] = (byte)(i >> 8); buf[offset + 3] = (byte)i; } public static void WriteUint48(long i, Stream output) { output.WriteByte((byte)(i >> 40)); output.WriteByte((byte)(i >> 32)); output.WriteByte((byte)(i >> 24)); output.WriteByte((byte)(i >> 16)); output.WriteByte((byte)(i >> 8)); output.WriteByte((byte)i); } public static void WriteUint48(long i, byte[] buf, int offset) { buf[offset] = (byte)(i >> 40); buf[offset + 1] = (byte)(i >> 32); buf[offset + 2] = (byte)(i >> 24); buf[offset + 3] = (byte)(i >> 16); buf[offset + 4] = (byte)(i >> 8); buf[offset + 5] = (byte)i; } public static void WriteUint64(long i, Stream output) { output.WriteByte((byte)(i >> 56)); output.WriteByte((byte)(i >> 48)); output.WriteByte((byte)(i >> 40)); output.WriteByte((byte)(i >> 32)); output.WriteByte((byte)(i >> 24)); output.WriteByte((byte)(i >> 16)); output.WriteByte((byte)(i >> 8)); output.WriteByte((byte)i); } public static void WriteUint64(long i, byte[] buf, int offset) { buf[offset] = (byte)(i >> 56); buf[offset + 1] = (byte)(i >> 48); buf[offset + 2] = (byte)(i >> 40); buf[offset + 3] = (byte)(i >> 32); buf[offset + 4] = (byte)(i >> 24); buf[offset + 5] = (byte)(i >> 16); buf[offset + 6] = (byte)(i >> 8); buf[offset + 7] = (byte)i; } public static void WriteOpaque8(byte[] buf, Stream output) { WriteUint8((byte)buf.Length, output); output.Write(buf, 0, buf.Length); } public static void WriteOpaque16(byte[] buf, Stream output) { WriteUint16(buf.Length, output); output.Write(buf, 0, buf.Length); } public static void WriteOpaque24(byte[] buf, Stream output) { WriteUint24(buf.Length, output); output.Write(buf, 0, buf.Length); } public static void WriteUint8Array(byte[] uints, Stream output) { output.Write(uints, 0, uints.Length); } public static void WriteUint8Array(byte[] uints, byte[] buf, int offset) { for (int i = 0; i < uints.Length; i++) { WriteUint8(uints[i], buf, offset); offset++; } } public static void WriteUint8ArrayWithUint8Length(byte[] uints, Stream output) { CheckUint8(uints.Length); WriteUint8((byte)uints.Length, output); WriteUint8Array(uints, output); } public static void WriteUint8ArrayWithUint8Length(byte[] uints, byte[] buf, int offset) { CheckUint8(uints.Length); WriteUint8((byte)uints.Length, buf, offset); WriteUint8Array(uints, buf, offset + 1); } public static void WriteUint16Array(int[] uints, Stream output) { for (int i = 0; i < uints.Length; i++) { WriteUint16(uints[i], output); } } public static void WriteUint16Array(int[] uints, byte[] buf, int offset) { for (int i = 0; i < uints.Length; i++) { WriteUint16(uints[i], buf, offset); offset += 2; } } public static void WriteUint16ArrayWithUint16Length(int[] uints, Stream output) { int i = 2 * uints.Length; CheckUint16(i); WriteUint16(i, output); WriteUint16Array(uints, output); } public static void WriteUint16ArrayWithUint16Length(int[] uints, byte[] buf, int offset) { int i = 2 * uints.Length; CheckUint16(i); WriteUint16(i, buf, offset); WriteUint16Array(uints, buf, offset + 2); } public static byte DecodeUint8(byte[] buf) { if (buf == null) { throw new ArgumentNullException("buf"); } if (buf.Length != 1) { throw new TlsFatalAlert(50); } return ReadUint8(buf, 0); } public static byte[] DecodeUint8ArrayWithUint8Length(byte[] buf) { if (buf == null) { throw new ArgumentNullException("buf"); } int num = ReadUint8(buf, 0); if (buf.Length != num + 1) { throw new TlsFatalAlert(50); } byte[] array = new byte[num]; for (int i = 0; i < num; i++) { array[i] = ReadUint8(buf, i + 1); } return array; } public static byte[] EncodeOpaque8(byte[] buf) { CheckUint8(buf.Length); return Arrays.Prepend(buf, (byte)buf.Length); } public static byte[] EncodeUint8(byte val) { CheckUint8(val); byte[] array = new byte[1]; WriteUint8(val, array, 0); return array; } public static byte[] EncodeUint8ArrayWithUint8Length(byte[] uints) { byte[] array = new byte[1 + uints.Length]; WriteUint8ArrayWithUint8Length(uints, array, 0); return array; } public static byte[] EncodeUint16ArrayWithUint16Length(int[] uints) { int num = 2 * uints.Length; byte[] array = new byte[2 + num]; WriteUint16ArrayWithUint16Length(uints, array, 0); return array; } public static byte ReadUint8(Stream input) { int num = input.ReadByte(); if (num < 0) { throw new EndOfStreamException(); } return (byte)num; } public static byte ReadUint8(byte[] buf, int offset) { return buf[offset]; } public static int ReadUint16(Stream input) { int num = input.ReadByte(); int num2 = input.ReadByte(); if (num2 < 0) { throw new EndOfStreamException(); } return (num << 8) | num2; } public static int ReadUint16(byte[] buf, int offset) { uint num = (uint)(buf[offset] << 8); return (int)(num | buf[++offset]); } public static int ReadUint24(Stream input) { int num = input.ReadByte(); int num2 = input.ReadByte(); int num3 = input.ReadByte(); if (num3 < 0) { throw new EndOfStreamException(); } return (num << 16) | (num2 << 8) | num3; } public static int ReadUint24(byte[] buf, int offset) { uint num = (uint)(buf[offset] << 16); num |= (uint)(buf[++offset] << 8); return (int)(num | buf[++offset]); } public static long ReadUint32(Stream input) { int num = input.ReadByte(); int num2 = input.ReadByte(); int num3 = input.ReadByte(); int num4 = input.ReadByte(); if (num4 < 0) { throw new EndOfStreamException(); } return (uint)((num << 24) | (num2 << 16) | (num3 << 8) | num4); } public static long ReadUint32(byte[] buf, int offset) { uint num = (uint)(buf[offset] << 24); num |= (uint)(buf[++offset] << 16); num |= (uint)(buf[++offset] << 8); num |= buf[++offset]; return num; } public static long ReadUint48(Stream input) { int num = ReadUint24(input); int num2 = ReadUint24(input); return ((num & 0xFFFFFFFFu) << 24) | (num2 & 0xFFFFFFFFu); } public static long ReadUint48(byte[] buf, int offset) { int num = ReadUint24(buf, offset); int num2 = ReadUint24(buf, offset + 3); return ((num & 0xFFFFFFFFu) << 24) | (num2 & 0xFFFFFFFFu); } public static byte[] ReadAllOrNothing(int length, Stream input) { if (length < 1) { return EmptyBytes; } byte[] array = new byte[length]; int num = Streams.ReadFully(input, array); if (num == 0) { return null; } if (num != length) { throw new EndOfStreamException(); } return array; } public static byte[] ReadFully(int length, Stream input) { if (length < 1) { return EmptyBytes; } byte[] array = new byte[length]; if (length != Streams.ReadFully(input, array)) { throw new EndOfStreamException(); } return array; } public static void ReadFully(byte[] buf, Stream input) { if (Streams.ReadFully(input, buf, 0, buf.Length) < buf.Length) { throw new EndOfStreamException(); } } public static byte[] ReadOpaque8(Stream input) { byte b = ReadUint8(input); byte[] array = new byte[b]; ReadFully(array, input); return array; } public static byte[] ReadOpaque16(Stream input) { int num = ReadUint16(input); byte[] array = new byte[num]; ReadFully(array, input); return array; } public static byte[] ReadOpaque24(Stream input) { int length = ReadUint24(input); return ReadFully(length, input); } public static byte[] ReadUint8Array(int count, Stream input) { byte[] array = new byte[count]; for (int i = 0; i < count; i++) { array[i] = ReadUint8(input); } return array; } public static int[] ReadUint16Array(int count, Stream input) { int[] array = new int[count]; for (int i = 0; i < count; i++) { array[i] = ReadUint16(input); } return array; } public static ProtocolVersion ReadVersion(byte[] buf, int offset) { return ProtocolVersion.Get(buf[offset], buf[offset + 1]); } public static ProtocolVersion ReadVersion(Stream input) { int major = input.ReadByte(); int num = input.ReadByte(); if (num < 0) { throw new EndOfStreamException(); } return ProtocolVersion.Get(major, num); } public static int ReadVersionRaw(byte[] buf, int offset) { return (buf[offset] << 8) | buf[offset + 1]; } public static int ReadVersionRaw(Stream input) { int num = input.ReadByte(); int num2 = input.ReadByte(); if (num2 < 0) { throw new EndOfStreamException(); } return (num << 8) | num2; } public static Asn1Object ReadAsn1Object(byte[] encoding) { MemoryStream memoryStream = new MemoryStream(encoding, writable: false); Asn1InputStream asn1InputStream = new Asn1InputStream(memoryStream, encoding.Length); Asn1Object asn1Object = asn1InputStream.ReadObject(); if (asn1Object == null) { throw new TlsFatalAlert(50); } if (memoryStream.Position != memoryStream.Length) { throw new TlsFatalAlert(50); } return asn1Object; } public static Asn1Object ReadDerObject(byte[] encoding) { Asn1Object asn1Object = ReadAsn1Object(encoding); byte[] encoded = asn1Object.GetEncoded("DER"); if (!Arrays.AreEqual(encoded, encoding)) { throw new TlsFatalAlert(50); } return asn1Object; } public static void WriteGmtUnixTime(byte[] buf, int offset) { int num = (int)(DateTimeUtilities.CurrentUnixMs() / 1000); buf[offset] = (byte)(num >> 24); buf[offset + 1] = (byte)(num >> 16); buf[offset + 2] = (byte)(num >> 8); buf[offset + 3] = (byte)num; } public static void WriteVersion(ProtocolVersion version, Stream output) { output.WriteByte((byte)version.MajorVersion); output.WriteByte((byte)version.MinorVersion); } public static void WriteVersion(ProtocolVersion version, byte[] buf, int offset) { buf[offset] = (byte)version.MajorVersion; buf[offset + 1] = (byte)version.MinorVersion; } public static IList GetAllSignatureAlgorithms() { IList list = Platform.CreateArrayList(4); list.Add((byte)0); list.Add((byte)1); list.Add((byte)2); list.Add((byte)3); return list; } public static IList GetDefaultDssSignatureAlgorithms() { return VectorOfOne(new SignatureAndHashAlgorithm(2, 2)); } public static IList GetDefaultECDsaSignatureAlgorithms() { return VectorOfOne(new SignatureAndHashAlgorithm(2, 3)); } public static IList GetDefaultRsaSignatureAlgorithms() { return VectorOfOne(new SignatureAndHashAlgorithm(2, 1)); } public static byte[] GetExtensionData(IDictionary extensions, int extensionType) { if (extensions != null) { return (byte[])extensions[extensionType]; } return null; } public static IList GetDefaultSupportedSignatureAlgorithms() { byte[] array = new byte[5] { 2, 3, 4, 5, 6 }; byte[] array2 = new byte[3] { 1, 2, 3 }; IList list = Platform.CreateArrayList(); for (int i = 0; i < array2.Length; i++) { for (int j = 0; j < array.Length; j++) { list.Add(new SignatureAndHashAlgorithm(array[j], array2[i])); } } return list; } public static SignatureAndHashAlgorithm GetSignatureAndHashAlgorithm(TlsContext context, TlsSignerCredentials signerCredentials) { SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; if (IsTlsV12(context)) { signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm; if (signatureAndHashAlgorithm == null) { throw new TlsFatalAlert(80); } } return signatureAndHashAlgorithm; } public static bool HasExpectedEmptyExtensionData(IDictionary extensions, int extensionType, byte alertDescription) { byte[] extensionData = GetExtensionData(extensions, extensionType); if (extensionData == null) { return false; } if (extensionData.Length != 0) { throw new TlsFatalAlert(alertDescription); } return true; } public static TlsSession ImportSession(byte[] sessionID, SessionParameters sessionParameters) { return new TlsSessionImpl(sessionID, sessionParameters); } public static bool IsSignatureAlgorithmsExtensionAllowed(ProtocolVersion clientVersion) { return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(clientVersion.GetEquivalentTLSVersion()); } public static void AddSignatureAlgorithmsExtension(IDictionary extensions, IList supportedSignatureAlgorithms) { extensions[13] = CreateSignatureAlgorithmsExtension(supportedSignatureAlgorithms); } public static IList GetSignatureAlgorithmsExtension(IDictionary extensions) { byte[] extensionData = GetExtensionData(extensions, 13); if (extensionData != null) { return ReadSignatureAlgorithmsExtension(extensionData); } return null; } public static byte[] CreateSignatureAlgorithmsExtension(IList supportedSignatureAlgorithms) { MemoryStream memoryStream = new MemoryStream(); EncodeSupportedSignatureAlgorithms(supportedSignatureAlgorithms, allowAnonymous: false, memoryStream); return memoryStream.ToArray(); } public static IList ReadSignatureAlgorithmsExtension(byte[] extensionData) { if (extensionData == null) { throw new ArgumentNullException("extensionData"); } MemoryStream memoryStream = new MemoryStream(extensionData, writable: false); IList result = ParseSupportedSignatureAlgorithms(allowAnonymous: false, memoryStream); TlsProtocol.AssertEmpty(memoryStream); return result; } public static void EncodeSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms, bool allowAnonymous, Stream output) { if (supportedSignatureAlgorithms == null) { throw new ArgumentNullException("supportedSignatureAlgorithms"); } if (supportedSignatureAlgorithms.Count < 1 || supportedSignatureAlgorithms.Count >= 32768) { throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms"); } int i = 2 * supportedSignatureAlgorithms.Count; CheckUint16(i); WriteUint16(i, output); foreach (SignatureAndHashAlgorithm supportedSignatureAlgorithm in supportedSignatureAlgorithms) { if (!allowAnonymous && supportedSignatureAlgorithm.Signature == 0) { throw new ArgumentException("SignatureAlgorithm.anonymous MUST NOT appear in the signature_algorithms extension"); } supportedSignatureAlgorithm.Encode(output); } } public static IList ParseSupportedSignatureAlgorithms(bool allowAnonymous, Stream input) { int num = ReadUint16(input); if (num < 2 || (num & 1) != 0) { throw new TlsFatalAlert(50); } int num2 = num / 2; IList list = Platform.CreateArrayList(num2); for (int i = 0; i < num2; i++) { SignatureAndHashAlgorithm signatureAndHashAlgorithm = SignatureAndHashAlgorithm.Parse(input); if (!allowAnonymous && signatureAndHashAlgorithm.Signature == 0) { throw new TlsFatalAlert(47); } list.Add(signatureAndHashAlgorithm); } return list; } public static void VerifySupportedSignatureAlgorithm(IList supportedSignatureAlgorithms, SignatureAndHashAlgorithm signatureAlgorithm) { if (supportedSignatureAlgorithms == null) { throw new ArgumentNullException("supportedSignatureAlgorithms"); } if (supportedSignatureAlgorithms.Count < 1 || supportedSignatureAlgorithms.Count >= 32768) { throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms"); } if (signatureAlgorithm == null) { throw new ArgumentNullException("signatureAlgorithm"); } if (signatureAlgorithm.Signature != 0) { foreach (SignatureAndHashAlgorithm supportedSignatureAlgorithm in supportedSignatureAlgorithms) { if (supportedSignatureAlgorithm.Hash == signatureAlgorithm.Hash && supportedSignatureAlgorithm.Signature == signatureAlgorithm.Signature) { return; } } } throw new TlsFatalAlert(47); } public static byte[] PRF(TlsContext context, byte[] secret, string asciiLabel, byte[] seed, int size) { ProtocolVersion serverVersion = context.ServerVersion; if (serverVersion.IsSsl) { throw new InvalidOperationException("No PRF available for SSLv3 session"); } byte[] array = Strings.ToByteArray(asciiLabel); byte[] array2 = Concat(array, seed); int prfAlgorithm = context.SecurityParameters.PrfAlgorithm; if (prfAlgorithm == 0) { return PRF_legacy(secret, array, array2, size); } IDigest digest = CreatePrfHash(prfAlgorithm); byte[] array3 = new byte[size]; HMacHash(digest, secret, array2, array3); return array3; } public static byte[] PRF_legacy(byte[] secret, string asciiLabel, byte[] seed, int size) { byte[] array = Strings.ToByteArray(asciiLabel); byte[] labelSeed = Concat(array, seed); return PRF_legacy(secret, array, labelSeed, size); } internal static byte[] PRF_legacy(byte[] secret, byte[] label, byte[] labelSeed, int size) { int num = (secret.Length + 1) / 2; byte[] array = new byte[num]; byte[] array2 = new byte[num]; Array.Copy(secret, 0, array, 0, num); Array.Copy(secret, secret.Length - num, array2, 0, num); byte[] array3 = new byte[size]; byte[] array4 = new byte[size]; HMacHash(CreateHash(1), array, labelSeed, array3); HMacHash(CreateHash(2), array2, labelSeed, array4); for (int i = 0; i < size; i++) { byte[] array6; byte[] array5 = (array6 = array3); int num2 = i; nint num3 = num2; array5[num2] = (byte)(array6[num3] ^ array4[i]); } return array3; } internal static byte[] Concat(byte[] a, byte[] b) { byte[] array = new byte[a.Length + b.Length]; Array.Copy(a, 0, array, 0, a.Length); Array.Copy(b, 0, array, a.Length, b.Length); return array; } internal static void HMacHash(IDigest digest, byte[] secret, byte[] seed, byte[] output) { HMac hMac = new HMac(digest); hMac.Init(new KeyParameter(secret)); byte[] array = seed; int digestSize = digest.GetDigestSize(); int num = (output.Length + digestSize - 1) / digestSize; byte[] array2 = new byte[hMac.GetMacSize()]; byte[] array3 = new byte[hMac.GetMacSize()]; for (int i = 0; i < num; i++) { hMac.BlockUpdate(array, 0, array.Length); hMac.DoFinal(array2, 0); array = array2; hMac.BlockUpdate(array, 0, array.Length); hMac.BlockUpdate(seed, 0, seed.Length); hMac.DoFinal(array3, 0); Array.Copy(array3, 0, output, digestSize * i, System.Math.Min(digestSize, output.Length - digestSize * i)); } } internal static void ValidateKeyUsage(X509CertificateStructure c, int keyUsageBits) { X509Extensions extensions = c.TbsCertificate.Extensions; if (extensions == null) { return; } X509Extension extension = extensions.GetExtension(X509Extensions.KeyUsage); if (extension != null) { DerBitString instance = KeyUsage.GetInstance(extension); int num = instance.GetBytes()[0]; if ((num & keyUsageBits) != keyUsageBits) { throw new TlsFatalAlert(46); } } } internal static byte[] CalculateKeyBlock(TlsContext context, int size) { SecurityParameters securityParameters = context.SecurityParameters; byte[] masterSecret = securityParameters.MasterSecret; byte[] array = Concat(securityParameters.ServerRandom, securityParameters.ClientRandom); if (IsSsl(context)) { return CalculateKeyBlock_Ssl(masterSecret, array, size); } return PRF(context, masterSecret, "key expansion", array, size); } internal static byte[] CalculateKeyBlock_Ssl(byte[] master_secret, byte[] random, int size) { IDigest digest = CreateHash(1); IDigest digest2 = CreateHash(2); int digestSize = digest.GetDigestSize(); byte[] array = new byte[digest2.GetDigestSize()]; byte[] array2 = new byte[size + digestSize]; int num = 0; int num2 = 0; while (num2 < size) { byte[] array3 = SSL3_CONST[num]; digest2.BlockUpdate(array3, 0, array3.Length); digest2.BlockUpdate(master_secret, 0, master_secret.Length); digest2.BlockUpdate(random, 0, random.Length); digest2.DoFinal(array, 0); digest.BlockUpdate(master_secret, 0, master_secret.Length); digest.BlockUpdate(array, 0, array.Length); digest.DoFinal(array2, num2); num2 += digestSize; num++; } return Arrays.CopyOfRange(array2, 0, size); } internal static byte[] CalculateMasterSecret(TlsContext context, byte[] pre_master_secret) { SecurityParameters securityParameters = context.SecurityParameters; byte[] array = (securityParameters.IsExtendedMasterSecret ? securityParameters.SessionHash : Concat(securityParameters.ClientRandom, securityParameters.ServerRandom)); if (IsSsl(context)) { return CalculateMasterSecret_Ssl(pre_master_secret, array); } string asciiLabel = (securityParameters.IsExtendedMasterSecret ? ExporterLabel.extended_master_secret : "master secret"); return PRF(context, pre_master_secret, asciiLabel, array, 48); } internal static byte[] CalculateMasterSecret_Ssl(byte[] pre_master_secret, byte[] random) { IDigest digest = CreateHash(1); IDigest digest2 = CreateHash(2); int digestSize = digest.GetDigestSize(); byte[] array = new byte[digest2.GetDigestSize()]; byte[] array2 = new byte[digestSize * 3]; int num = 0; for (int i = 0; i < 3; i++) { byte[] array3 = SSL3_CONST[i]; digest2.BlockUpdate(array3, 0, array3.Length); digest2.BlockUpdate(pre_master_secret, 0, pre_master_secret.Length); digest2.BlockUpdate(random, 0, random.Length); digest2.DoFinal(array, 0); digest.BlockUpdate(pre_master_secret, 0, pre_master_secret.Length); digest.BlockUpdate(array, 0, array.Length); digest.DoFinal(array2, num); num += digestSize; } return array2; } internal static byte[] CalculateVerifyData(TlsContext context, string asciiLabel, byte[] handshakeHash) { if (IsSsl(context)) { return handshakeHash; } SecurityParameters securityParameters = context.SecurityParameters; byte[] masterSecret = securityParameters.MasterSecret; int verifyDataLength = securityParameters.VerifyDataLength; return PRF(context, masterSecret, asciiLabel, handshakeHash, verifyDataLength); } public static IDigest CreateHash(byte hashAlgorithm) { return hashAlgorithm switch { 1 => new MD5Digest(), 2 => new Sha1Digest(), 3 => new Sha224Digest(), 4 => new Sha256Digest(), 5 => new Sha384Digest(), 6 => new Sha512Digest(), _ => throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm"), }; } public static IDigest CreateHash(SignatureAndHashAlgorithm signatureAndHashAlgorithm) { if (signatureAndHashAlgorithm != null) { return CreateHash(signatureAndHashAlgorithm.Hash); } return new CombinedHash(); } public static IDigest CloneHash(byte hashAlgorithm, IDigest hash) { return hashAlgorithm switch { 1 => new MD5Digest((MD5Digest)hash), 2 => new Sha1Digest((Sha1Digest)hash), 3 => new Sha224Digest((Sha224Digest)hash), 4 => new Sha256Digest((Sha256Digest)hash), 5 => new Sha384Digest((Sha384Digest)hash), 6 => new Sha512Digest((Sha512Digest)hash), _ => throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm"), }; } public static IDigest CreatePrfHash(int prfAlgorithm) { if (prfAlgorithm == 0) { return new CombinedHash(); } return CreateHash(GetHashAlgorithmForPrfAlgorithm(prfAlgorithm)); } public static IDigest ClonePrfHash(int prfAlgorithm, IDigest hash) { if (prfAlgorithm == 0) { return new CombinedHash((CombinedHash)hash); } return CloneHash(GetHashAlgorithmForPrfAlgorithm(prfAlgorithm), hash); } public static byte GetHashAlgorithmForPrfAlgorithm(int prfAlgorithm) { return prfAlgorithm switch { 0 => throw new ArgumentException("legacy PRF not a valid algorithm", "prfAlgorithm"), 1 => 4, 2 => 5, _ => throw new ArgumentException("unknown PrfAlgorithm", "prfAlgorithm"), }; } public static DerObjectIdentifier GetOidForHashAlgorithm(byte hashAlgorithm) { return hashAlgorithm switch { 1 => PkcsObjectIdentifiers.MD5, 2 => X509ObjectIdentifiers.IdSha1, 3 => NistObjectIdentifiers.IdSha224, 4 => NistObjectIdentifiers.IdSha256, 5 => NistObjectIdentifiers.IdSha384, 6 => NistObjectIdentifiers.IdSha512, _ => throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm"), }; } internal static short GetClientCertificateType(Certificate clientCertificate, Certificate serverCertificate) { if (clientCertificate.IsEmpty) { return -1; } X509CertificateStructure certificateAt = clientCertificate.GetCertificateAt(0); SubjectPublicKeyInfo subjectPublicKeyInfo = certificateAt.SubjectPublicKeyInfo; try { AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(subjectPublicKeyInfo); if (asymmetricKeyParameter.IsPrivate) { throw new TlsFatalAlert(80); } if (asymmetricKeyParameter is RsaKeyParameters) { ValidateKeyUsage(certificateAt, 128); return 1; } if (asymmetricKeyParameter is DsaPublicKeyParameters) { ValidateKeyUsage(certificateAt, 128); return 2; } if (asymmetricKeyParameter is ECPublicKeyParameters) { ValidateKeyUsage(certificateAt, 128); return 64; } throw new TlsFatalAlert(43); } catch (Exception alertCause) { throw new TlsFatalAlert(43, alertCause); } } internal static void TrackHashAlgorithms(TlsHandshakeHash handshakeHash, IList supportedSignatureAlgorithms) { if (supportedSignatureAlgorithms == null) { return; } foreach (SignatureAndHashAlgorithm supportedSignatureAlgorithm in supportedSignatureAlgorithms) { byte hash = supportedSignatureAlgorithm.Hash; if (HashAlgorithm.IsRecognized(hash)) { handshakeHash.TrackHashAlgorithm(hash); } } } public static bool HasSigningCapability(byte clientCertificateType) { switch (clientCertificateType) { case 1: case 2: case 64: return true; default: return false; } } public static TlsSigner CreateTlsSigner(byte clientCertificateType) { return clientCertificateType switch { 2 => new TlsDssSigner(), 64 => new TlsECDsaSigner(), 1 => new TlsRsaSigner(), _ => throw new ArgumentException("not a type with signing capability", "clientCertificateType"), }; } private static byte[][] GenSsl3Const() { int num = 10; byte[][] array = new byte[num][]; for (int i = 0; i < num; i++) { byte[] array2 = new byte[i + 1]; Arrays.Fill(array2, (byte)(65 + i)); array[i] = array2; } return array; } private static IList VectorOfOne(object obj) { IList list = Platform.CreateArrayList(1); list.Add(obj); return list; } public static int GetCipherType(int ciphersuite) { switch (GetEncryptionAlgorithm(ciphersuite)) { case 10: case 11: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 103: case 104: return 2; case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 12: case 13: case 14: return 1; case 0: case 1: case 2: return 0; default: throw new TlsFatalAlert(80); } } public static int GetEncryptionAlgorithm(int ciphersuite) { switch (ciphersuite) { case 10: case 13: case 16: case 19: case 22: case 27: case 139: case 143: case 147: case 49155: case 49160: case 49165: case 49170: case 49175: case 49178: case 49179: case 49180: case 49204: return 7; case 47: case 48: case 49: case 50: case 51: case 52: case 60: case 62: case 63: case 64: case 103: case 108: case 140: case 144: case 148: case 174: case 178: case 182: case 49156: case 49161: case 49166: case 49171: case 49176: case 49181: case 49182: case 49183: case 49187: case 49189: case 49191: case 49193: case 49205: case 49207: return 8; case 49308: case 49310: case 49316: case 49318: case 49324: return 15; case 49312: case 49314: case 49320: case 49322: case 49326: return 16; case 156: case 158: case 160: case 162: case 164: case 166: case 168: case 170: case 172: case 49195: case 49197: case 49199: case 49201: return 10; case 65280: case 65282: case 65284: case 65296: case 65298: case 65300: return 103; case 53: case 54: case 55: case 56: case 57: case 58: case 61: case 104: case 105: case 106: case 107: case 109: case 141: case 145: case 149: case 175: case 179: case 183: case 49157: case 49162: case 49167: case 49172: case 49177: case 49184: case 49185: case 49186: case 49188: case 49190: case 49192: case 49194: case 49206: case 49208: return 9; case 49309: case 49311: case 49317: case 49319: case 49325: return 17; case 49313: case 49315: case 49321: case 49323: case 49327: return 18; case 157: case 159: case 161: case 163: case 165: case 167: case 169: case 171: case 173: case 49196: case 49198: case 49200: case 49202: return 11; case 65281: case 65283: case 65285: case 65297: case 65299: case 65301: return 104; case 65: case 66: case 67: case 68: case 69: case 70: case 186: case 187: case 188: case 189: case 190: case 191: case 49266: case 49268: case 49270: case 49272: case 49300: case 49302: case 49304: case 49306: return 12; case 49274: case 49276: case 49278: case 49280: case 49282: case 49284: case 49286: case 49288: case 49290: case 49292: case 49294: case 49296: case 49298: return 19; case 132: case 133: case 134: case 135: case 136: case 137: case 192: case 193: case 194: case 195: case 196: case 197: case 49267: case 49269: case 49271: case 49273: case 49301: case 49303: case 49305: case 49307: return 13; case 49275: case 49277: case 49279: case 49281: case 49283: case 49285: case 49287: case 49289: case 49291: case 49293: case 49295: case 49297: case 49299: return 20; case 52392: case 52393: case 52394: case 52395: case 52396: case 52397: case 52398: return 21; case 1: return 0; case 2: case 44: case 45: case 46: case 49153: case 49158: case 49163: case 49168: case 49173: case 49209: return 0; case 59: case 176: case 180: case 184: case 49210: return 0; case 177: case 181: case 185: case 49211: return 0; case 4: case 24: return 2; case 5: case 138: case 142: case 146: case 49154: case 49159: case 49164: case 49169: case 49174: case 49203: return 2; case 150: case 151: case 152: case 153: case 154: case 155: return 14; default: throw new TlsFatalAlert(80); } } public static int GetKeyExchangeAlgorithm(int ciphersuite) { switch (ciphersuite) { case 24: case 27: case 52: case 58: case 70: case 108: case 109: case 137: case 155: case 166: case 167: case 191: case 197: case 49284: case 49285: return 11; case 13: case 48: case 54: case 62: case 66: case 104: case 133: case 151: case 164: case 165: case 187: case 193: case 49282: case 49283: return 7; case 16: case 49: case 55: case 63: case 67: case 105: case 134: case 152: case 160: case 161: case 188: case 194: case 49278: case 49279: return 9; case 19: case 50: case 56: case 64: case 68: case 106: case 135: case 153: case 162: case 163: case 189: case 195: case 49280: case 49281: return 3; case 45: case 142: case 143: case 144: case 145: case 170: case 171: case 178: case 179: case 180: case 181: case 49296: case 49297: case 49302: case 49303: case 49318: case 49319: case 49322: case 49323: case 52397: case 65298: case 65299: return 14; case 22: case 51: case 57: case 69: case 103: case 107: case 136: case 154: case 158: case 159: case 190: case 196: case 49276: case 49277: case 49310: case 49311: case 49314: case 49315: case 52394: case 65280: case 65281: return 5; case 49173: case 49174: case 49175: case 49176: case 49177: return 20; case 49153: case 49154: case 49155: case 49156: case 49157: case 49189: case 49190: case 49197: case 49198: case 49268: case 49269: case 49288: case 49289: case 65284: case 65285: return 16; case 49163: case 49164: case 49165: case 49166: case 49167: case 49193: case 49194: case 49201: case 49202: case 49272: case 49273: case 49292: case 49293: return 18; case 49158: case 49159: case 49160: case 49161: case 49162: case 49187: case 49188: case 49195: case 49196: case 49266: case 49267: case 49286: case 49287: case 49324: case 49325: case 49326: case 49327: case 52393: return 17; case 49203: case 49204: case 49205: case 49206: case 49207: case 49208: case 49209: case 49210: case 49211: case 49306: case 49307: case 52396: case 65300: case 65301: return 24; case 49168: case 49169: case 49170: case 49171: case 49172: case 49191: case 49192: case 49199: case 49200: case 49270: case 49271: case 49290: case 49291: case 52392: case 65282: case 65283: return 19; case 44: case 138: case 139: case 140: case 141: case 168: case 169: case 174: case 175: case 176: case 177: case 49294: case 49295: case 49300: case 49301: case 49316: case 49317: case 49320: case 49321: case 52395: case 65296: case 65297: return 13; case 1: case 2: case 4: case 5: case 10: case 47: case 53: case 59: case 60: case 61: case 65: case 132: case 150: case 156: case 157: case 186: case 192: case 49274: case 49275: case 49308: case 49309: case 49312: case 49313: case 52398: return 1; case 46: case 146: case 147: case 148: case 149: case 172: case 173: case 182: case 183: case 184: case 185: case 49298: case 49299: case 49304: case 49305: return 15; case 49178: case 49181: case 49184: return 21; case 49180: case 49183: case 49186: return 22; case 49179: case 49182: case 49185: return 23; default: throw new TlsFatalAlert(80); } } public static int GetMacAlgorithm(int ciphersuite) { switch (ciphersuite) { case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 49195: case 49196: case 49197: case 49198: case 49199: case 49200: case 49201: case 49202: case 49274: case 49275: case 49276: case 49277: case 49278: case 49279: case 49280: case 49281: case 49282: case 49283: case 49284: case 49285: case 49286: case 49287: case 49288: case 49289: case 49290: case 49291: case 49292: case 49293: case 49294: case 49295: case 49296: case 49297: case 49298: case 49299: case 49308: case 49309: case 49310: case 49311: case 49312: case 49313: case 49314: case 49315: case 49316: case 49317: case 49318: case 49319: case 49320: case 49321: case 49322: case 49323: case 49324: case 49325: case 49326: case 49327: case 52392: case 52393: case 52394: case 52395: case 52396: case 52397: case 52398: case 65280: case 65281: case 65282: case 65283: case 65284: case 65285: case 65296: case 65297: case 65298: case 65299: case 65300: case 65301: return 0; case 1: case 4: case 24: return 1; case 2: case 5: case 10: case 13: case 16: case 19: case 22: case 27: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 65: case 66: case 67: case 68: case 69: case 70: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 49153: case 49154: case 49155: case 49156: case 49157: case 49158: case 49159: case 49160: case 49161: case 49162: case 49163: case 49164: case 49165: case 49166: case 49167: case 49168: case 49169: case 49170: case 49171: case 49172: case 49173: case 49174: case 49175: case 49176: case 49177: case 49178: case 49179: case 49180: case 49181: case 49182: case 49183: case 49184: case 49185: case 49186: case 49203: case 49204: case 49205: case 49206: case 49209: return 2; case 59: case 60: case 61: case 62: case 63: case 64: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 174: case 176: case 178: case 180: case 182: case 184: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: case 49187: case 49189: case 49191: case 49193: case 49207: case 49210: case 49266: case 49268: case 49270: case 49272: case 49300: case 49302: case 49304: case 49306: return 3; case 175: case 177: case 179: case 181: case 183: case 185: case 49188: case 49190: case 49192: case 49194: case 49208: case 49211: case 49267: case 49269: case 49271: case 49273: case 49301: case 49303: case 49305: case 49307: return 4; default: throw new TlsFatalAlert(80); } } public static ProtocolVersion GetMinimumVersion(int ciphersuite) { if (ciphersuite <= 197) { switch (ciphersuite) { case 59: case 60: case 61: case 62: case 63: case 64: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: break; default: goto IL_0300; } } else { switch (ciphersuite) { case 49187: case 49188: case 49189: case 49190: case 49191: case 49192: case 49193: case 49194: case 49195: case 49196: case 49197: case 49198: case 49199: case 49200: case 49201: case 49202: case 49266: case 49267: case 49268: case 49269: case 49270: case 49271: case 49272: case 49273: case 49274: case 49275: case 49276: case 49277: case 49278: case 49279: case 49280: case 49281: case 49282: case 49283: case 49284: case 49285: case 49286: case 49287: case 49288: case 49289: case 49290: case 49291: case 49292: case 49293: case 49294: case 49295: case 49296: case 49297: case 49298: case 49299: case 49308: case 49309: case 49310: case 49311: case 49312: case 49313: case 49314: case 49315: case 49316: case 49317: case 49318: case 49319: case 49320: case 49321: case 49322: case 49323: case 49324: case 49325: case 49326: case 49327: case 52392: case 52393: case 52394: case 52395: case 52396: case 52397: case 52398: case 65280: case 65281: case 65282: case 65283: case 65284: case 65285: case 65296: case 65297: case 65298: case 65299: case 65300: case 65301: break; default: goto IL_0300; } } return ProtocolVersion.TLSv12; IL_0300: return ProtocolVersion.SSLv3; } public static bool IsAeadCipherSuite(int ciphersuite) { return 2 == GetCipherType(ciphersuite); } public static bool IsBlockCipherSuite(int ciphersuite) { return 1 == GetCipherType(ciphersuite); } public static bool IsStreamCipherSuite(int ciphersuite) { return 0 == GetCipherType(ciphersuite); } public static bool IsValidCipherSuiteForSignatureAlgorithms(int cipherSuite, IList sigAlgs) { int keyExchangeAlgorithm; try { keyExchangeAlgorithm = GetKeyExchangeAlgorithm(cipherSuite); } catch (IOException) { return true; } switch (keyExchangeAlgorithm) { case 11: case 12: case 20: return sigAlgs.Contains((byte)0); case 5: case 6: case 19: case 23: return sigAlgs.Contains((byte)1); case 3: case 4: case 22: return sigAlgs.Contains((byte)2); case 17: return sigAlgs.Contains((byte)3); default: return true; } } public static bool IsValidCipherSuiteForVersion(int cipherSuite, ProtocolVersion serverVersion) { return GetMinimumVersion(cipherSuite).IsEqualOrEarlierVersionOf(serverVersion.GetEquivalentTLSVersion()); } public static IList GetUsableSignatureAlgorithms(IList sigHashAlgs) { if (sigHashAlgs == null) { return GetAllSignatureAlgorithms(); } IList list = Platform.CreateArrayList(4); list.Add((byte)0); foreach (SignatureAndHashAlgorithm sigHashAlg in sigHashAlgs) { byte signature = sigHashAlg.Signature; if (!list.Contains(signature)) { list.Add(signature); } } return list; } }