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
Related
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.
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
..
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".
This is more about how to get HttpWebRequest to work or even if HttpWebRequest is the right implementation. I've let my C# and .Net skill lapse the past few year, so I hope I can be forgiven for that.
I trying to hit a secure web service that requires client authentication. I have four certs to hit this with.
• Root Certificate
• Intermediate Root Certificate
• Device Certificate
• Private Key
The server is Java and these certs are in .jks form trustore and keystore. I pulled them into .pem files.
So, I failed on the C# client side, so I thought I'd write a little Python snippet to make sure at least the server side is working as expected. Twenty minutes later, I'm making secure posts. Here's that code:
# Keys
path = "C:\\path\\"
key = path + "device.pem"
privkey = path + "device_privkey.pem"
CACerts = path + "truststore.concat" # root & intermediate cert
def post():
url = "/url"
headers = {'Content-Type': 'application/xml'}
## This section is HTTPSConnection
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
context.verify_mode = ssl.CERT_OPTIONAL
context.load_cert_chain(key, privkey, password='password')
context.verify_mode = ssl.CERT_NONE
context.load_verify_locations(CACerts)
conn = http.client.HTTPSConnection(host, port=8080, context=context)
conn.request("POST", url, registrationBody, headers)
response = conn.getresponse()
regresp = response.read()
The concat certificate is the concatenation of the root and intermediate certificates.
Are you with me?
Now to my C#/.Net headache.
This my attempt. I clearly don't know what I'm doing here.
public async Task POSTSecure(string pathname, string body)
{
string path = "C:\\path";
string key = path + "device.pem";
string privkey = path + "device_privkey.pem";
string CACerts1 = path + "vtn_root.pem";
string CACerts2 = path + "vtn_int.pem";
try
{
// Create certs from files
X509Certificate2 keyCert = new X509Certificate2(key);
X509Certificate2 rootCert = new X509Certificate2(CACerts1);
X509Certificate2 intCert = new X509Certificate2(CACerts2);
HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create("https://" + host + ":" + port + pathname);
ServicePoint currentServicePoint = request.ServicePoint;
// build the client chain?
request.ClientCertificates.Add(keyCert);
request.ClientCertificates.Add(rootCert);
request.ClientCertificates.Add(intCert);
Console.WriteLine("URI: {0}", currentServicePoint.Address);
// This validates the server regardless of whether it should
request.ServerCertificateValidationCallback = ValidateServerCertificate;
request.Method = "POST";
request.ContentType = "application/xml";
request.ContentLength = body.Length;
using (var sendStream = request.GetRequestStream())
{
sendStream.Write(Encoding.UTF8.GetBytes(body), 0, body.Length);
}
var response = (HttpWebResponse)request.GetResponse();
}
catch (Exception e)
{
Console.WriteLine("Post error.");
}
}
Thanks for any help or a pointer to a decent tutorial.
[Edit] More info. On the server side, the debugging points to an empty client certificate chain. This is right after it reports serverhello done.
Okay, I think I was pretty close in the original, but I solved it this way:
request.ClientCertificates = new X509Certificate2Collection(
new X509Certificate2(
truststore,
password));
The "trustore" file is a .p12 containing the certificates listed above. The .p12 truststore can be created from the .jks truststore through keytool and openssl. Lots of info out there on how to do that.
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?