I am trying to make HTTP calls to a server that requires a two-way SSL connection (client authentication). I have a .p12 file that contains more than one certificate and a password. Request is serialized using protocol buffer.
My first thought was to add the keystore to the ClientCertificate properties of the WebRequestHandler used by the HttpClient. I've also added the keystore to my trusted root Certification Authorities on my computer.
I'm always getting a "could not create ssl/tls secure channel" when the PostAsync is executed. There's obviously something that I do wrong but I'm a bit at loss here.
Any pointers would be appreciated.
public void SendRequest()
{
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
var handler = new WebRequestHandler();
// Certificate is located in bin/debug folder
var certificate = new X509Certificate2Collection();
certificate.Import("MY_KEYSTORE.p12", "PASSWORD", X509KeyStorageFlags.DefaultKeySet);
handler.ClientCertificates.AddRange(certificate);
handler.ServerCertificateValidationCallback = ValidateServerCertificate;
var client = new HttpClient(handler)
{
BaseAddress = new Uri("SERVER_URL")
};
client.DefaultRequestHeaders.Add("Accept", "application/x-protobuf");
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/x-protobuf");
client.Timeout = new TimeSpan(0, 5, 0);
// Serialize protocol buffer payload
byte[] protoRequest;
using (var ms = new MemoryStream())
{
Serializer.Serialize(ms, MyPayloadObject());
protoRequest = ms.ToArray();
}
var result = await client.PostAsync("/resource", new ByteArrayContent(protoRequest));
if (!result.IsSuccessStatusCode)
{
var stringContent = result.Content.ReadAsStringAsync().Result;
if (stringContent != null)
{
Console.WriteLine("Request Content: " + stringContent);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
// Do not allow this client to communicate with unauthenticated servers.
return false;
}
EDIT
I don't even break into ValidateServerCertificate. Exception is thrown as soon as the PostAsync is called. Protocol is definitely TLS v1.
Client OS is Windows 8.1. Server is coded in Java (not sure on what OS it's running on. I don't have access to it. It's a black box.)
Stacktrace
at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context) at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
There's no inner exception.
Did you try changing your security protocol
to Ssl3
? Either case you would need to set Expect
property to true
. It will fix your error. Further you can explore this link to get more knowledge over passing client certificate for authentication.
public void SendRequest()
{
try
{
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
var handler = new WebRequestHandler();
.....
}
..
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With