We have third party API provider that provided an SOAP API. They have provided 3 certificates,
Client Cert
Intermediate Cert
Root Cert
All certs are installed locally. They have provided a pfx cert with password. We have uploaded this pfx in SOAP UI tool and run a request it worked. Then we tried the same with .NET request,
var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
var client = new ServiceReference1.myClient(binding, new EndpointAddress(serviceUrl));
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var certificate = new X509Certificate2(certificateBinary, certificatePassword);
client.ClientCredentials.ClientCertificate.Certificate = certificate;
It failed with handshake failure error.
Then we monitored both SOAP UI traffic and .NET code traffic using WireShark.
Clearly the .NET is not sending Root CA. The problem is that request is rejected by the third party API if Root CA is not present in the request. How can force send ROOT CA.
Related
I'm trying to set up a TCP stream (non-HTTP) on a server that will be exposed to the public internet, but only "chosen" clients should be able to connect to. As I understand it, this is generally handled by certificate pinning, but I'm not familiar with all the details of how this is done.
Generate a SSL cert for the server. That's easy enough.
Set up the server. Have it call something like the following when a client connects:
private SslStream GetSslStream(TcpClient client, string certificateFile)
{
var c = X509Certificate.CreateFromCertFile(certificateFile);
var cert = new X509Certificate2(c);
if (!cert.Verify()) {
throw new Exception("Certificate failed verification");
}
var stream = new SslStream(client.GetStream(), false, VerifyClientCert);
stream.AuthenticateAsServer(cert, true, true);
return stream;
}
Where does the client certificate come from? Is it a copy of the server's SSL certificate? Is it a separate cert that has to be derived from the server's cert in some way? Is it a completely different cert?
What goes in the VerifyClientCert method to make sure it's the right certificate? Just Verify() and check the Thumbprint against an expected value, or is there more that needs to happen?
Should every client get a copy of the same client cert?
Certificate pinning is a different concept. When server uses SSL certificate, it's usually issued by some Certificate Authority. Certificate of that authority can in turn be issued by yet another Certificate Authority, forming a chain. When client validates server certificate, it checks if that Certificate Authority is "trusted" by this particular client. "Trusted" in turn means that some certificate in the chain described above is trusted by this client. For example, Windows and Linux OS both come with certain set of Certificate Auhorities trusted by default. If server certificate has some of those authorities in their chain - then it's also trusted.
Certificate pinning means you, as a client, impose more restrictions on server certificate than what is described above. For example, you might say that for this domain \ endpoint, I only trust this specific certificate (with this specific digest), and I do not care about trust chain at all. Or that for this endpoint I only trust this specific Certificate Authority. This is certificate pinning. You can use it for your server, but it has its drawbacks which I won't describe here.
Now back to your problem. What you describe is called Client Certificate Authentication. In SSL handshake, not only server can present certificate for client to verify. Server might also request client to send his own certificate, to authenticate that client. This certificate is of course completely different from server's certificate.
Every client must have different certificate. Usually one of the two options are used:
You (server owner) create your own Certificate Authority (for example with couple of simple openssl commands), and then you issue separate certificate for each client from this authority. Then you send those certificates (one for each client), including private keys, to their respective clients. After that you can throw away (delete) those certificates, because you will no longer need them. When validating client certificate - just check if it was issued by your Certificate Authority.
OR separate certificate is issued for each client and you store thumbprints (digests\hashes) of those certificates, one for each client. Then during validation you ensure that Thumbprint has the expected value for given client. The benefit is that you can ask client to generate such certificate and send you (the server owner) the thumbprint. Then you never had private key of that certificate in your possession (unlike method with your own Certificate Authority where you generated certificate yourself and at one point posessed its private key).
I am in the process of building a WCF client for a SOAP HTTPS webservice in .Net Core 2.1.
The service provider has supplied a .key and a .cert file which I have converted to a .p12 file using openssl. By adding this to a keystore I am able, through SoapUI, to successfully sent a request to the webservice (no other authentication than the certificate is required).
To do the same operation in .Net Core I have added a Connected Service to my project through the WCF wizard in Visual Studio. This service is based on the supplied service contract (WSDL file). I have then installed the .p12 certificate locally on my PC and I am using the following code to make the request. "MyService" is the connected service.
var binding = new BasicHttpsBinding();
binding.Security.Mode = BasicHttpsSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
var endpoint = new EndpointAddress("https://x.x.x.x:8300/MyService.asmx");
var channelFactory = new ChannelFactory<MyService>(binding, endpoint);
channelFactory.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
channelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication()
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck,
TrustedStoreLocation = StoreLocation.LocalMachine
};
channelFactory.Credentials.ClientCertificate.SetCertificate(
StoreLocation.CurrentUser,
StoreName.My,
X509FindType.FindByIssuerName,
"xxxxxxxxxxxxxxxxxxxxxxxxxx");
var service = channelFactory.CreateChannel();
ExecuteResponse response = service.Execute(new ExecuteRequest());
When running this code I am getting the following error:
System.ServiceModel.Security.MessageSecurityException: 'The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate'.'
The strange thing is that I am allowed to make the request if I use the HttpClientHandler which tells me that there must be a mismatch between the underlying structure of the two implementations.
Anyone who knows how I can fix this error?
The certificate might just be used to establish the trust relationship between the client-side and the server-side.
For making a successful call to the service, we should keep the binding type between the client-side and the server-side consistent. Therefore, I would like to know the automatically generated client-side configuration by Adding service reference, please post the System.servicemodel section located in the appconfig of the client project.
If the server authenticates the client-side with a certificate, the error typically indicates the trust relationship has not established yet between the client-side and the server-side.
On the client-side, we should install the server certificate in the LocalCA. On the server-side, we should install the client certificate in the LocalCA certificate store.
Feel free to let me know if the problem still exists.
I'm trying to connect to Java web service with C# client. I don't have physical access to that service, but I was told by it's developers that I need to provide client certificate AND intermediate CA in my requests.
I tried using Service Reference and WebClient but I only managed to send just client certificate.
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
request.ClientCertificates.Add(m_TransportCertificate);
//m_TransportCertificate holds client certificate with key and rest of the cert chain (intermediate and root)
return request;
}
How to send two client certificates in C#? As far as i know it isn't normal behaviour - client should only send one certificate.
I can't make my app to do it - it always sends one certificate.
Wireshark screenshot
However it works in SoapUI (the second one is intermediate CA)
Wireshark screenshot
I found a solution. Intermediate CA was automatically installed in Intermediate Certification Authorities but it needs to be in Trusted Root Certification Authorities.
Just moved it there and it worked.
Scenario: User talks with WebApi called 'Gateway' by angularjs client. 'Gateway' is like a facade or a proxy, so all requests from User to 'Gateway' will be forwarded to another WebApis.
Security details: 'Gateway' WebApi and all others WebApis are placed in IIS with HTTPS binding and SSL client certificate option is 'Accept'. So, user will provide valid client certificate to IIS and after verification, request will be handled by WebApi.
The problem: when 'Gateway' WebApi receives a request, client certificate is presented in Request object. Then I just forward this request using HttpClient to another WebApi. But when another WebApi endpoint receives a request, there is not client certificate attached any more.
Below is a code snipped of request forwarding:
var request = Request; // income request from angularjs
var handler = new WebRequestHandler();
handler.ClientCertificates.Add(request.GetClientCertificate()); // setting up client certificate from user's request
using (var httpClient = new HttpClient(handler))
{
request.RequestUri = *chaning request address here*;
var response = await httpClient.SendAsync(request);
return ResponseMessage(response);
}
Note: If I try to go directly to the another WebApi, client certificate is presented as expected. If I try to go via 'Gateway', client certificate is presented as well in 'Gateway' request, but after it's successfully attached and request is sent, another WebApi does not receive any certificate attached.
Any ideas?
Thank you.
On your gateway server, you need to import an authentication key onto the "machine" certificate store (MMC.exe, add snap-in "Certificates", Computer account", Certficates-Personal-Certificates, import).
Grant permissions (for the auth cert) to the account which your IIS pool is using. (right-click the cert, All-Tasks, Manage private keys. Add, Advanced, Locations=[machine-name], find now, (probably) Network Service, Read).
In your web.config (on your gateway server), check your system.serviceModel / behaviors / endpointBehaviors / behavior / clientCredentials / clientCertificate. Make sure the attribute: storeLoction="LocalMachine", to use the cert from the machine key store.
I am trying to access service bus via a squid3 webproxy with Basic authentication enabled in the proxy using C#
i am using below code to set the web proxy
webproxy webproxy = new webproxy("http://weproxyuri:port", false);
webproxy.credentials = new networkcredential("username", "password","domain");
WebRequest.DefaultWebProxy = webProxy
i am using below code to access service bus
MessagingFactory messagingFactory = MessagingFactory.CreateFromConnectionString(connectionstring);
QueueClient queueSendClient = messagingFactory.CreateQueueClient(queuename);
var bm1 = queueSendClient.Peek();
access of service bus is failing with error - The X.509 certificate CN=servicebus.windows.net is not in the trusted people store
in the proxy log i am seeing 1454679317.842 0 10.168.84.150 TCP_DENIED/407 4046 GET http://www.microsoft.com/pki/mscorp/msitwww2.crt - HIER_NONE/- text/html
in the network traces i am seeing host trying to connect to http://www.microsoft.com/pki/mscorp/msitwww2.crt first it is trying to connect with out authentication then proxy is saying HTTP/1.1 407 Proxy Authentication required as a response to the request for this ideally host should resend the request with Proxy-Authorization Header which contains username and password but i am seeing a weird behavior where host is not send the Proxy-Authorization Header in the second time
any registry key needs to be set ?
i am using windows core 2012 R2 as host
this issue is fixed in 3.0.50496.1 or higher version of Microsoft.ServiceBus.dll