diff --git a/src/Common/tests/System/Net/VirtualNetwork/VirtualNetwork.cs b/src/Common/tests/System/Net/VirtualNetwork/VirtualNetwork.cs index b82c3946d9d5..e34ffd7f4b97 100644 --- a/src/Common/tests/System/Net/VirtualNetwork/VirtualNetwork.cs +++ b/src/Common/tests/System/Net/VirtualNetwork/VirtualNetwork.cs @@ -10,16 +10,29 @@ namespace System.Net.Test.Common { public class VirtualNetwork { + public class VirtualNetworkConnectionBroken : Exception + { + public VirtualNetworkConnectionBroken() : base("Connection broken") { } + } + private readonly int WaitForReadDataTimeoutMilliseconds = 30 * 1000; - + private readonly ConcurrentQueue _clientWriteQueue = new ConcurrentQueue(); private readonly ConcurrentQueue _serverWriteQueue = new ConcurrentQueue(); private readonly SemaphoreSlim _clientDataAvailable = new SemaphoreSlim(0); private readonly SemaphoreSlim _serverDataAvailable = new SemaphoreSlim(0); + public bool DisableConnectionBreaking { get; set; } = false; + private bool _connectionBroken = false; + public void ReadFrame(bool server, out byte[] buffer) { + if (_connectionBroken) + { + throw new VirtualNetworkConnectionBroken(); + } + SemaphoreSlim semaphore; ConcurrentQueue packetQueue; @@ -39,6 +52,11 @@ public void ReadFrame(bool server, out byte[] buffer) throw new TimeoutException("VirtualNetwork: Timeout reading the next frame."); } + if (_connectionBroken) + { + throw new VirtualNetworkConnectionBroken(); + } + bool dequeueSucceeded = false; int remainingTries = 3; int backOffDelayMilliseconds = 2; @@ -62,6 +80,11 @@ public void ReadFrame(bool server, out byte[] buffer) public void WriteFrame(bool server, byte[] buffer) { + if (_connectionBroken) + { + throw new VirtualNetworkConnectionBroken(); + } + SemaphoreSlim semaphore; ConcurrentQueue packetQueue; @@ -82,5 +105,15 @@ public void WriteFrame(bool server, byte[] buffer) packetQueue.Enqueue(innerBuffer); semaphore.Release(); } + + public void BreakConnection() + { + if (!DisableConnectionBreaking) + { + _connectionBroken = true; + _serverDataAvailable.Release(1_000_000); + _clientDataAvailable.Release(1_000_000); + } + } } } diff --git a/src/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs b/src/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs index e04eb54ace7a..d019c101adb9 100644 --- a/src/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs +++ b/src/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs @@ -156,5 +156,15 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, As public override void EndWrite(IAsyncResult asyncResult) => TaskToApm.End(asyncResult); + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _network.BreakConnection(); + } + + base.Dispose(disposing); + } } } diff --git a/src/System.Net.Security/ref/System.Net.Security.cs b/src/System.Net.Security/ref/System.Net.Security.cs index fbe4022fbe01..785eadd9c235 100644 --- a/src/System.Net.Security/ref/System.Net.Security.cs +++ b/src/System.Net.Security/ref/System.Net.Security.cs @@ -32,6 +32,8 @@ public enum EncryptionPolicy RequireEncryption = 0, } public delegate System.Security.Cryptography.X509Certificates.X509Certificate LocalCertificateSelectionCallback(object sender, string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection localCertificates, System.Security.Cryptography.X509Certificates.X509Certificate remoteCertificate, string[] acceptableIssuers); + public delegate System.Security.Cryptography.X509Certificates.X509Certificate ServerCertificateSelectionCallback(object sender, string hostName); + public partial class NegotiateStream : AuthenticatedStream { public NegotiateStream(System.IO.Stream innerStream) : base(innerStream, false) { } @@ -108,6 +110,7 @@ public class SslServerAuthenticationOptions public X509RevocationMode CertificateRevocationCheckMode { get { throw null; } set { } } public List ApplicationProtocols { get { throw null; } set { } } public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get { throw null; } set { } } + public ServerCertificateSelectionCallback ServerCertificateSelectionCallback { get { throw null; } set { } } public EncryptionPolicy EncryptionPolicy { get { throw null; } set { } } } public partial class SslClientAuthenticationOptions diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj index 5600de569196..e9a5737afe63 100644 --- a/src/System.Net.Security/src/System.Net.Security.csproj +++ b/src/System.Net.Security/src/System.Net.Security.csproj @@ -23,6 +23,7 @@ + diff --git a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs index b444eea3125b..a9ddc3439d51 100644 --- a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs +++ b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs @@ -624,7 +624,7 @@ private bool AcquireClientCredentials(ref byte[] thumbPrint) // // Acquire Server Side Certificate information and set it on the class. // - private bool AcquireServerCredentials(ref byte[] thumbPrint) + private bool AcquireServerCredentials(ref byte[] thumbPrint, byte[] clientHello) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this); @@ -632,7 +632,18 @@ private bool AcquireServerCredentials(ref byte[] thumbPrint) X509Certificate localCertificate = null; bool cachedCred = false; - if (_sslAuthenticationOptions.CertSelectionDelegate != null) + if (_sslAuthenticationOptions.ServerCertSelectionDelegate != null) + { + string serverIdentity = SniHelper.GetServerName(clientHello); + localCertificate = _sslAuthenticationOptions.ServerCertSelectionDelegate(serverIdentity); + + if (localCertificate == null) + { + throw new AuthenticationException(SR.net_ssl_io_no_server_cert); + } + } + // This probably never gets called as this is a client options delegate + else if (_sslAuthenticationOptions.CertSelectionDelegate != null) { X509CertificateCollection tempCollection = new X509CertificateCollection(); tempCollection.Add(_sslAuthenticationOptions.ServerCertificate); @@ -744,7 +755,6 @@ private SecurityStatusPal GenerateToken(byte[] input, int offset, int count, ref #if TRACE_VERBOSE if (NetEventSource.IsEnabled) NetEventSource.Enter(this, $"_refreshCredentialNeeded = {_refreshCredentialNeeded}"); #endif - if (offset < 0 || offset > (input == null ? 0 : input.Length)) { NetEventSource.Fail(this, "Argument 'offset' out of range."); @@ -786,7 +796,7 @@ private SecurityStatusPal GenerateToken(byte[] input, int offset, int count, ref if (_refreshCredentialNeeded) { cachedCreds = _sslAuthenticationOptions.IsServer - ? AcquireServerCredentials(ref thumbPrint) + ? AcquireServerCredentials(ref thumbPrint, input) : AcquireClientCredentials(ref thumbPrint); } diff --git a/src/System.Net.Security/src/System/Net/Security/SniHelper.cs b/src/System.Net.Security/src/System/Net/Security/SniHelper.cs new file mode 100644 index 000000000000..b1540f122b3c --- /dev/null +++ b/src/System.Net.Security/src/System/Net/Security/SniHelper.cs @@ -0,0 +1,391 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers.Binary; +using System.Globalization; +using System.Text; + +namespace System.Net.Security +{ + internal class SniHelper + { + private const int ProtocolVersionSize = 2; + private const int UInt24Size = 3; + private const int RandomSize = 32; + private readonly static IdnMapping s_idnMapping = CreateIdnMapping(); + private readonly static Encoding s_encoding = CreateEncoding(); + + public static string GetServerName(byte[] clientHello) + { + return GetSniFromSslPlainText(clientHello); + } + + private static string GetSniFromSslPlainText(ReadOnlySpan sslPlainText) + { + // https://tools.ietf.org/html/rfc6101#section-5.2.1 + // struct { + // ContentType type; // enum with max value 255 + // ProtocolVersion version; // 2x uint8 + // uint16 length; + // opaque fragment[SSLPlaintext.length]; + // } SSLPlaintext; + const int ContentTypeOffset = 0; + const int ProtocolVersionOffset = ContentTypeOffset + sizeof(ContentType); + const int LengthOffset = ProtocolVersionOffset + ProtocolVersionSize; + const int HandshakeOffset = LengthOffset + sizeof(ushort); + + // SSL v2's ContentType has 0x80 bit set. + // We do not care about SSL v2 here because it does not support client hello extensions + if (sslPlainText.Length < HandshakeOffset || (ContentType)sslPlainText[ContentTypeOffset] != ContentType.Handshake) + { + return null; + } + + // Skip ContentType and ProtocolVersion + int handshakeLength = BinaryPrimitives.ReadUInt16BigEndian(sslPlainText.Slice(LengthOffset)); + ReadOnlySpan sslHandshake = sslPlainText.Slice(HandshakeOffset); + + if (handshakeLength != sslHandshake.Length) + { + return null; + } + + return GetSniFromSslHandshake(sslHandshake); + } + + private static string GetSniFromSslHandshake(ReadOnlySpan sslHandshake) + { + // https://tools.ietf.org/html/rfc6101#section-5.6 + // struct { + // HandshakeType msg_type; /* handshake type */ + // uint24 length; /* bytes in message */ + // select (HandshakeType) { + // ... + // case client_hello: ClientHello; + // ... + // } body; + // } Handshake; + const int HandshakeTypeOffset = 0; + const int ClientHelloLengthOffset = HandshakeTypeOffset + sizeof(HandshakeType); + const int ClientHelloOffset = ClientHelloLengthOffset + UInt24Size; + + if (sslHandshake.Length < ClientHelloOffset || (HandshakeType)sslHandshake[HandshakeTypeOffset] != HandshakeType.ClientHello) + { + return null; + } + + int clientHelloLength = ReadUInt24BigEndian(sslHandshake.Slice(ClientHelloLengthOffset)); + ReadOnlySpan clientHello = sslHandshake.Slice(ClientHelloOffset); + + if (clientHello.Length != clientHelloLength) + { + return null; + } + + return GetSniFromClientHello(clientHello); + } + + private static string GetSniFromClientHello(ReadOnlySpan clientHello) + { + // Basic structure: https://tools.ietf.org/html/rfc6101#section-5.6.1.2 + // Extended structure: https://tools.ietf.org/html/rfc3546#section-2.1 + // struct { + // ProtocolVersion client_version; // 2x uint8 + // Random random; // 32 bytes + // SessionID session_id; // opaque type + // CipherSuite cipher_suites<2..2^16-1>; // opaque type + // CompressionMethod compression_methods<1..2^8-1>; // opaque type + // Extension client_hello_extension_list<0..2^16-1>; + // } ClientHello; + ReadOnlySpan p = SkipBytes(clientHello, ProtocolVersionSize + RandomSize); + + // Skip SessionID (max size 32 => size fits in 1 byte) + p = SkipOpaqueType1(p); + + // Skip cipher suites (max size 2^16-1 => size fits in 2 bytes) + p = SkipOpaqueType2(p, out _); + + // Skip compression methods (max size 2^8-1 => size fits in 1 byte) + p = SkipOpaqueType1(p); + + // is invalid structure or no extensions? + if (p.IsEmpty) + { + return null; + } + + // client_hello_extension_list (max size 2^16-1 => size fits in 2 bytes) + int extensionListLength = BinaryPrimitives.ReadUInt16BigEndian(p); + p = SkipBytes(p, sizeof(ushort)); + + if (extensionListLength != p.Length) + { + return null; + } + + string ret = null; + while (!p.IsEmpty) + { + bool invalid; + string sni = GetSniFromExtension(p, out p, out invalid); + if (invalid) + { + return null; + } + + if (ret != null && sni != null) + { + return null; + } + + if (sni != null) + { + ret = sni; + } + } + + return ret; + } + + private static string GetSniFromExtension(ReadOnlySpan extension, out ReadOnlySpan remainingBytes, out bool invalid) + { + // https://tools.ietf.org/html/rfc3546#section-2.3 + // struct { + // ExtensionType extension_type; + // opaque extension_data<0..2^16-1>; + // } Extension; + const int ExtensionDataOffset = sizeof(ExtensionType); + + if (extension.Length < ExtensionDataOffset) + { + remainingBytes = ReadOnlySpan.Empty; + invalid = true; + return null; + } + + ExtensionType extensionType = (ExtensionType)BinaryPrimitives.ReadUInt16BigEndian(extension); + ReadOnlySpan extensionData = extension.Slice(ExtensionDataOffset); + + if (extensionType == ExtensionType.ServerName) + { + return GetSniFromServerNameList(extensionData, out remainingBytes, out invalid); + } + else + { + remainingBytes = SkipOpaqueType2(extensionData, out invalid); + return null; + } + } + + private static string GetSniFromServerNameList(ReadOnlySpan serverNameListExtension, out ReadOnlySpan remainingBytes, out bool invalid) + { + // https://tools.ietf.org/html/rfc3546#section-3.1 + // struct { + // ServerName server_name_list<1..2^16-1> + // } ServerNameList; + // ServerNameList is an opaque type (length of sufficient size for max data length is prepended) + const int ServerNameListOffset = sizeof(ushort); + + if (serverNameListExtension.Length < ServerNameListOffset) + { + remainingBytes = ReadOnlySpan.Empty; + invalid = true; + return null; + } + + int serverNameListLength = BinaryPrimitives.ReadUInt16BigEndian(serverNameListExtension); + ReadOnlySpan serverNameList = serverNameListExtension.Slice(ServerNameListOffset); + + if (serverNameListLength > serverNameList.Length) + { + remainingBytes = ReadOnlySpan.Empty; + invalid = true; + return null; + } + + remainingBytes = serverNameList.Slice(serverNameListLength); + ReadOnlySpan serverName = serverNameList.Slice(0, serverNameListLength); + + return GetSniFromServerName(serverName, out invalid); + } + + private static string GetSniFromServerName(ReadOnlySpan serverName, out bool invalid) + { + // https://tools.ietf.org/html/rfc3546#section-3.1 + // struct { + // NameType name_type; + // select (name_type) { + // case host_name: HostName; + // } name; + // } ServerName; + // ServerName is an opaque type (length of sufficient size for max data length is prepended) + const int ServerNameLengthOffset = 0; + const int NameTypeOffset = ServerNameLengthOffset + sizeof(ushort); + const int HostNameStructOffset = NameTypeOffset + sizeof(NameType); + + if (serverName.Length < HostNameStructOffset) + { + invalid = true; + return null; + } + + // Following can underflow but it is ok due to equality check below + int hostNameStructLength = BinaryPrimitives.ReadUInt16BigEndian(serverName) - sizeof(NameType); + NameType nameType = (NameType)serverName[NameTypeOffset]; + ReadOnlySpan hostNameStruct = serverName.Slice(HostNameStructOffset); + + if (hostNameStructLength != hostNameStruct.Length || nameType != NameType.HostName) + { + invalid = true; + return null; + } + + return GetSniFromHostNameStruct(hostNameStruct, out invalid); + } + + private static string GetSniFromHostNameStruct(ReadOnlySpan hostNameStruct, out bool invalid) + { + // https://tools.ietf.org/html/rfc3546#section-3.1 + // HostName is an opaque type (length of sufficient size for max data length is prepended) + const int HostNameLengthOffset = 0; + const int HostNameOffset = HostNameLengthOffset + sizeof(ushort); + + int hostNameLength = BinaryPrimitives.ReadUInt16BigEndian(hostNameStruct); + ReadOnlySpan hostName = hostNameStruct.Slice(HostNameOffset); + if (hostNameLength != hostName.Length) + { + invalid = true; + return null; + } + + invalid = false; + return DecodeString(hostName); + } + + private static string DecodeString(ReadOnlySpan bytes) + { + // https://tools.ietf.org/html/rfc3546#section-3.1 + // Per spec: + // If the hostname labels contain only US-ASCII characters, then the + // client MUST ensure that labels are separated only by the byte 0x2E, + // representing the dot character U+002E (requirement 1 in section 3.1 + // of [IDNA] notwithstanding). If the server needs to match the HostName + // against names that contain non-US-ASCII characters, it MUST perform + // the conversion operation described in section 4 of [IDNA], treating + // the HostName as a "query string" (i.e. the AllowUnassigned flag MUST + // be set). Note that IDNA allows labels to be separated by any of the + // Unicode characters U+002E, U+3002, U+FF0E, and U+FF61, therefore + // servers MUST accept any of these characters as a label separator. If + // the server only needs to match the HostName against names containing + // exclusively ASCII characters, it MUST compare ASCII names case- + // insensitively. + + string idnEncodedString; + try + { + idnEncodedString = s_encoding.GetString(bytes); + } + catch (DecoderFallbackException) + { + return null; + } + + try + { + return s_idnMapping.GetUnicode(idnEncodedString); + } + catch (ArgumentException) + { + // client has not done IDN mapping + return idnEncodedString; + } + } + + private static int ReadUInt24BigEndian(ReadOnlySpan bytes) + { + return (bytes[0] << 16) | (bytes[1] << 8) | bytes[2]; + } + + private static ReadOnlySpan SkipBytes(ReadOnlySpan bytes, int numberOfBytesToSkip) + { + return (numberOfBytesToSkip < bytes.Length) ? bytes.Slice(numberOfBytesToSkip) : ReadOnlySpan.Empty; + } + + // Opaque type is of structure: + // - length (minimum number of bytes to hold the max value) + // - data (length bytes) + // We will only use opaque types which are of max size: 255 (length = 1) or 2^16-1 (length = 2). + // We will call them SkipOpaqueType`length` + private static ReadOnlySpan SkipOpaqueType1(ReadOnlySpan bytes) + { + const int OpaqueTypeLengthSize = sizeof(byte); + if (bytes.Length < OpaqueTypeLengthSize) + { + return ReadOnlySpan.Empty; + } + + byte length = bytes[0]; + int totalBytes = OpaqueTypeLengthSize + length; + + return SkipBytes(bytes, totalBytes); + } + + private static ReadOnlySpan SkipOpaqueType2(ReadOnlySpan bytes, out bool invalid) + { + const int OpaqueTypeLengthSize = sizeof(ushort); + if (bytes.Length < OpaqueTypeLengthSize) + { + invalid = true; + return ReadOnlySpan.Empty; + } + + ushort length = BinaryPrimitives.ReadUInt16BigEndian(bytes); + int totalBytes = OpaqueTypeLengthSize + length; + + invalid = bytes.Length < totalBytes; + if (invalid) + { + return ReadOnlySpan.Empty; + } + else + { + return bytes.Slice(totalBytes); + } + } + + private static IdnMapping CreateIdnMapping() + { + return new IdnMapping() + { + // Per spec "AllowUnassigned flag MUST be set". See comment above GetSniFromServerNameList for more details. + AllowUnassigned = true + }; + } + + private static Encoding CreateEncoding() + { + return Encoding.GetEncoding("utf-8", new EncoderExceptionFallback(), new DecoderExceptionFallback()); + } + + private enum ContentType : byte + { + Handshake = 0x16 + } + + private enum HandshakeType : byte + { + ClientHello = 0x01 + } + + private enum ExtensionType : ushort + { + ServerName = 0x00 + } + + private enum NameType : byte + { + HostName = 0x00 + } + } +} diff --git a/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs b/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs index 609666aee497..1710fff4eb7f 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs @@ -49,6 +49,7 @@ internal SslAuthenticationOptions(SslServerAuthenticationOptions sslServerAuthen // Server specific options. CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode; ServerCertificate = sslServerAuthenticationOptions.ServerCertificate; + ServerCertSelectionDelegate = sslServerAuthenticationOptions._serverCertDelegate; } internal bool AllowRenegotiation { get; set; } @@ -66,6 +67,7 @@ internal SslAuthenticationOptions(SslServerAuthenticationOptions sslServerAuthen internal bool CheckCertName { get; set; } internal RemoteCertValidationCallback CertValidationDelegate { get; set; } internal LocalCertSelectionCallback CertSelectionDelegate { get; set; } + internal ServerCertCallback ServerCertSelectionDelegate { get; set; } } } diff --git a/src/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs b/src/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs index cf5b271a10b7..7e9420151b36 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs @@ -16,6 +16,7 @@ public class SslServerAuthenticationOptions private bool _allowRenegotiation = true; internal RemoteCertValidationCallback _certValidationDelegate; + internal ServerCertCallback _serverCertDelegate; public bool AllowRenegotiation { @@ -29,6 +30,8 @@ public bool AllowRenegotiation public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; } + public ServerCertificateSelectionCallback ServerCertificateSelectionCallback { get; set; } + public X509Certificate ServerCertificate { get; set; } public SslProtocols EnabledSslProtocols diff --git a/src/System.Net.Security/src/System/Net/Security/SslState.cs b/src/System.Net.Security/src/System/Net/Security/SslState.cs index 4fb420bd3347..05f437f46cc9 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslState.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslState.cs @@ -133,11 +133,16 @@ internal void ValidateCreateContext(SslServerAuthenticationOptions sslServerAuth throw new InvalidOperationException(SR.net_auth_client_server); } - if (sslServerAuthenticationOptions.ServerCertificate == null) + if (sslServerAuthenticationOptions.ServerCertificate == null && sslServerAuthenticationOptions._serverCertDelegate == null) { throw new ArgumentNullException(nameof(sslServerAuthenticationOptions.ServerCertificate)); } + if (sslServerAuthenticationOptions.ServerCertificate != null && sslServerAuthenticationOptions._serverCertDelegate != null) + { + throw new InvalidOperationException(SR.Format(SR.net_conflicting_options, nameof(ServerCertificateSelectionCallback))); + } + _exception = null; try { diff --git a/src/System.Net.Security/src/System/Net/Security/SslStream.cs b/src/System.Net.Security/src/System/Net/Security/SslStream.cs index 71f9e0181bce..eb6563c0b19f 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslStream.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStream.cs @@ -31,9 +31,12 @@ public enum EncryptionPolicy // A user delegate used to select local SSL certificate. public delegate X509Certificate LocalCertificateSelectionCallback(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers); + public delegate X509Certificate ServerCertificateSelectionCallback(object sender, string hostName); + // Internal versions of the above delegates. internal delegate bool RemoteCertValidationCallback(string host, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors); internal delegate X509Certificate LocalCertSelectionCallback(string targetHost, X509CertificateCollection localCertificates, X509Certificate2 remoteCertificate, string[] acceptableIssuers); + internal delegate X509Certificate ServerCertCallback(string hostName); public class SslStream : AuthenticatedStream { @@ -42,6 +45,7 @@ public class SslStream : AuthenticatedStream internal RemoteCertificateValidationCallback _userCertificateValidationCallback; internal LocalCertificateSelectionCallback _userCertificateSelectionCallback; + internal ServerCertificateSelectionCallback _userServerCertificateSelectionCallback; internal RemoteCertValidationCallback _certValidationDelegate; internal LocalCertSelectionCallback _certSelectionDelegate; internal EncryptionPolicy _encryptionPolicy; @@ -141,6 +145,17 @@ private X509Certificate UserCertSelectionCallbackWrapper(string targetHost, X509 return _userCertificateSelectionCallback(this, targetHost, localCertificates, remoteCertificate, acceptableIssuers); } + private X509Certificate ServerCertSelectionCallbackWrapper(string targetHost) + { + return _userServerCertificateSelectionCallback(this, targetHost); + } + + private void SetServerCertificateSelectionCallbackWrapper(SslServerAuthenticationOptions sslServerAuthenticationOptions) + { + _userServerCertificateSelectionCallback = sslServerAuthenticationOptions.ServerCertificateSelectionCallback; + sslServerAuthenticationOptions._serverCertDelegate = _userServerCertificateSelectionCallback == null ? null : new ServerCertCallback(ServerCertSelectionCallbackWrapper); + } + // // Client side auth. // @@ -236,6 +251,8 @@ private IAsyncResult BeginAuthenticateAsServer(SslServerAuthenticationOptions ss // Set the delegate on the options. sslServerAuthenticationOptions._certValidationDelegate = _certValidationDelegate; + SetServerCertificateSelectionCallbackWrapper(sslServerAuthenticationOptions); + _sslState.ValidateCreateContext(sslServerAuthenticationOptions); LazyAsyncResult result = new LazyAsyncResult(_sslState, asyncState, asyncCallback); diff --git a/src/System.Net.Security/tests/FunctionalTests/SniHelperTest.cs b/src/System.Net.Security/tests/FunctionalTests/SniHelperTest.cs new file mode 100644 index 000000000000..3dafcc083f16 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/SniHelperTest.cs @@ -0,0 +1,3255 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace System.Net.Security.Tests +{ + public class SniHelperTest + { + [Fact] + public void SniHelper_ValidData_Ok() + { + InvalidClientHello(s_validClientHello, -1, shouldPass: true); + } + + [Theory] + [MemberData(nameof(InvalidClientHelloData))] + public void SniHelper_InvalidData_Fails(int id, byte[] clientHello) + { + InvalidClientHello(clientHello, id, shouldPass: false); + } + + [Theory] + [MemberData(nameof(InvalidClientHelloDataTruncatedBytes))] + public void SniHelper_TruncatedData_Fails(int id, byte[] clientHello) + { + InvalidClientHello(clientHello, id, shouldPass: false); + } + + private void InvalidClientHello(byte[] clientHello, int id, bool shouldPass) + { + string ret = SniHelper.GetServerName(clientHello); + if (shouldPass) + Assert.NotNull(ret); + else + Assert.Null(ret); + } + + private static IEnumerable InvalidClientHelloData() + { + int id = 0; + foreach (byte[] invalidClientHello in InvalidClientHello()) + { + id++; + yield return new object[] { id, invalidClientHello }; + } + } + + private static IEnumerable InvalidClientHelloDataTruncatedBytes() + { + // converting to base64 first to remove duplicated test cases + var uniqueInvalidHellos = new HashSet(); + foreach (byte[] invalidClientHello in InvalidClientHello()) + { + for (int i = 0; i < invalidClientHello.Length - 1; i++) + { + uniqueInvalidHellos.Add(Convert.ToBase64String(invalidClientHello.Take(i).ToArray())); + } + } + + for (int i = 0; i < s_validClientHello.Length - 1; i++) + { + uniqueInvalidHellos.Add(Convert.ToBase64String(s_validClientHello.Take(i).ToArray())); + } + + int id = 0; + foreach (string invalidClientHello in uniqueInvalidHellos) + { + id++; + yield return new object[] { id, Convert.FromBase64String(invalidClientHello) }; + } + } + + private static byte[] s_validClientHello = new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x0C, 0x3C, 0x85, 0x78, 0xCA, + 0x67, 0x70, 0xAA, 0x38, 0xCB, + 0x28, 0xBC, 0xDC, 0x3E, 0x30, + 0xBF, 0x11, 0x96, 0x95, 0x1A, + 0xB9, 0xF0, 0x99, 0xA4, 0x91, + 0x09, 0x13, 0xB4, 0x89, 0x94, + 0x27, 0x2E, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + private static IEnumerable InvalidClientHello() + { + // This test covers following test cases: + // - Length of structure off by 1 (search for "length off by 1") + // - Length of structure is max length (search for "max length") + // - Type is invalid or unknown (i.e. SslPlainText.ClientType is not 0x16 - search for "unknown") + // - Invalid utf-8 characters + // in each case sni will be null or will cause parsing error - we only expect some parsing errors, + // anything else is considered a bug + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 - length off by 1 + 0x00, 0x02, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 - max length + 0xFF, 0xFF, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 - length off by 1 + 0x00, 0x01, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 - max length + 0xFF, 0xFF, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 - length off by 1 + 0x00, 0x01, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 - max length + 0xFF, 0xFF, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D - length off by 1 + 0x00, 0x15, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D - max length + 0xFF, 0xFF, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B - length off by 1 + 0x00, 0x03, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B - max length + 0xFF, 0xFF, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A - length off by 1 + 0x00, 0x09, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A - max length + 0xFF, 0xFF, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length - length off by 1 + 0x00, 0x35, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length - max length + 0xFF, 0xFF, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type - unknown + 0x01, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length - length off by 1 + 0x00, 0x38, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length - max length + 0xFF, 0xFF, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length - length off by 1 + 0x00, 0x3A, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length - max length + 0xFF, 0xFF, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) - unknown + 0x01, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length - length off by 1 + 0x00, 0x75, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length - max length + 0xFF, 0xFF, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods - length off by 1 + 0x02, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods - max length + 0xFF, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites - length off by 1 + 0x00, 0x2B, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites - max length + 0xFF, 0xFF, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId - length off by 1 + 0x01, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId - max length + 0xFF, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length - length off by 1 + 0x00, 0x00, 0xC8, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length - max length + 0xFF, 0xFF, 0xFF, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) - unknown + 0x00, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length - length off by 1 + 0x00, 0xCC, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length - max length + 0xFF, 0xFF, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) - unknown + 0x01, 0x03, 0x04, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x58, 0xAA, 0x5F, 0xE7, 0x22, + 0xCF, 0x9F, 0x59, 0x8A, 0xC5, + 0x8B, 0x87, 0xC7, 0x62, 0x32, + 0x98, 0xD4, 0xD8, 0xA2, 0xBE, + 0x77, 0xCE, 0xA9, 0xCE, 0x42, + 0x25, 0x5A, 0x8B, 0xEE, 0x16, + 0x80, 0xF1, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + + yield return new byte[] { + // SslPlainText.(ContentType+ProtocolVersion) + 0x16, 0x03, 0x03, + // SslPlainText.length + 0x00, 0xCB, + // Handshake.msg_type (client hello) + 0x01, + // Handshake.length + 0x00, 0x00, 0xC7, + // ClientHello.client_version + 0x03, 0x03, + // ClientHello.random + 0x0C, 0x3C, 0x85, 0x78, 0xCA, + 0x67, 0x70, 0xAA, 0x38, 0xCB, + 0x28, 0xBC, 0xDC, 0x3E, 0x30, + 0xBF, 0x11, 0x96, 0x95, 0x1A, + 0xB9, 0xF0, 0x99, 0xA4, 0x91, + 0x09, 0x13, 0xB4, 0x89, 0x94, + 0x27, 0x2E, + // ClientHello.SessionId + 0x00, + // ClientHello.cipher_suites + 0x00, 0x2A, 0xC0, 0x2C, 0xC0, + 0x2B, 0xC0, 0x30, 0xC0, 0x2F, + 0x00, 0x9F, 0x00, 0x9E, 0xC0, + 0x24, 0xC0, 0x23, 0xC0, 0x28, + 0xC0, 0x27, 0xC0, 0x0A, 0xC0, + 0x09, 0xC0, 0x14, 0xC0, 0x13, + 0x00, 0x9D, 0x00, 0x9C, 0x00, + 0x3D, 0x00, 0x3C, 0x00, 0x35, + 0x00, 0x2F, 0x00, 0x0A, + // ClientHello.compression_methods + 0x01, 0x01, + // ClientHello.extension_list_length + 0x00, 0x74, + // Extension.extension_type (server_name) + 0x00, 0x00, + // ServerNameListExtension.length + 0x00, 0x39, + // ServerName.length + 0x00, 0x37, + // ServerName.type + 0x00, + // HostName.length + 0x00, 0x34, + // HostName.bytes + 0x80, 0x80, 0x80, 0x80, 0x61, // 0x80 0x80 0x80 0x80 is a forbidden utf-8 sequence + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, + // Extension.extension_type (00 0A) + 0x00, 0x0A, + // Extension 0A + 0x00, 0x08, 0x00, 0x06, 0x00, + 0x1D, 0x00, 0x17, 0x00, 0x18, + // Extension.extension_type (00 0B) + 0x00, 0x0B, + // Extension 0B + 0x00, 0x02, 0x01, 0x00, + // Extension.extension_type (00 0D) + 0x00, 0x0D, + // Extension 0D + 0x00, 0x14, 0x00, 0x12, 0x04, + 0x01, 0x05, 0x01, 0x02, 0x01, + 0x04, 0x03, 0x05, 0x03, 0x02, + 0x03, 0x02, 0x02, 0x06, 0x01, + 0x06, 0x03, + // Extension.extension_type (00 23) + 0x00, 0x23, + // Extension 00 23 + 0x00, 0x00, + // Extension.extension_type (00 17) + 0x00, 0x17, + // Extension 17 + 0x00, 0x00, + // Extension.extension_type (FF 01) + 0xFF, 0x01, + // Extension FF01 + 0x00, 0x01, 0x00 + }; + } + } +} diff --git a/src/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs b/src/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs new file mode 100644 index 000000000000..55cf3e948330 --- /dev/null +++ b/src/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs @@ -0,0 +1,135 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Net.Test.Common; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace System.Net.Security.Tests +{ + using Configuration = System.Net.Test.Common.Configuration; + + public class SslStreamSniTest + { + [Theory] + [MemberData(nameof(HostNameData))] + public void SslStream_ClientSendsSNIServerReceives_Ok(string hostName) + { + X509Certificate serverCert = Configuration.Certificates.GetSelfSignedServerCertificate(); + + WithVirtualConnection((server, client) => + { + Task clientJob = Task.Run(() => { + client.AuthenticateAsClient(hostName); + }); + + SslServerAuthenticationOptions options = DefaultServerOptions(); + + int timesCallbackCalled = 0; + options.ServerCertificateSelectionCallback = (sender, actualHostName) => + { + timesCallbackCalled++; + Assert.Equal(hostName, actualHostName); + return serverCert; + }; + + var cts = new CancellationTokenSource(); + server.AuthenticateAsServerAsync(options, cts.Token).Wait(); + + Assert.Equal(1, timesCallbackCalled); + clientJob.Wait(); + }, + (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => + { + Assert.Equal(serverCert, certificate); + return true; + }); + } + + [Fact] + public void SslStream_NoSniFromClient_CallbackReturnsNull() + { + WithVirtualConnection((server, client) => + { + Task clientJob = Task.Run(() => { + Assert.Throws(() + => client.AuthenticateAsClient("test")); + }); + + int timesCallbackCalled = 0; + SslServerAuthenticationOptions options = DefaultServerOptions(); + options.ServerCertificateSelectionCallback = (sender, actualHostName) => + { + timesCallbackCalled++; + return null; + }; + + var cts = new CancellationTokenSource(); + Assert.Throws(WithAggregateExceptionUnwrapping(() => + server.AuthenticateAsServerAsync(options, cts.Token).Wait() + )); + + // to break connection so that client is not waiting + server.Dispose(); + + Assert.Equal(1, timesCallbackCalled); + + clientJob.Wait(); + }, + (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => + { + return true; + }); + } + + private static Action WithAggregateExceptionUnwrapping(Action a) + { + return () => { + try + { + a(); + } + catch (AggregateException e) + { + throw e.InnerException; + } + }; + } + + private static SslServerAuthenticationOptions DefaultServerOptions() + { + return new SslServerAuthenticationOptions() + { + ClientCertificateRequired = false, + EnabledSslProtocols = SslProtocols.Tls, + CertificateRevocationCheckMode = X509RevocationMode.NoCheck, + }; + } + + private void WithVirtualConnection(Action serverClientConnection, RemoteCertificateValidationCallback clientCertValidate) + { + VirtualNetwork vn = new VirtualNetwork(); + using (VirtualNetworkStream serverStream = new VirtualNetworkStream(vn, isServer: true), + clientStream = new VirtualNetworkStream(vn, isServer: false)) + using (SslStream server = new SslStream(serverStream, leaveInnerStreamOpen: false), + client = new SslStream(clientStream, leaveInnerStreamOpen: false, clientCertValidate)) + { + serverClientConnection(server, client); + } + } + + private static IEnumerable HostNameData() + { + yield return new object[] { "a" }; + yield return new object[] { "test" }; + // max allowed hostname length is 63 + yield return new object[] { new string('a', 63) }; + yield return new object[] { "\u017C\u00F3\u0142\u0107 g\u0119\u015Bl\u0105 ja\u017A\u0144. \u7EA2\u70E7. \u7167\u308A\u713C\u304D" }; + } + } +} diff --git a/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs index ae608d302b0b..61da0d226e68 100644 --- a/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs +++ b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs @@ -310,7 +310,11 @@ await serverSslStream.WriteAsync(new byte[] { 1 }, 0, 1) [Fact] public async Task SslStream_StreamToStream_Dispose_Throws() { - VirtualNetwork network = new VirtualNetwork(); + VirtualNetwork network = new VirtualNetwork() + { + DisableConnectionBreaking = true + }; + using (var clientStream = new VirtualNetworkStream(network, isServer: false)) using (var serverStream = new VirtualNetworkStream(network, isServer: true)) using (var clientSslStream = new SslStream(clientStream, false, AllowAnyServerCertificate)) diff --git a/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj index 8268fd077be5..c758241a3be2 100644 --- a/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj +++ b/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -90,10 +90,15 @@ + + src\SniHelper.cs + + + @@ -159,4 +164,4 @@ - \ No newline at end of file +