ClientCertificates in WebRequestHandler - asp.net-web-api

I use HttpClient to talk to my WebAPI service. For SSL authentication, I set up the client certificates on the HttpClient using WebRequestHandler -
private static WebRequestHandler CreateWebRequestHandler(List<X509Certificate2> clientCertificates)
{
WebRequestHandler handler = new WebRequestHandler();
if (clientCertificates != null && clientCertificates.Any())
{
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
clientCertificates.ForEach(cert => handler.ClientCertificates.Add(cert));
}
return handler;
}
On the Service, I have a custom DelegatingHandler to validate the client certificates using thumbprint -
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
X509Certificate2 certificate = request.GetClientCertificate();
// Code to validate certificate's Thumbprint with white listed thumbprints
}
From the HttpRequest, I can get only one client certificate.
My question: Why does WebRequestHandler allow a collection of ClientCertificates to be set? Does it present all the client certificates to the server? If yes, then how do I get the list of client certificates in the DelegatingHandler?

Actually, only one certificate is send to server by a client during TLS\SSL handshake which you are obtain on the Server. The process of choosing this certificate is well described here.
Briefly explanation is - the client will choose the best suitable certificate from X509CertificateCollection looking for a match between the list of certificate issuers provided by the server and the client certificate issuer name. The first certificate that matches is sent to the server. If no certificate matches or the certificate collection is empty, then an anonymous credential is sent to the server. The deeper mechanism of TLS\SSL work described in a good manner here

Related

ASP.NET Core 6 getting Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[1] Failed to authenticate HTTPS connection

I am building a 5 method Web API application that needs to be secured with TLS in production. I have a gRPC server that works and when I use the same configuration in the Web API app, I am getting the following error:
dbug: Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[1]
Failed to authenticate HTTPS connection.
System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream.
at System.Net.Security.SslStream.ReceiveBlobAsync[TIOAdapter](TIOAdapter adapter)
at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware.OnConnectionAsync(ConnectionContext context)
dbug: Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[1]
Failed to authenticate HTTPS connection.
System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream.
at System.Net.Security.SslStream.ReceiveBlobAsync[TIOAdapter](TIOAdapter adapter)
at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware.OnConnectionAsync(ConnectionContext context)
I ripped out all of the gRPC code in the Web API Program.cs file in lieu of trying to configure Kestrel in the launchSettings.json file.
The snippet below shows my current effort:
"Kestrel": {
"Endpoints": {
"HttpsInlineCertFile": {
"Url": "https://localhost:30050",
"Certificate": {
"Path": "D:\\Development\\Certs\\MDevelopment.pfx",
"Password": "xxxxxxxx"
}
}
},
"Certificates": {
"Default": {
"Path": "D:\\Development\\Certs\\MDevelopment.pfx",
"Password": "xxxxxxxx"
}
}
}
The development and production certs work in the gRPC case, and also for securing a mail server I have so I am confident the certs are good. I have tried so many things, I cannot tell you anything else of value.
#Buffoonism, #Alvaro: I tried many things in trying to overcome this error. I did find that the cert that was being used in production was not correct (the node name changed messing everything up...)
What I did was create a new cert to ensure I was using the correct keys to gen the certificate. Then, I changed the way the cert was being applied to the listener as such:
// Get the host name and port number to bind the service to.
kestrelServerOptions.ConfigureHttpsDefaults (httpsConnectionAdapterOptions => {
httpsConnectionAdapterOptions.ServerCertificate = new X509Certificate2 (certPath, certPassword);
httpsConnectionAdapterOptions.SslProtocols = SslProtocols.Tls12;
});
Once I made that change, everything started to work. #Microsoft, you really need to step up your documentation game! All of you examples surround using a dev cert which is easy. Using a production-grade cert requires more handling (such as trusting the cert) which could use waaaaaaay better examples!
I hope that helps!

How to get server certificate when using IWinHttpRequest

How can i get server certificate information when using IWinHttpRequest (or its IServerXMLHTTPRequest wrapper)?
WinHttp example
IWinHttpRequest http = new WinHttpRequest();
http.Open("GET", "https://example.com", false);
http.send(null);
MSXML example
//IServerXmlHttpRequest internally is a wrapper around WinHttp
IServerXmlHttpRequest http = new ServerXmlHttp60();
http.open("GET", "https://example.com/", false);
http.send(null);
Now that i've sent the request, how can i get information about the server certificate?
Specifically:
i need it's thumbprint (e.g., 43c930419a3adf8ae1e9a635e078ae62e2c7ab4b)
i would like it's subject (e.g., CN = *.silkroad.onion)
i would like it's issuerer (e.g., CN = DigiCert SHA2 Secure Server CA)
It goes without saying that this is not using the flat C WinHttp API, but is using the COM object.
Bonus Reading
InternetQueryOption function
INTERNET_OPTION_SECURITY_CERTIFICATE / INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT
INTERNET_CERTIFICATE_INFO structure

