WebRequest does not send client certificate

I am writing a client for the REST API and for the authentication of the API I must use the certificate that was provided to me.

this code is as follows:

public string GetCustomer(int custId) { X509Certificate2 Cert = new X509Certificate2(); Cert.Import(@"C:\users\foo\desktop\api\pubAndPrivateCert.pkcs12", "", X509KeyStorageFlags.PersistKeySet); ServicePointManager.ServerCertificateValidationCallback += ValidateServerCertificate; HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://api.foo.net/api/customer/v1/" + custId); req.ClientCertificates.Add(Cert); req.UserAgent = "LOL API Client"; req.Accept = "application/json"; req.Method = WebRequestMethods.Http.Get; string result = null; using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse()) { StreamReader reader = new StreamReader(resp.GetResponseStream()); result = reader.ReadToEnd(); } return result; } 

Every time I make a request, I get 400 error message and when using Fiddler to look at the answer, I get the following

 <html> <head><title>400 No required SSL certificate was sent</title></head> <body bgcolor="white"> <center><h1>400 Bad Request</h1></center> <center>No required SSL certificate was sent</center> <hr><center>nginx/0.6.32</center> </body> </html> 

I see no reason for him not to send a certificate, but troubleshooting SSL is not very easy. I added some debugging instructions to add some details and stop using the violinist, and this is what I got

These errors apply to ValidateServerCertificate ()

 Certificate error: RemoteCertificateChainErrors NotSignatureValid The signature of the certificate cannot be verified. 1048576 Unknown error. 

These are errors caused by the release of WebExecption.

 Cought Exception ProtocolError The remote server returned an error: (400) Bad Request. BadRequest <html> <head><title>400 No required SSL certificate was sent</title></head> <body bgcolor="white"> <center><h1>400 Bad Request</h1></center> <center>No required SSL certificate was sent</center> <hr><center>nginx/0.6.32</center> </body> </html> 

This is ValidateServerCertificate () code that always returns true to ignore any certificate errors.

  public static bool ValidateServerCertificate(object sender, X509Certificate certificate,X509Chain chain,SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) return true; if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { Console.WriteLine("Certificate error: {0}", sslPolicyErrors); foreach (var chainstat in chain.ChainStatus) { Console.WriteLine("{0}", chainstat.Status); Console.WriteLine("{0}", chainstat.StatusInformation); } return true; } Console.WriteLine("Certificate error: {0}", sslPolicyErrors); // allow this client to communicate with unauthenticated servers. return true; } 
+8
c # rest ssl
source share
1 answer

Your code loads the client certificate from the local file. You should have more success if you import the client certificate into the certificate store (which is highly recommended to protect the private key). Then your code should look something like this:

 public string GetCustomer(int custId) { // EDIT THIS TO MATCH YOUR CLIENT CERTIFICATE: the subject key identifier in hexadecimal. string subjectKeyIdentifier = "39b66c2a49b2059a15adf96e6b2a3cda9f4b0e3b"; X509Store store = new X509Store("My", StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly); X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindBySubjectKeyIdentifier, subjectKeyIdentifier, true); X509Certificate2 certificate = certificates[0]; HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://api.foo.net/api/customer/v1/" + custId); req.ClientCertificates.Add(certificate); req.UserAgent = "LOL API Client"; req.Accept = "application/json"; req.Method = WebRequestMethods.Http.Get; string result = null; using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse()) { StreamReader reader = new StreamReader(resp.GetResponseStream()); result = reader.ReadToEnd(); } return result; } 

See Import a certificate for instructions. The code assumes that you have imported the certificate with public and private keys into the personal certificate folder ("My") of the current user.

You do not need to specify ServicePointManager.ServerCertificateValidationCallback . This allows your application to change the way the server certificate is verified. This does not affect how the server validates the client certificate.

+10
source share

All Articles