I am working on connection with hashicorp. We need to call there decrypt api in .net. for calling decrypt API, we need to pass token in it. But token call is different which is using client certificate and key for authentication. We are calling token generation url from .net application but getting error ""{"errors":["client certificate must be supplied"]}\n"".
var allKeyytes = File.ReadAllBytes(@"file.key");
var privateKey = new X509Certificate2(allKeyytes, "XXXXXX").PrivateKey as DSACryptoServiceProvider;
var certificate2 = new X509Certificate2(@"file.crt");
certificate2.CopyWithPrivateKey(privateKey);
HttpClientHandler handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate2);
using (HttpClient client = new HttpClient(handler))
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, vaultUrl);
HttpResponseMessage response = client.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
}
}
After adding above line of code getting error "System.Security.Cryptography.CryptographicException: 'Cannot find the requested object."
Please let me know what I am doing wrong!
Thank you in advance.
CodePudding user response:
Code is not right. On line 2, you are reading privatekey in first parameter, it should have been encrypted certificate containing private key. Also, this method is obsolete.
I did the below code and it runs successfully. If you are using DSA, you can replace RSA with DSA
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
int bytesread;
var allKeyytes = File.ReadAllBytes(@"tls.key");
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
provider.ImportFromPem(File.ReadAllText("tls.key"));
var certificate2 = new X509Certificate2(@"tls.cer");
certificate2.CopyWithPrivateKey(provider);
HttpClientHandler handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate2);
using (HttpClient client = new HttpClient(handler))
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://www.google.com");
HttpResponseMessage response = client.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
}
}
CodePudding user response:
You are not actually using the result of CopyWithPrivateKey
which returns a new certificate, it does not modify the original.
You are also missing using
on various objects, and you also need to use await
rather than .Result
otherwise you may deadlock
var allKeyytes = File.ReadAllBytes(@"file.key");
using (var crt = new X509Certificate2(@"file.crt"))
using (var privateKey = new X509Certificate2(allKeyytes, "XXXXXX"))
using (var certificate2 = crt.CopyWithPrivateKey(privateKey.GetDSAPrivateKey()))
{
HttpClientHandler handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate2);
using (var client = new HttpClient(handler))
using (var request = new HttpRequestMessage(HttpMethod.Post, vaultUrl))
{
using (var response = client.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
}
}
}
}
If the private key is actually RSA then you will need to cast to privateKey.GetRSAPrivateKey()
instead.
Ideally the HttpClient
would be cached in a static . For that you would only dispose crt
and privateKey
not certificate2
.