Skip to content

Commit f6d22cd

Browse files
authored
Add server-side SNI support (dotnet/corefx#28278)
* add initial implementation for server side SNI support * remove analyzerdata * add braces around single line if statements and inline simple functions * fix deadlock on linux * add test with special characters * IDN decoding * idn unmapping (with fallback) * apply feedback, fix netfx/uwp * rename the SNIHelper to SniHelper * rename test file as well (git does not like renames on windows) * change file casing in csproj * test should expect AuthenticationException * add SniHelper tests * apply review feedback * shorten SNI (limit is 63 bytes) * replace remaining constants * test behavior on truncated client hello * add structures descriptions * apply review feedback * get rid of the new dependency and add a test for invalid utf-8 bytes Commit migrated from dotnet/corefx@2d39212
1 parent c740861 commit f6d22cd

File tree

14 files changed

+3882
-8
lines changed

14 files changed

+3882
-8
lines changed

src/libraries/Common/tests/System/Net/VirtualNetwork/VirtualNetwork.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,29 @@ namespace System.Net.Test.Common
1010
{
1111
public class VirtualNetwork
1212
{
13+
public class VirtualNetworkConnectionBroken : Exception
14+
{
15+
public VirtualNetworkConnectionBroken() : base("Connection broken") { }
16+
}
17+
1318
private readonly int WaitForReadDataTimeoutMilliseconds = 30 * 1000;
14-
19+
1520
private readonly ConcurrentQueue<byte[]> _clientWriteQueue = new ConcurrentQueue<byte[]>();
1621
private readonly ConcurrentQueue<byte[]> _serverWriteQueue = new ConcurrentQueue<byte[]>();
1722

1823
private readonly SemaphoreSlim _clientDataAvailable = new SemaphoreSlim(0);
1924
private readonly SemaphoreSlim _serverDataAvailable = new SemaphoreSlim(0);
2025

26+
public bool DisableConnectionBreaking { get; set; } = false;
27+
private bool _connectionBroken = false;
28+
2129
public void ReadFrame(bool server, out byte[] buffer)
2230
{
31+
if (_connectionBroken)
32+
{
33+
throw new VirtualNetworkConnectionBroken();
34+
}
35+
2336
SemaphoreSlim semaphore;
2437
ConcurrentQueue<byte[]> packetQueue;
2538

@@ -39,6 +52,11 @@ public void ReadFrame(bool server, out byte[] buffer)
3952
throw new TimeoutException("VirtualNetwork: Timeout reading the next frame.");
4053
}
4154

55+
if (_connectionBroken)
56+
{
57+
throw new VirtualNetworkConnectionBroken();
58+
}
59+
4260
bool dequeueSucceeded = false;
4361
int remainingTries = 3;
4462
int backOffDelayMilliseconds = 2;
@@ -62,6 +80,11 @@ public void ReadFrame(bool server, out byte[] buffer)
6280

6381
public void WriteFrame(bool server, byte[] buffer)
6482
{
83+
if (_connectionBroken)
84+
{
85+
throw new VirtualNetworkConnectionBroken();
86+
}
87+
6588
SemaphoreSlim semaphore;
6689
ConcurrentQueue<byte[]> packetQueue;
6790

@@ -82,5 +105,15 @@ public void WriteFrame(bool server, byte[] buffer)
82105
packetQueue.Enqueue(innerBuffer);
83106
semaphore.Release();
84107
}
108+
109+
public void BreakConnection()
110+
{
111+
if (!DisableConnectionBreaking)
112+
{
113+
_connectionBroken = true;
114+
_serverDataAvailable.Release(1_000_000);
115+
_clientDataAvailable.Release(1_000_000);
116+
}
117+
}
85118
}
86119
}

src/libraries/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,5 +156,15 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, As
156156

157157
public override void EndWrite(IAsyncResult asyncResult) =>
158158
TaskToApm.End(asyncResult);
159+
160+
protected override void Dispose(bool disposing)
161+
{
162+
if (disposing)
163+
{
164+
_network.BreakConnection();
165+
}
166+
167+
base.Dispose(disposing);
168+
}
159169
}
160170
}

