wcf service with transport security - wcf

I've been struggling with following since few days. Please help me. I'm using XP machine with .Net 3.5. I was following this example http://msdn.microsoft.com/en-us/library/ms729789.aspx. I created a certificate using http://msdn.microsoft.com/en-us/library/ms733813(v=vs.90).aspx and imported the root certificate in the Certificate(Local Computer) > Trusted Root Certification Authorities > Certificates and other one in the Certificate(Local Computer) > Personal > Certificates. I've self hosted service. The hosing code is
ServiceHost svcHost = new ServiceHost(typeof(CalculatorService.CalculatorService), new Uri("https://localhost:8012/CalculatorService"));
ServiceMetadataBehavior smb = svcHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
smb = new ServiceMetadataBehavior();
smb.HttpsGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
svcHost.Description.Behaviors.Add(smb);
svcHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpsBinding(),
"mex");
WSHttpBinding b = new WSHttpBinding();
b.Security.Mode= SecurityMode.Transport;
b.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
svcHost.AddServiceEndpoint(typeof(CalculatorService.ICalculator),b , "");
svcHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "SignedByCA");
svcHost.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
svcHost.Close();
When I try to add reference in the client I get the following error.
There was an error downloading 'https://localhost:8012/CalculatorService/mex'.
The underlying connection was closed: An unexpected error occurred on a send.
Authentication failed because the remote party has closed the transport stream.
Metadata contains a reference that cannot be resolved: 'https://localhost:8012/CalculatorService/mex'.
An error occurred while making the HTTP request to https://localhost:8012/CalculatorService/mex. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.
The underlying connection was closed: An unexpected error occurred on a send.
Authentication failed because the remote party has closed the transport stream.
If the service is defined in the current solution, try building the solution and adding the service reference again.
I think I've tried all possible ways. Now, I've no clue. Please help me. You're my final resource.

Related

Certificate based authentication in WCF

I am trying to understand certificate based authentication using the msdn sample https://msdn.microsoft.com/en-us/library/ms731074(v=vs.90).aspx
This is the server code:
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
// Create the URI for the endpoint.
Uri httpUri = new Uri("https://localhost/Calculator");
// Create the service and add an endpoint.
ServiceHost myServiceHost = new ServiceHost(typeof(ServiceModel.Calculator), httpUri);
myServiceHost.AddServiceEndpoint(typeof(ServiceModel.ICalculator), binding, "");
// Open the service.
myServiceHost.Open();
Console.WriteLine("Listening...");
Console.ReadLine();
// Close the service.
myServiceHost.Close();
This is the client code I wrote:
ChannelFactory<ICalculator> factory = null;
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
EndpointAddress address = new EndpointAddress("https://localhost/Calculator");
factory = new ChannelFactory<ICalculator>(binding, address);
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
factory.Credentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "sroger");
ICalculator channel = factory.CreateChannel();
int y = channel.add(9, 8);
I am getting the following exception:
An unhandled exception of type 'System.ServiceModel.CommunicationException' occurred in mscorlib.dll
Additional information: An error occurred while making the HTTP request to https://localhost/Calculator. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.
I am running both client and server from the same machine. And "sroger" is the certificate in my current user\ personal\certificates which corresponds to my machine name..
Not sure what to do from here..Any thoughts?
In the server code what certificate server uses?
Thanks
Gulumal.
https://msdn.microsoft.com/en-us/library/ms731074(v=vs.90).aspx example you used is incomplete.
Consuming https wcf service requires a valid server certificate to work, in your case both client and server certificates are required.
This is because both client and server need to trust each other in a HTTPS connection.
To get started, read https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/message-security-with-mutual-certificates which is a more complete example that includes specifying certificate to authenticate the service.
For a hosted WCF library via https to work you need to do the following in order:
Configure the port with an X.509 certificate (which has been
answered in
webHttpBinding with certificate)
From your server, create certificate request for common name of your
server fully qualified domain name, or at-least including a DNS subjectAltName of your server fully qualified domain name.
(there are different ways to do this, you may already know this
though)
Issue certificate and install certificate on your server
Grab application id from assembly file of your App that hosts WCF
library (i.e [assembly:
Guid("5870aeed-caca-4734-8b09-5c0615402bcf")]) Grab the certificate
thumbprint by viewing certificate properties.
As administrator, open
CMD and run this command to bind X.509 certificate to the port used
by your app on server
netsh http add sslcert ipport=0.0.0.0:443 certhash= appid={} certstorename=MY
netsh http add iplisten ipaddress=0.0.0.0:443
Add this to your server code:
myServiceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySerialNumber, "<certificate thumbprint>");
In your client code, reference your server address by fully qualified domain name that certificate that is specified as certificate Common Name or subject Alt Name

