public async Task SslStream_SameCertUsedForClientAndServer_Ok() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new SslStream(stream1, true, AllowAnyCertificate)) using (var server = new SslStream(stream2, true, AllowAnyCertificate)) using (X509Certificate2 certificate = Configuration.Certificates.GetServerCertificate()) { // Using the same certificate for server and client auth. X509Certificate2Collection clientCertificateCollection = new X509Certificate2Collection(certificate); Task t1 = server.AuthenticateAsServerAsync(certificate, true, false); Task t2 = client.AuthenticateAsClientAsync( certificate.GetNameInfo(X509NameType.SimpleName, false), clientCertificateCollection, false); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); if (!PlatformDetection.IsWindows7 || Capability.IsTrustedRootCertificateInstalled()) { // https://technet.microsoft.com/en-us/library/hh831771.aspx#BKMK_Changes2012R2 // Starting with Windows 8, the "Management of trusted issuers for client authentication" has changed: // The behavior to send the Trusted Issuers List by default is off. // // In Windows 7 the Trusted Issuers List is sent within the Server Hello TLS record. This list is built // by the server using certificates from the Trusted Root Authorities certificate store. // The client side will use the Trusted Issuers List, if not empty, to filter proposed certificates. Assert.True(client.IsMutuallyAuthenticated); Assert.True(server.IsMutuallyAuthenticated); } } }
public async Task SslStream_UntrustedCaWithCustomCallback_Throws() { var options = new SslClientAuthenticationOptions() { TargetHost = "localhost" }; options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { chain.ChainPolicy.ExtraStore.AddRange(_serverChain); chain.ChainPolicy.CustomTrustStore.Add(_serverChain[_serverChain.Count - 1]); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; // This should work and we should be able to trust the chain. Assert.True(chain.Build((X509Certificate2)certificate)); // Reject it in custom callback to simulate for example pinning. return(false); }; (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); using (clientStream) using (serverStream) using (SslStream client = new SslStream(clientStream)) using (SslStream server = new SslStream(serverStream)) { Task t1 = client.AuthenticateAsClientAsync(options, default); Task t2 = server.AuthenticateAsServerAsync(_serverCert); await Assert.ThrowsAsync <AuthenticationException>(() => t1); // Server side should finish since we run custom callback after handshake is done. await t2; } }
public async Task Read_CorrectlyUnlocksAfterFailure() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); var clientStream = new ThrowingDelegatingStream(stream1); using (var clientSslStream = new SslStream(clientStream, false, AllowAnyServerCertificate)) using (var serverSslStream = new SslStream(stream2)) { await DoHandshake(clientSslStream, serverSslStream); // Throw an exception from the wrapped stream's read operation clientStream.ExceptionToThrow = new FormatException(); IOException thrown = await Assert.ThrowsAsync <IOException>(() => ReadAsync(clientSslStream, new byte[1], 0, 1)); Assert.Same(clientStream.ExceptionToThrow, thrown.InnerException); clientStream.ExceptionToThrow = null; // Validate that the SslStream continues to be usable for (byte b = 42; b < 52; b++) // arbitrary test values { await WriteAsync(serverSslStream, new byte[1] { b }, 0, 1); byte[] buffer = new byte[1]; Assert.Equal(1, await ReadAsync(clientSslStream, buffer, 0, 1)); Assert.Equal(b, buffer[0]); } } }
public async Task SslStream_StreamToStream_ServerInitiatedCloseNotify_Ok() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new SslStream(stream1, true, AllowAnyServerCertificate)) using (var server = new SslStream(stream2)) using (X509Certificate2 certificate = Configuration.Certificates.GetServerCertificate()) { var handshake = new Task[2]; handshake[0] = server.AuthenticateAsServerAsync(certificate); handshake[1] = client.AuthenticateAsClientAsync(certificate.GetNameInfo(X509NameType.SimpleName, false)); await Task.WhenAll(handshake).TimeoutAfter(TestConfiguration.PassingTestTimeoutMilliseconds); var readBuffer = new byte[1024]; await server.ShutdownAsync(); int bytesRead = await client.ReadAsync(readBuffer, 0, readBuffer.Length); // close_notify received by the client. Assert.Equal(0, bytesRead); await client.ShutdownAsync(); bytesRead = await server.ReadAsync(readBuffer, 0, readBuffer.Length); // close_notify received by the server. Assert.Equal(0, bytesRead); } }
public async Task SslStream_StreamToStream_DataAfterShutdown_Fail() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new SslStream(stream1, true, AllowAnyServerCertificate)) using (var server = new SslStream(stream2)) using (X509Certificate2 certificate = Configuration.Certificates.GetServerCertificate()) { var handshake = new Task[2]; handshake[0] = server.AuthenticateAsServerAsync(certificate); handshake[1] = client.AuthenticateAsClientAsync(certificate.GetNameInfo(X509NameType.SimpleName, false)); await Task.WhenAll(handshake).TimeoutAfter(TestConfiguration.PassingTestTimeoutMilliseconds); var buffer = new byte[1024]; Assert.True(client.CanWrite); await client.ShutdownAsync(); Assert.False(client.CanWrite); await Assert.ThrowsAsync <InvalidOperationException>(() => client.ShutdownAsync()); await Assert.ThrowsAsync <InvalidOperationException>(() => client.WriteAsync(buffer, 0, buffer.Length)); } }
public async Task SslStream_StreamToStream_HandshakeAlert_Ok() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new SslStream(stream1, true, AllowAnyServerCertificate)) using (var server = new SslStream(stream2, true, FailClientCertificate)) using (X509Certificate2 certificate = Configuration.Certificates.GetServerCertificate()) { Task serverAuth = server.AuthenticateAsServerAsync(certificate); await client.AuthenticateAsClientAsync(certificate.GetNameInfo(X509NameType.SimpleName, false)); byte[] buffer = new byte[1024]; // Schannel semantics require that Decrypt is called to receive an alert. await client.WriteAsync(buffer, 0, buffer.Length); var exception = await Assert.ThrowsAsync <IOException>(() => client.ReadAsync(buffer, 0, buffer.Length)); Assert.IsType <Win32Exception>(exception.InnerException); var win32ex = (Win32Exception)exception.InnerException; // The Schannel HResults for each alert are documented here: // https://msdn.microsoft.com/en-us/library/windows/desktop/dd721886(v=vs.85).aspx Assert.Equal(SEC_E_CERT_UNKNOWN, unchecked ((uint)win32ex.NativeErrorCode)); await Assert.ThrowsAsync <AuthenticationException>(() => serverAuth); await Assert.ThrowsAsync <AuthenticationException>(() => server.WriteAsync(buffer, 0, buffer.Length)); await Assert.ThrowsAsync <AuthenticationException>(() => server.ReadAsync(buffer, 0, buffer.Length)); } }
public async Task NegotiateStream_StreamToStream_Successive_CancelableReadsWrites() { if (!SupportsCancelableReadsWrites) { return; } byte[] recvBuf = new byte[s_sampleMsg.Length]; (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var clientStream = new DelayStream(stream1)) using (var serverStream = new DelayStream(stream2)) using (var client = new NegotiateStream(clientStream)) using (var server = new NegotiateStream(serverStream)) { await TestConfiguration.WhenAllOrAnyFailedWithTimeout( AuthenticateAsClientAsync(client, CredentialCache.DefaultNetworkCredentials, string.Empty), AuthenticateAsServerAsync(server)); clientStream.DelayMilliseconds = int.MaxValue; serverStream.DelayMilliseconds = int.MaxValue; var cts = new CancellationTokenSource(); Task t = WriteAsync(client, s_sampleMsg, 0, s_sampleMsg.Length, cts.Token); Assert.False(t.IsCompleted); cts.Cancel(); await Assert.ThrowsAnyAsync <OperationCanceledException>(() => t); cts = new CancellationTokenSource(); t = ReadAsync(server, s_sampleMsg, 0, s_sampleMsg.Length, cts.Token); Assert.False(t.IsCompleted); cts.Cancel(); await Assert.ThrowsAnyAsync <OperationCanceledException>(() => t); } }
public async Task Write_CorrectlyUnlocksAfterFailure() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); var clientStream = new ThrowingDelegatingStream(stream1); using (var clientSslStream = new SslStream(clientStream, false, AllowAnyServerCertificate)) using (var serverSslStream = new SslStream(stream2)) { await DoHandshake(clientSslStream, serverSslStream); // Throw an exception from the wrapped stream's write operation clientStream.ExceptionToThrow = new FormatException(); IOException thrown = await Assert.ThrowsAsync <IOException>(() => WriteAsync(clientSslStream, new byte[1], 0, 1)); Assert.Same(clientStream.ExceptionToThrow, thrown.InnerException); clientStream.ExceptionToThrow = null; // Validate that the SslStream continues to be writable. However, the stream is still largely // unusable: because the previously encrypted data won't have been written to the underlying // stream and thus not received by the reader, if we tried to validate this data being received // by the reader, it would likely fail with a decryption error. await WriteAsync(clientSslStream, new byte[1] { 42 }, 0, 1); } }
public async Task DisposeAsync_Connected_ClosesStream() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); var trackingStream1 = new CallTrackingStream(stream1); var trackingStream2 = new CallTrackingStream(stream2); var clientStream = new SslStream(trackingStream1, false, delegate { return(true); }); var serverStream = new SslStream(trackingStream2, false, delegate { return(true); }); using (X509Certificate2 certificate = Configuration.Certificates.GetServerCertificate()) { await TestConfiguration.WhenAllOrAnyFailedWithTimeout( clientStream.AuthenticateAsClientAsync(certificate.GetNameInfo(X509NameType.SimpleName, false)), serverStream.AuthenticateAsServerAsync(certificate)); } Assert.Equal(0, trackingStream1.TimesCalled(nameof(Stream.DisposeAsync))); await clientStream.DisposeAsync(); Assert.NotEqual(0, trackingStream1.TimesCalled(nameof(Stream.DisposeAsync))); Assert.Equal(0, trackingStream2.TimesCalled(nameof(Stream.DisposeAsync))); await serverStream.DisposeAsync(); Assert.NotEqual(0, trackingStream2.TimesCalled(nameof(Stream.DisposeAsync))); }
public async Task SslStream_UntrustedCaWithCustomCallback_OK() { var clientOptions = new SslClientAuthenticationOptions() { TargetHost = "localhost" }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { chain.ChainPolicy.CustomTrustStore.Add(_serverChain[_serverChain.Count - 1]); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; bool result = chain.Build((X509Certificate2)certificate); Assert.True(result); return(result); }; var serverOptions = new SslServerAuthenticationOptions(); serverOptions.ServerCertificateContext = SslStreamCertificateContext.Create(_serverCert, _serverChain); (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); using (clientStream) using (serverStream) using (SslStream client = new SslStream(clientStream)) using (SslStream server = new SslStream(serverStream)) { Task t1 = client.AuthenticateAsClientAsync(clientOptions, CancellationToken.None); Task t2 = server.AuthenticateAsServerAsync(serverOptions, CancellationToken.None); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); } }
public async Task NegotiateStream_StreamToStream_Authenticated_DisposeAsync(int delay) { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); await using (var client = new NegotiateStream(new DelayStream(stream1, delay))) await using (var server = new NegotiateStream(new DelayStream(stream2, delay))) { Assert.False(client.IsServer); Assert.False(server.IsServer); Assert.False(client.IsAuthenticated); Assert.False(server.IsAuthenticated); Assert.False(client.IsMutuallyAuthenticated); Assert.False(server.IsMutuallyAuthenticated); Assert.False(client.IsEncrypted); Assert.False(server.IsEncrypted); Assert.False(client.IsSigned); Assert.False(server.IsSigned); await TestConfiguration.WhenAllOrAnyFailedWithTimeout( AuthenticateAsClientAsync(client, CredentialCache.DefaultNetworkCredentials, string.Empty), AuthenticateAsServerAsync(server)); } }
public async Task SslStream_StreamToStream_DuplicateOptions_Throws() { RemoteCertificateValidationCallback rCallback = (sender, certificate, chain, errors) => { return(true); }; LocalCertificateSelectionCallback lCallback = (sender, host, localCertificates, remoteCertificate, issuers) => { return(null); }; (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); using (clientStream) using (serverStream) using (var client = new SslStream(clientStream, false, rCallback, lCallback, EncryptionPolicy.RequireEncryption)) using (var server = new SslStream(serverStream, false, rCallback)) using (X509Certificate2 certificate = Configuration.Certificates.GetServerCertificate()) { SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions(); clientOptions.RemoteCertificateValidationCallback = AllowAnyServerCertificate; clientOptions.TargetHost = certificate.GetNameInfo(X509NameType.SimpleName, false); SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions(); serverOptions.ServerCertificate = certificate; serverOptions.RemoteCertificateValidationCallback = AllowAnyServerCertificate; Task t1 = Assert.ThrowsAsync <InvalidOperationException>(() => client.AuthenticateAsClientAsync(TestAuthenticateAsync, clientOptions)); Task t2 = Assert.ThrowsAsync <InvalidOperationException>(() => server.AuthenticateAsServerAsync(TestAuthenticateAsync, serverOptions)); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); } }
public async Task NegotiateStream_EndReadEndWriteInvalidParameter_Throws() { byte[] recvBuf = new byte[s_sampleMsg.Length]; (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new NegotiateStream(stream1)) using (var server = new NegotiateStream(stream2)) { await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(CredentialCache.DefaultNetworkCredentials, string.Empty), server.AuthenticateAsServerAsync()); await TestConfiguration.WhenAllOrAnyFailedWithTimeout( Task.Factory.FromAsync(client.BeginWrite, (asyncResult) => { NegotiateStream authStream = (NegotiateStream)asyncResult.AsyncState; AssertExtensions.Throws <ArgumentNullException>(nameof(asyncResult), () => authStream.EndWrite(null)); IAsyncResult result = new MyAsyncResult(); AssertExtensions.Throws <ArgumentException>(nameof(asyncResult), () => authStream.EndWrite(result)); }, s_sampleMsg, 0, s_sampleMsg.Length, client), Task.Factory.FromAsync(server.BeginRead, (asyncResult) => { NegotiateStream authStream = (NegotiateStream)asyncResult.AsyncState; AssertExtensions.Throws <ArgumentNullException>(nameof(asyncResult), () => authStream.EndRead(null)); IAsyncResult result = new MyAsyncResult(); AssertExtensions.Throws <ArgumentException>(nameof(asyncResult), () => authStream.EndRead(result)); }, recvBuf, 0, s_sampleMsg.Length, server)); } }
public async Task NegotiateStream_StreamContractTest_Success() { (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); using (clientStream) using (serverStream) using (var client = new NegotiateStream(clientStream)) using (var server = new NegotiateStream(serverStream)) { Assert.False(client.CanSeek); Assert.False(client.CanRead); Assert.False(client.CanTimeout); Assert.False(client.CanWrite); Assert.False(server.CanSeek); Assert.False(server.CanRead); Assert.False(server.CanTimeout); Assert.False(server.CanWrite); Assert.Throws <InvalidOperationException>(() => client.ReadTimeout); Assert.Throws <InvalidOperationException>(() => client.WriteTimeout); Assert.Throws <NotSupportedException>(() => client.Length); Assert.Throws <NotSupportedException>(() => client.Position); Assert.Throws <NotSupportedException>(() => client.Seek(0, new SeekOrigin())); await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(), server.AuthenticateAsServerAsync()); Assert.True(client.CanRead); Assert.True(client.CanWrite); Assert.True(server.CanRead); Assert.True(server.CanWrite); } }
public async Task NegotiateStream_EndAuthenticateInvalidParameter_Throws() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new NegotiateStream(stream1)) using (var server = new NegotiateStream(stream2)) { await TestConfiguration.WhenAllOrAnyFailedWithTimeout( Task.Factory.FromAsync(client.BeginAuthenticateAsClient, (asyncResult) => { NegotiateStream authStream = (NegotiateStream)asyncResult.AsyncState; AssertExtensions.Throws <ArgumentNullException>(nameof(asyncResult), () => authStream.EndAuthenticateAsClient(null)); IAsyncResult result = new MyAsyncResult(); AssertExtensions.Throws <ArgumentException>(nameof(asyncResult), () => authStream.EndAuthenticateAsClient(result)); authStream.EndAuthenticateAsClient(asyncResult); }, CredentialCache.DefaultNetworkCredentials, string.Empty, client), Task.Factory.FromAsync(server.BeginAuthenticateAsServer, (asyncResult) => { NegotiateStream authStream = (NegotiateStream)asyncResult.AsyncState; AssertExtensions.Throws <ArgumentNullException>(nameof(asyncResult), () => authStream.EndAuthenticateAsServer(null)); IAsyncResult result = new MyAsyncResult(); AssertExtensions.Throws <ArgumentException>(nameof(asyncResult), () => authStream.EndAuthenticateAsServer(result)); authStream.EndAuthenticateAsServer(asyncResult); }, server)); } }
public void NegotiateStream_NullServicePrincipalName_Throws() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new NegotiateStream(stream1)) using (var server = new NegotiateStream(stream2)) { AssertExtensions.Throws <ArgumentNullException>("servicePrincipalName", () => client.AuthenticateAsClient(CredentialCache.DefaultNetworkCredentials, null)); } }
public void NegotiateStream_NullCredential_Throws() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new NegotiateStream(stream1)) using (var server = new NegotiateStream(stream2)) { AssertExtensions.Throws <ArgumentNullException>("credential", () => client.AuthenticateAsClient(null, TargetName)); } }
private async Task WithVirtualConnection(Func <SslStream, SslStream, Task> serverClientConnection, RemoteCertificateValidationCallback clientCertValidate) { (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); using (SslStream server = new SslStream(serverStream, leaveInnerStreamOpen: false), client = new SslStream(clientStream, leaveInnerStreamOpen: false, clientCertValidate)) { await serverClientConnection(server, client); } }
public async Task NegotiateStream_StreamToStream_Authentication_EmptyCredentials_Fails() { string targetName = "testTargetName"; // Ensure there is no confusion between DefaultCredentials / DefaultNetworkCredentials and a // NetworkCredential object with empty user, password and domain. NetworkCredential emptyNetworkCredential = new NetworkCredential("", "", ""); Assert.NotEqual(emptyNetworkCredential, CredentialCache.DefaultCredentials); Assert.NotEqual(emptyNetworkCredential, CredentialCache.DefaultNetworkCredentials); (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new NegotiateStream(stream1)) using (var server = new NegotiateStream(stream2)) { Assert.False(client.IsAuthenticated); Assert.False(server.IsAuthenticated); Task[] auth = new Task[2]; auth[0] = AuthenticateAsClientAsync(client, emptyNetworkCredential, targetName); auth[1] = AuthenticateAsServerAsync(server); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth); // Expected Client property values: Assert.True(client.IsAuthenticated); Assert.Equal(TokenImpersonationLevel.Identification, client.ImpersonationLevel); Assert.Equal(IsEncryptedAndSigned, client.IsEncrypted); Assert.False(client.IsMutuallyAuthenticated); Assert.False(client.IsServer); Assert.Equal(IsEncryptedAndSigned, client.IsSigned); Assert.False(client.LeaveInnerStreamOpen); IIdentity serverIdentity = client.RemoteIdentity; Assert.Equal("NTLM", serverIdentity.AuthenticationType); Assert.True(serverIdentity.IsAuthenticated); Assert.Equal(targetName, serverIdentity.Name); // Expected Server property values: Assert.True(server.IsAuthenticated); Assert.Equal(TokenImpersonationLevel.Identification, server.ImpersonationLevel); Assert.Equal(IsEncryptedAndSigned, server.IsEncrypted); Assert.False(server.IsMutuallyAuthenticated); Assert.True(server.IsServer); Assert.Equal(IsEncryptedAndSigned, server.IsSigned); Assert.False(server.LeaveInnerStreamOpen); IIdentity clientIdentity = server.RemoteIdentity; Assert.Equal("NTLM", clientIdentity.AuthenticationType); Assert.False(clientIdentity.IsAuthenticated); // On .NET Desktop: Assert.True(clientIdentity.IsAuthenticated); IdentityValidator.AssertHasName(clientIdentity, new SecurityIdentifier(WellKnownSidType.AnonymousSid, null).Translate(typeof(NTAccount)).Value); } }
public void NegotiateStream_DisposedState_Throws() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new NegotiateStream(stream1)) using (var server = new NegotiateStream(stream2)) { client.Dispose(); Assert.Throws <ObjectDisposedException>(() => client.AuthenticateAsClient()); } }
public void NegotiateStream_InvalidPolicy_Throws() { var policy = new ExtendedProtectionPolicy(PolicyEnforcement.Never); (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new NegotiateStream(stream1)) using (var server = new NegotiateStream(stream2)) { // If ExtendedProtection is on, either CustomChannelBinding or CustomServiceNames must be set. AssertExtensions.Throws <ArgumentException>(nameof(policy), () => server.AuthenticateAsServer(policy)); } }
public void NegotiateStream_StreamToStream_Flush_Propagated() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var stream = new CallTrackingStream(stream1)) using (var negotiateStream = new NegotiateStream(stream)) using (stream2) { Assert.Equal(0, stream.TimesCalled(nameof(Stream.Flush))); negotiateStream.Flush(); Assert.NotEqual(0, stream.TimesCalled(nameof(Stream.Flush))); } }
public async Task SslStream_NestedAuth_Throws() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var ssl = new SslStream(stream1)) using (stream2) { // Start handshake. Task task = ssl.AuthenticateAsClientAsync("foo.com", null, SslProtocols.Tls12, false); // Do it again without waiting for previous one to finish. await Assert.ThrowsAsync <InvalidOperationException>(() => ssl.AuthenticateAsClientAsync("foo.com", null, SslProtocols.Tls12, false)); } }
private static NegotiatedParams ConnectAndGetNegotiatedParams(ConnectionParams serverParams, ConnectionParams clientParams) { (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); using (clientStream) using (serverStream) using (SslStream server = new SslStream(serverStream, leaveInnerStreamOpen: false), client = new SslStream(clientStream, leaveInnerStreamOpen: false)) { var serverOptions = new SslServerAuthenticationOptions(); serverOptions.ServerCertificate = Configuration.Certificates.GetSelfSignedServerCertificate(); serverOptions.EncryptionPolicy = serverParams.EncryptionPolicy; serverOptions.EnabledSslProtocols = serverParams.SslProtocols; serverOptions.CipherSuitesPolicy = serverParams.CipherSuitesPolicy; var clientOptions = new SslClientAuthenticationOptions(); clientOptions.EncryptionPolicy = clientParams.EncryptionPolicy; clientOptions.EnabledSslProtocols = clientParams.SslProtocols; clientOptions.CipherSuitesPolicy = clientParams.CipherSuitesPolicy; clientOptions.TargetHost = "test"; clientOptions.RemoteCertificateValidationCallback = new RemoteCertificateValidationCallback((object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => { return(true); }); Exception failure = WaitForSecureConnection(client, clientOptions, server, serverOptions).GetAwaiter().GetResult(); if (failure == null) { // send some bytes, make sure they can talk byte[] data = new byte[] { 1, 2, 3 }; byte[] receivedData = new byte[1]; Task serverTask = server.WriteAsync(data, 0, data.Length); for (int i = 0; i < data.Length; i++) { Assert.True(client.ReadAsync(receivedData, 0, 1).Wait(TestConfiguration.PassingTestTimeoutMilliseconds), $"Read task failed to finish in {TestConfiguration.PassingTestTimeoutMilliseconds}ms."); Assert.Equal(data[i], receivedData[0]); } Assert.True(serverTask.Wait(TestConfiguration.PassingTestTimeoutMilliseconds), $"WriteTask failed to finish in {TestConfiguration.PassingTestTimeoutMilliseconds}ms."); return(new NegotiatedParams(server, client)); } else { return(new NegotiatedParams(failure)); } } }
public async Task SslStream_StreamToStream_Dispose_Throws() { if (this is SslStreamStreamToStreamTest_SyncBase) { // This test assumes operations complete asynchronously. return; } (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var clientSslStream = new SslStream(DelegateDelegatingStream.NopDispose(stream1), false, AllowAnyServerCertificate)) { var serverSslStream = new SslStream(DelegateDelegatingStream.NopDispose(stream2)); await DoHandshake(clientSslStream, serverSslStream); var serverBuffer = new byte[1]; Task serverReadTask = ReadAsync(serverSslStream, serverBuffer, 0, serverBuffer.Length); await WriteAsync(serverSslStream, new byte[] { 1 }, 0, 1) .WaitAsync(TestConfiguration.PassingTestTimeout); // Shouldn't throw, the context is disposed now. // Since the server read task is in progress, the read buffer is not returned to ArrayPool. serverSslStream.Dispose(); // Read in client var clientBuffer = new byte[1]; await ReadAsync(clientSslStream, clientBuffer, 0, clientBuffer.Length); Assert.Equal(1, clientBuffer[0]); await WriteAsync(clientSslStream, new byte[] { 2 }, 0, 1); // We're inconsistent as to whether the ObjectDisposedException is thrown directly // or wrapped in an IOException. For Begin/End, it's always wrapped; for Async, // it's only wrapped on .NET Framework. if (this is SslStreamStreamToStreamTest_BeginEnd || PlatformDetection.IsNetFramework) { await Assert.ThrowsAsync <ObjectDisposedException>(() => serverReadTask); } else { IOException serverException = await Assert.ThrowsAsync <IOException>(() => serverReadTask); Assert.IsType <ObjectDisposedException>(serverException.InnerException); } await Assert.ThrowsAsync <ObjectDisposedException>(() => ReadAsync(serverSslStream, serverBuffer, 0, serverBuffer.Length)); // Now, there is no pending read, so the internal buffer will be returned to ArrayPool. serverSslStream.Dispose(); await Assert.ThrowsAsync <ObjectDisposedException>(() => ReadAsync(serverSslStream, serverBuffer, 0, serverBuffer.Length)); } }
public async Task NegotiateStream_StreamToStream_Authentication_TargetName_Success() { string targetName = "testTargetName"; (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new NegotiateStream(stream1)) using (var server = new NegotiateStream(stream2)) { Assert.False(client.IsAuthenticated); Assert.False(server.IsAuthenticated); Assert.False(client.IsMutuallyAuthenticated); Assert.False(server.IsMutuallyAuthenticated); Task[] auth = new Task[2]; auth[0] = AuthenticateAsClientAsync(client, CredentialCache.DefaultNetworkCredentials, targetName); auth[1] = AuthenticateAsServerAsync(server); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth); // Expected Client property values: Assert.True(client.IsAuthenticated); Assert.Equal(TokenImpersonationLevel.Identification, client.ImpersonationLevel); Assert.Equal(IsEncryptedAndSigned, client.IsEncrypted); Assert.False(client.IsMutuallyAuthenticated); Assert.False(client.IsServer); Assert.Equal(IsEncryptedAndSigned, client.IsSigned); Assert.False(client.LeaveInnerStreamOpen); IIdentity serverIdentity = client.RemoteIdentity; Assert.Equal("NTLM", serverIdentity.AuthenticationType); Assert.True(serverIdentity.IsAuthenticated); Assert.Equal(targetName, serverIdentity.Name); // Expected Server property values: Assert.True(server.IsAuthenticated); Assert.Equal(TokenImpersonationLevel.Identification, server.ImpersonationLevel); Assert.Equal(IsEncryptedAndSigned, server.IsEncrypted); Assert.False(server.IsMutuallyAuthenticated); Assert.True(server.IsServer); Assert.Equal(IsEncryptedAndSigned, server.IsSigned); Assert.False(server.LeaveInnerStreamOpen); IIdentity clientIdentity = server.RemoteIdentity; Assert.Equal("NTLM", clientIdentity.AuthenticationType); Assert.True(clientIdentity.IsAuthenticated); IdentityValidator.AssertIsCurrentIdentity(clientIdentity); } }
public async Task SslStream_TargetHostName_Succeeds(bool useEmptyName) { string targetName = useEmptyName ? string.Empty : Guid.NewGuid().ToString("N"); int count = 0; (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); using (clientStream) using (serverStream) using (var client = new SslStream(clientStream)) using (var server = new SslStream(serverStream)) using (X509Certificate2 certificate = Configuration.Certificates.GetServerCertificate()) { // It should be empty before handshake. Assert.Equal(string.Empty, client.TargetHostName); Assert.Equal(string.Empty, server.TargetHostName); SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions() { TargetHost = targetName }; clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { SslStream stream = (SslStream)sender; Assert.Equal(targetName, stream.TargetHostName); count++; return(true); }; SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions(); serverOptions.ServerCertificateSelectionCallback = (sender, name) => { SslStream stream = (SslStream)sender; Assert.Equal(targetName, stream.TargetHostName); return(certificate); }; await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(clientOptions), server.AuthenticateAsServerAsync(serverOptions)); await TestHelper.PingPong(client, server); Assert.Equal(targetName, client.TargetHostName); Assert.Equal(targetName, server.TargetHostName); Assert.Equal(1, count); } }
public async Task SslStream_UntrustedCaWithCustomCallback_Throws(bool customCallback) { string errorMessage; var clientOptions = new SslClientAuthenticationOptions() { TargetHost = "localhost" }; if (customCallback) { clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { // Add only root CA to verify that peer did send intermediate CA cert. chain.ChainPolicy.CustomTrustStore.Add(certificates.serverChain[certificates.serverChain.Count - 1]); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; // This should work and we should be able to trust the chain. Assert.True(chain.Build((X509Certificate2)certificate)); // Reject it in custom callback to simulate for example pinning. return(false); }; errorMessage = "RemoteCertificateValidationCallback"; } else { // On Windows we hand whole chain to OS so they can always see the root CA. errorMessage = PlatformDetection.IsWindows ? "UntrustedRoot" : "PartialChain"; } var serverOptions = new SslServerAuthenticationOptions(); serverOptions.ServerCertificateContext = SslStreamCertificateContext.Create(certificates.serverCert, certificates.serverChain); (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); using (clientStream) using (serverStream) using (SslStream client = new SslStream(clientStream)) using (SslStream server = new SslStream(serverStream)) { Task t1 = client.AuthenticateAsClientAsync(clientOptions, CancellationToken.None); Task t2 = server.AuthenticateAsServerAsync(serverOptions, CancellationToken.None); var e = await Assert.ThrowsAsync <AuthenticationException>(() => t1); Assert.Contains(errorMessage, e.Message); // Server side should finish since we run custom callback after handshake is done. await t2; } }
public async Task SslStream_StreamToStream_Authentication_Success(X509Certificate serverCert = null, X509Certificate clientCert = null) { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new SslStream(stream1, false, AllowAnyServerCertificate)) using (var server = new SslStream(stream2, false, delegate { return(true); })) { await DoHandshake(client, server, serverCert, clientCert); Assert.True(client.IsAuthenticated); Assert.True(server.IsAuthenticated); } clientCert?.Dispose(); serverCert?.Dispose(); }
public async Task NegotiateStream_DoubleAuthentication_Throws() { (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); using (var client = new NegotiateStream(stream1)) using (var server = new NegotiateStream(stream2)) { await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(), server.AuthenticateAsServerAsync()); await TestConfiguration.WhenAllOrAnyFailedWithTimeout( Assert.ThrowsAsync <InvalidOperationException>(() => client.AuthenticateAsClientAsync()), Assert.ThrowsAsync <InvalidOperationException>(() => server.AuthenticateAsServerAsync())); } }