SocketIO4Net - Error initializing handshake with https://localhost/

I'm trying to use SocketIO4Net to connect with my node.js server via socket.io.
Can't seem to get it to work, when it comes to HTTPS.
Getting this: Error initializing handshake with https://localhost/
Couldn't find a solution in other similar questions.
If you have other solutions to connect to socket.io sockets from C# feel free to share the information.
.NET seems to block my self signed certificate.
Implementing the RemoteCertificateValidationCallback seems to solve the problem.
ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(pass);
private static bool pass(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error) { return true; }

MPNS sending pushing forbidden response 403

I want to use MPNS in my windows phone app and we are going to authenticate the webservice which is sending the push to clients.
I have the done the all steps that are needed for MPNS authentication.
Uploaded the certificates on my WindowsPhone dev dashboard.
Created the channel name with the common name of my certificates
Getting the return URI with https:// thats mean my push channel is authenticated
Adding certificates to my WebRequest header
But when I am going to send push message and send webrequest but I am getting "The remote server returned an error: (403) Forbidden." response. I have read that I am doing something wrong with my request and not adding certificate properly.
Here is my code for Request Header
X509Certificate2 Cert = new X509Certificate2(Server.MapPath("Certs/abc.crt"), "password");
request.ClientCertificates.Add(Cert);
We have verisign ssl and i am testing this from my visual studio IIS. Its not hosted on any server right now and even not configured in IIS and no SSL configured for IIS.
Is that the issue or something else.
There's no unique answer for your problem.
However, when you add a client certificate to your request you only add the public key to it. The server will then respond with a challenge signed with your public key (see client certificate authentication) and you need to decipher and respond to it with your private key. If this authentication process fails, you will get a 403 forbidden.
Therefore, you must ensure that the .pfx/.p12 (containing your private key, public certificate, intermediate CA and Root CA certificates) is imported to your local machine certificate store and that your IIS server has access to it.
Because there are so many variables related to Windows, you can use Curl instead for testing purposes. Note that you must convert your .pfx/.p12 to .pem first (use openssl).
curl --cert P:\cert.pem:PASSWORD -v -H "Content-Type:text/xml" -H "X-WindowsPhone-Target:To
ast" -H "X-NotificationClass:2" -X POST -d "<?xml version='1.0' encoding='utf-8'
?><wp:Notification xmlns:wp='WPNotification'><wp:Toast><wp:Text1>My title</wp:Te
xt1><wp:Text2>My subtitle</wp:Text2></wp:Toast></wp:Notification>" https://am3.n
otify.live.net/unthrottledthirdparty/01.00/push_uri_here
Once you get that working, you may face the same problem as me: some notifications are being sent correctly and some others are rejected with a 403 forbidden for no apparent reason. See this thread:
http://social.msdn.microsoft.com/Forums/sharepoint/en-US/383617ab-eafe-45fb-92cc-5e4b25a50e7f/authenticated-push-notifications-failing-randomly-403-forbidden?forum=wpnotifications
and the same here:
https://stackoverflow.com/questions/23805883/windows-phone-authenticated-push-notifications-failing-randomly-403-forbidden

Mutual Authentication with HttpClient

i am going to present my problem:
My web application submit a form by https to a server that it needs client certificate for set the communication. It works fine, when i submit the form, the https server asks me for a certificate, i select my certificate and the server response me. But now, i want to post to https server from a servlet with HttpClient because i want to manage the response from https server, and here i have problems...
My code to send a post with HttpClient is:
DefaultHttpClient client = new DefaultHttpClient();
// in the truststore i have the https server certificates for establish connection
// from my client to https server
FileInputStream instream = new FileInputStream(new File(TRUESTORE_PATH));
KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
truststore.load(instream, KEY_TRUESTORE_PASS.toCharArray());
// in the keystore i have the client certificate but without private key because,
// in theory, i shouldn't know it
FileInputStream otherinstream = new FileInputStream(new File(KEYSTORE_PATH));
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(otherinstream,KEY_STORE_PASS.toCharArray());
SSLSocketFactory socketFactory = new SocketFactory(keystore,KEY_STORE_PASS,truststore);
Scheme sch = new Scheme("https", 443, socketFactory);
client.getConnectionManager().getSchemeRegistry().register(sch);
HttpGet httpget = new HttpGet("https://remote_server_with_client_authentication");
HttpResponse response = client.execute(httpget);
When i execute this code, in an unit test for example, i have response from https server, but it tells me that i am not authorized. I suspect that i can't authenticate with the https server because the keystore has the client certificate but whitout private key, then i am not authorized.
Then, Is there some way to establish communication with the https server with a client certificate selected by the user?
Thanks!

Resources