Question

Well im trying to setup a net.tcp connection with SSL encryption I have the following classes

Wcf Interface:

[ServiceContract()]
public interface IServer
{
    [OperationContract]
    void Send(string message);
}

Server:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
class Server : IServer
{
    readonly ServiceHost host;

    public Server()
    {
        host = new ServiceHost(this);
        host.AddServiceEndpoint(typeof(IServer), Program.GetBinding(), string.Format("net.tcp://localhost:{0}/", 1010));
        host.Credentials.ServiceCertificate.Certificate = Program.LoadCert();
        host.Open();
    }

    public void Send(string message)
    {
        Console.WriteLine(message);
    }
}

Program (Client/Server):

class Program
{
    static ChannelFactory<IServer> channelFactory;
    static IServer server;
    static RemoteCertificateValidationCallback callback = null;


    public const int MaxMessageSize = 1024 * 1024 * 2;
    public static Binding GetBinding()
    {
        NetTcpBinding binding = new NetTcpBinding();
        binding.Security.Mode = SecurityMode.Transport;
        binding.Security.Message.ClientCredentialType = MessageCredentialType.None;
        binding.ReaderQuotas.MaxArrayLength = MaxMessageSize;
        binding.ReaderQuotas.MaxBytesPerRead = MaxMessageSize;
        binding.MaxBufferSize = MaxMessageSize;
        binding.MaxReceivedMessageSize = MaxMessageSize;
        binding.MaxBufferPoolSize = binding.MaxBufferSize * 10;
        binding.TransactionFlow = false;
        binding.ReliableSession.Enabled = false;
        binding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
        return binding;
    }


    public static X509Certificate2 LoadCert()
    {
        X509Certificate2 cert = new X509Certificate2();
        cert.Import(@"Test2.pfx", "Test", X509KeyStorageFlags.DefaultKeySet);
        return cert;
    }

    static void Main(string[] args)
    {
        try
        {
            callback = new RemoteCertificateValidationCallback(ValidateCertificate);
            ServicePointManager.ServerCertificateValidationCallback += callback;
            Console.WriteLine("[C]lient or [S]erver?");
            ConsoleKeyInfo key = Console.ReadKey(true);
            if (key.Key == ConsoleKey.S)
            {
                StartServer();
            }
            else if (key.Key == ConsoleKey.C)
            {
                StartClient();
            }
        }
        finally
        {
            if (callback != null)
                ServicePointManager.ServerCertificateValidationCallback -= callback;
        }
    }

    private static void StartClient()
    {
        Console.WriteLine("Starting client mode!");
        Console.Write("Host:");
        string host = Console.ReadLine();
        channelFactory = new ChannelFactory<IServer>(GetBinding());

        server = channelFactory.CreateChannel(new EndpointAddress(string.Format("net.tcp://{0}:{1}/", host, 1010)));
        while (true)
        {
            Console.Write("Message:");
            server.Send(Console.ReadLine());
        }
    }

    private static void StartServer()
    {
        Console.WriteLine("Starting server mode!");
        Server server = new Server();
        Console.ReadKey();
        GC.KeepAlive(server);
    }

    public static bool ValidateCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        Console.WriteLine("ValidateCertificate");
        return true;
    }
}

This works fine when both the server and client are run on the same computer (but ValidateCertificate is never called like it should be).

But if i run them on separate computers i get the following exception on the client:

Description: The process was terminated due to an unhandled exception. Exception Info: System.ServiceModel.Security.SecurityNegotiationException Stack:

Server stack trace: at System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeInitiator.OnInitiateUpgrade(Stream stream, SecurityMessageProperty& remoteSecurity) at System.ServiceModel.Channels.StreamSecurityUpgradeInitiatorBase.InitiateUpgrade(Stream stream) at System.ServiceModel.Channels.ConnectionUpgradeHelper.InitiateUpgrade(StreamUpgradeInitiator upgradeInitiator, IConnection& connection, ClientFramingDecoder decoder, IDefaultCommunicationTimeouts defaultTimeouts, TimeoutHelper& timeoutHelper) at System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.SendPreamble(IConnection connection, ArraySegment`1 preamble, TimeoutHelper& timeoutHelper)
at System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.DuplexConnectionPoolHelper.AcceptPooledConnection(IConnection connection, TimeoutHelper& timeoutHelper) at System.ServiceModel.Channels.ConnectionPoolHelper.EstablishConnection(TimeSpan timeout) at System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.OnOpen(TimeSpan timeout) at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel channel, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(System.Runtime.Remoting.Messaging.IMessage, System.Runtime.Remoting.Messaging.IMessage) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32) at WcfChatTest.Client.Program+IServer.Send(System.String) at WcfChatTest.Client.Program.StartClient() at WcfChatTest.Client.Program.Main(System.String[])

What did i configure wrong, and why does it call "WindowsStreamSecurityUpgradeProvider" when i provided it a certificate?

Or if some one else got a great example how to get transport encryption on net.tcp without the client and server being in the same domain?

Was it helpful?

Solution

I solved the problem on the line

server = channelFactory.CreateChannel(new EndpointAddress(string.Format("net.tcp://{0}:{1}/", host, 1010)));

i had to add a addittional parameter that i created with the following code

EndpointIdentity.CreateX509CertificateIdentity(certificate)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top