src/libraries/System.Net.Security/ref/System.Net.Security.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public enum EncryptionPolicy
3232
RequireEncryption = 0,
3333
}
3434
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);
35+
public delegate System.Security.Cryptography.X509Certificates.X509Certificate ServerCertificateSelectionCallback(object sender, string hostName);
36+
3537
public partial class NegotiateStream : AuthenticatedStream
3638
{
3739
public NegotiateStream(System.IO.Stream innerStream) : base(innerStream, false) { }
@@ -108,6 +110,7 @@ public class SslServerAuthenticationOptions
108110
public X509RevocationMode CertificateRevocationCheckMode { get { throw null; } set { } }
109111
public List<SslApplicationProtocol> ApplicationProtocols { get { throw null; } set { } }
110112
public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get { throw null; } set { } }
113+
public ServerCertificateSelectionCallback ServerCertificateSelectionCallback { get { throw null; } set { } }
111114
public EncryptionPolicy EncryptionPolicy { get { throw null; } set { } }
112115
}
113116
public partial class SslClientAuthenticationOptions

src/libraries/System.Net.Security/src/System.Net.Security.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<Compile Include="System\Net\FixedSizeReader.cs" />
2424
<Compile Include="System\Net\HelperAsyncResults.cs" />
2525
<Compile Include="System\Net\Logging\NetEventSource.cs" />
26+
<Compile Include="System\Net\Security\SniHelper.cs" />
2627
<Compile Include="System\Net\Security\SslApplicationProtocol.cs" />
2728
<Compile Include="System\Net\Security\SslAuthenticationOptions.cs" />
2829
<Compile Include="System\Net\Security\SslClientAuthenticationOptions.cs" />

src/libraries/System.Net.Security/src/System/Net/Security/SecureChannel.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -624,15 +624,26 @@ private bool AcquireClientCredentials(ref byte[] thumbPrint)
624624
//
625625
// Acquire Server Side Certificate information and set it on the class.
626626
//
627-
private bool AcquireServerCredentials(ref byte[] thumbPrint)
627+
private bool AcquireServerCredentials(ref byte[] thumbPrint, byte[] clientHello)
628628
{
629629
if (NetEventSource.IsEnabled)
630630
NetEventSource.Enter(this);
631631

632632
X509Certificate localCertificate = null;
633633
bool cachedCred = false;
634634

635-
if (_sslAuthenticationOptions.CertSelectionDelegate != null)
635+
if (_sslAuthenticationOptions.ServerCertSelectionDelegate != null)
636+
{
637+
string serverIdentity = SniHelper.GetServerName(clientHello);
638+
localCertificate = _sslAuthenticationOptions.ServerCertSelectionDelegate(serverIdentity);
639+
640+
if (localCertificate == null)
641+
{
642+
throw new AuthenticationException(SR.net_ssl_io_no_server_cert);
643+
}
644+
}
645+
// This probably never gets called as this is a client options delegate
646+
else if (_sslAuthenticationOptions.CertSelectionDelegate != null)
636647
{
637648
X509CertificateCollection tempCollection = new X509CertificateCollection();
638649
tempCollection.Add(_sslAuthenticationOptions.ServerCertificate);
@@ -744,7 +755,6 @@ private SecurityStatusPal GenerateToken(byte[] input, int offset, int count, ref
744755
#if TRACE_VERBOSE
745756
if (NetEventSource.IsEnabled) NetEventSource.Enter(this, $"_refreshCredentialNeeded = {_refreshCredentialNeeded}");
746757
#endif
747-
748758
if (offset < 0 || offset > (input == null ? 0 : input.Length))
749759
{
750760
NetEventSource.Fail(this, "Argument 'offset' out of range.");
@@ -786,7 +796,7 @@ private SecurityStatusPal GenerateToken(byte[] input, int offset, int count, ref
786796
if (_refreshCredentialNeeded)
787797
{
788798
cachedCreds = _sslAuthenticationOptions.IsServer
789-
? AcquireServerCredentials(ref thumbPrint)
799+
? AcquireServerCredentials(ref thumbPrint, input)
790800
: AcquireClientCredentials(ref thumbPrint);
791801
}
792802

0 commit comments

Comments
 (0)