Getting the certificate info from the request on Restful POST

Hi I am having a Restful service (DotNet 4.0 WCF VS 2012) in HTTPS. My client will attach a certificate to it (certificate is given by me (.cer file)) I need to get the certificate back from the request and read its information to authenticate it, The serial Number, Thumprint are stored in DB when I need to check the same.
I did the SSL and Share the cer file to the client.
I used the following code to read back my certificate
C# code start
if (OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets == null)
throw new Exception ("No claimset service configured wrong");
if (OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets.Count <= 0)
throw new Exception ("No claimset service configured wrong");
var cert = ((X509CertificateClaimSet)OperationContext.Current.ServiceSecurityContext.
AuthorizationContext.ClaimSets[0]).X509Certificate;
C# code end
in the above code i always gets claimSets.Count = 0.
Is any setting I need to do in my server web.config, I did the following setting in my Server Side web.config
'security mode="Transport"'
'transport clientCredentialType="None"'
'security'
Please let me know Is I am missing any settings in the client side or the server side.
In the client side I am using following code the add the cer to the request
C# Code Start
X509Certificate2 cert = new X509Certificate2 ("C:\\xxxxxx.cer");
System.Net.ServicePointManager.ServerCertificateValidationCallback =
delegate(Object obj, X509Certificate X509certificate, X509Chain chain, System.Net.Security.SslPolicyErrors errors)
{
return true;
};
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(xxxxx.Text.Trim());
webRequest.ClientCertificates.Add(cert);
C# Code End
I did not have any special setting in my client web.config file.
Why you use clientCredentialType="None" and not clientCredentialType="Certificate"?
It is also possible your client does not send any certificate. Try to enable Network Tracing in App.config on the client - instructions here. That should create network.log with more debug info. Look for SecureChannel entries in log.

Unable to connect to self-hosted WCF service over HTTPS

I am unable to connect to my self-hosted WCF service running with WebHttp+HTTPS bindings. For various reasons, I configure the service entirely in code rather than using a config file, and I instantiate the service this way:
private ServiceHost CreateService()
{
Type myServiceType = typeof(MyService);
ServiceHost myService = new ServiceHost(myServiceType, new Uri(Constants.ServiceAddress));
ContractDescription contract = ContractDescription.GetContract(myServiceType);
WebHttpBinding httpsBinding = new WebHttpBinding(WebHttpSecurityMode.Transport);
httpsBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
ServiceEndpoint endpoint = myService.AddServiceEndpoint(myServiceType, httpsBinding, "MyService.svc");
endpoint.Behaviors.Add(new WebHttpBehavior());
ServiceMetadataBehavior metadataBehavior = new ServiceMetadataBehavior();
metadataBehavior.HttpGetEnabled = true;
metadataBehavior.HttpsGetEnabled = true;
myService.Description.Behaviors.Add(metadataBehavior);
myService.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindByThumbprint,
Constants.CertThumbprint);
return myService;
}
When I run this code, the service is instantiated and started without error. The service claims to be open when I query it in code, and netstat shows that someone is listening on the appropriate port. I have a firewall exception which allows incoming connections on this port.
However, if I try to open the service endpoint address in the browser or the client, the connection instantly fails. Any clue why? Is there any configuration of the service host or the environment that I have forgotten?
EDIT:
There is no error message to report---no 404, 500, or other error. The browser behaves as if it is unable to open a connection to the target port. The server doesn't seem to even see the incoming connection.
The problem turned out do be that I hadn't registered an SSL cert for my port. The following lines of code are non-functional:
myService.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindByThumbprint,
Constants.CertThumbprint);
Setting the service credentials is only relevant when you intend to use certificate authentication for clients. If you're using HTTPS, then you need to register an SSL cert for the port you're listening on. Issuing the following command resolves the issue:
netsh http add sslcert ipport=0.0.0.0:443 certhash=0b740a29f29f2cc795bf4f8730b83f303f26a6d5 appid={00112233-4455-6677-8899-AABBCCDDEEFF}
There is also an unmanaged interface for doing this, but no managed wrapper exists, so it's simplest to do this using the netsh program.

