Client send cert but GetClientCertificate always receives as null - c#

Web api always receive GetClientCertificate as null. Its using with IISExpress and no need to host certificate on IISExpress or IIS. Certificate exists on certificate Store on server. Just want to validate manually like, client send cert file and web api code validate cert manually by looking into cert store on server (no iis validation).
went through couple of post on same issue but it needs to host cert on IIS/IISExpress.
Tried:
client send the certificate as below, And expected to receive on server side.
client send certificate:
var handler = new HttpClientHandler();
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var certifcates = store.Certificates.Find(X509FindType.FindByThumbprint, "07a49ef049795a07be786512359be34d234e4548", false);
var cert = certifcates[0];
handler.ClientCertificates.Add(cert);
var client = new HttpClient(handler);
var s ="xml content to post";
var data = new StringContent(s, Encoding.UTF8, "application/xml");
var result = client.PostAsync("http://localhost:51567/api/PostContent", data).GetAwaiter().GetResult();
web api expecting to receive client cert on GetClientCertificate as below but, its always getting null.
web api:
var cert = httpActionContext.Request.GetClientCertificate();
if (cert == null)
...
else
..

Related

Where to add host name while adding pfx certificate in RestSharp using C#?

I'm trying to communicate with a server where I need to pass pfx cert, host and passphrase.
To test the server, I use Postman. So I fill the certificate setting in postman, and my request works fine as shown here.
enter image description here
I see there is a way to add pfx cert with password but how to add all 3 (host along with pfx cert and password)?
var client = new RestClient(url);
string certificatePath = #"certificates/certificate.pfx";
string pass = "password";
X509Certificate2 certificate = new X509Certificate2(certificatePath, pass);
client.ClientCertificates = new X509CertificateCollection() { certificate };
client.Proxy = new WebProxy();
var restrequest = new RestRequest(Method.POST);
restrequest.AddHeader("Cache-Control", "no-cache");
restrequest.AddHeader("Accept", "application/json");
restrequest.AddHeader("Content-Type", "application/json");
IRestResponse response = client.Execute(restrequest);
In PostMan, you configure the host so it doesn't use that certificate for communication with any host asking for a client certificate.
In your code, you can ensure that you use the RestClient that you configure with that certificate only for communication with a given host.

Could not create SSL/TLS secure channel when using client certificate from local machine

I am calling an API that requires a client certificate. With the client certificate installed into the Personal store of Current User, the API call is successful. But when the client certificate is installed into the Personal store of Local Machine, the call fails with:
The request was aborted: Could not create SSL/TLS secure channel.
Here is the setup code:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12
| SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; };
const StoreName storeName = StoreName.My;
const X509FindType findType = X509FindType.FindByThumbprint;
const string findValue = "9ce5b57fe576b9a0933b426347e74e5583da59dd";
var certCurrentUser = GetCertificate(storeName, StoreLocation.CurrentUser, findType, findValue);
var certLocalMachine = GetCertificate(storeName, StoreLocation.LocalMachine, findType, findValue);
Both calls to GetCertificate() succeed and the certificates appear to be identical. (They were installed from the same .pfx)
When this call is made with certCurrentUser, it succeeds:
WebRequestHandler handler = new WebRequestHandler();
handler.ClientCertificates.Add(certCurrentUser);
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync("https://preprod.xconnectcollection.ce.corp.com/odata");
}
But when the call is made using certLocalMachine, it fails:
WebRequestHandler handler = new WebRequestHandler();
handler.ClientCertificates.Add(certLocalMachine);
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync("https://preprod.xconnectcollection.ce.corp.com/odata");
}
Error:
The request was aborted: Could not create SSL/TLS secure channel.
What could be causing the request to fail when using the client certificate from local machine?
Ensure that the account running the application has full permissions to the certificate's private key.

How to fix "The SSL connection could not be established" error in RestSharp

I'm using RestSharp to call a Web Api with certificate. I've already set up the certificate in Azure and I've already tested the SSL connection with the server by ping commands.
Can anybody help me with the code?
The host of the web api is a windows server.
The code is following:
var client = new RestClient("<myApiEndpoint>");
var request = new RestRequest(Method.GET);
X509Certificate2 cert = null;
X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = certStore.Certificates.Find( X509FindType.FindByThumbprint, "<myKey>", false);
if (certCollection.Count > 0)
{
cert = certCollection[0];
client.ClientCertificates = new X509CertificateCollection() { cert };
}
request.AddHeader("sql", "select * FROM consumers");
IRestResponse response = client.Execute(request);
I expect to connect to the server as a result. But the result is a error. Error message is "The SSL connection could not be established, see inner exception. The remote certificate is invalid according to the validation procedure".

Https call with client certificate from smartcard

How can I programmatically call https endpoint from c# that requires client certificate from smart-card?
Can I use store certificate or do I need to export required certificate to file?
I can access the endpoint without any problems from a browser, but when i do that from c# or node I get 401 unauthorized and I tried both options using store or importing certificate from file but that doesn't work for me.
Here's sample code:
const string url = "https://somesite.com/url";
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
var certs = store.Certificates;
//var cert = new[] { X509Certificate.CreateFromCertFile("./m102044.cer") }; from cert exported from chrome
var request = (HttpWebRequest)WebRequest.Create(url);
request.ClientCertificates = certs;
var response = request.GetResponse(); // 401 unauthorized

Error: C# The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel

I'm trying to make a request via SSL. The certificate is already installed on the machine and it works via browser.
I am using this request:
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] data = encoding.GetBytes(request.Content.OuterXml.ToString());
string password = "XXXX";
X509Certificate2 cert = new X509Certificate2("c:\\zzzz.p12", password);
string key = cert.GetPublicKeyString();
string certData = Encoding.ASCII.GetString(cert.Export(X509ContentType.Cert));
Uri uri = new Uri(request.Url);
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(uri);
myRequest.Credentials = new NetworkCredential(request.User, request.Password.ToString());
myRequest.Method = "PUT";
myRequest.ContentType = request.ContentType;
myRequest.ContentLength = data.Length;
myRequest.ClientCertificates.Add(cert);
Stream newStream = myRequest.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
System.IO.StreamReader st = new StreamReader(((HttpWebResponse)myRequest.GetResponse()).GetResponseStream());
Using this code I get this error:
The underlying connection was closed: Could not establish trust
relationship for the SSL/TLS secure channel. --->
System.Security.Authentication.AuthenticationException: The remote
certificate is invalid according to the validation procedure.
What is the problem?
I solved the problem with this:
ServicePointManager.ServerCertificateValidationCallback = new
RemoteCertificateValidationCallback
(
delegate { return true; }
);
Make sure your certificate is properly trusted. Has the root certificate been added to the correct certificate store (Trusted Root CA's on Local Machine)?
I encountered this error when the (own made) root certificate for a (self signed) certificate had been added to the Trusted Root CA's for Current User). Moving the root cert to the Root CA store on Local Machine solved my issue.
You can add the following statement in the function that calls the web-method:
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
This is client code, right? And you're accessing an HTTPS url, aren't you?
I think the problem is with the server certificate, which the client-side TLS stack cannot validate.
When you connect to that URL via browser, does it work smoothly or do you see a warning on certificate mismatch?

Categories