2304 lines
45 KiB
C#
2304 lines
45 KiB
C#
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;
|
|
}
|
|
}
|