Issue in message security in WCF using certificate authentication

I have WCF service where I have implemented message security using certificate. But when I try to connect WCF service from my client application, I am getting following error :
The caller was not authenticated by the service.
My configuration settings are as below :
Service Settings :
ServiceHost host = new ServiceHost(typeof(HostService));
NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.Message);
tcpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
host.AddServiceEndpoint(typeof(IHostService), tcpBinding, "net.tcp://192.168.39.28:8000/HostService");
host.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "server_cert");
Client Settings :
NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.Message);
tcpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
DuplexChannelFactory<IHostService> serviceFactory = new DuplexChannelFactory<IHostService>(new InstanceContext(MainWindow), tcpBinding, "net.tcp://192.168.39.28:8000/HostService");
serviceFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "client_cert");
serviceFactory.CreateChannel();
where I have created server_cert and client_cert certificates using makecert command. Can you please guide me what I missed ?
debugging certificate related issue is a big pain, I highly recommend to use wireshark. in your case, it's possible you client side didn't even send out the certificate. if the client cert is signed by another cert(s), make sure put it(them) into the trusted root on both client and server.

BasicHttpBinding using transport sercurity with Self signed Certificate

I have WCF service, using both BasicHttpBinding and NetTcpBinding at different endpoints within one ServiceHost. NetTcp is using a self signed certificate, which is loaded from file, all were well untill I try to actually make use of the BasicHttpBinding, so I do:
On server:
var ServiceHost host = new ServiceHost(blah blah);
host.Credentials.ServiceCertificate.Certificate = GetCertificate(); //load a certificate from file
host.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
var httpBinding = new BasicHttpBinding();
httpBinding.Security.Mode = BasicHttpSecurityMode.Transport;
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
On Client:
ChannelFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
var cer = GetCertificate();
ChannelFactory.Credentials.ClientCertificate.Certificate = cer;
var httpBinding = new BasicHttpBinding();
httpBinding.Security.Mode = BasicHttpSecurityMode.Transport;
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
//accept any cert
System.Net.ServicePointManager.ServerCertificateValidationCallback =
((sender, certificate, chain, sslPolicyErrors) => true);
However when connects, I got this error
Exception - An error occurred while
making the HTTP request to
https://localhost/MyService. This
could be due to the fact that the
server certificate is not configured
properly with HTTP.SYS in the HTTPS
case. This could also be caused by a
mismatch of the security binding
between the client and the server.
certificate is not installed, and it worked fine with net tcp binding, I guess I must missed something small?
One thing I notice is net.tcp is duplex channel while basic http is simplex, I am sure there is a difference to setup? For example, I needed to load certificate at both end for net.tcp, what happens to basic http then?
Thanks in advance
Certificate for HTTPS is not configured in WCF configuration. You must configure certificate for http.sys. To do that use netsh.exe from command line with elevated privileges. If you are hosting your service in IIS/WAS you don't have to use netsh and you can configure HTTPS directly in IIS.