11

Want to send data with client certificate (.p12 or .pfx) from Windows application to Server machine, Windows application developed in .Net Framework 4.6, OS is windows 10.

When hit from postman with client certificate (.p12 or .pfx) [Loaded in setting tab -> Add client certificate - > put hostname, select pfx file, put password], all working properly (client certificate send to server machine), but issue from below c# code,

X509Certificate2 certificate = new X509Certificate2(certificateFilePath, "password"); WebRequestHandler handler = new WebRequestHandler(); handler.ClientCertificateOptions = ClientCertificateOption.Manual; handler.ServerCertificateValidationCallback = (a, b, c, d) => { return true; }; handler.ClientCertificates.Add(certificate); HttpClient request = new HttpClient(handler); request.DefaultRequestHeaders.Add("User-Agent", UserAgent); // added other headers and data var result = request.PostAsync(url, byteContent).Result; string resultContent = result.Content.ReadAsStringAsync().Result; 

Also cross check with fiddler for Postman hit and c# hit.

When server not receive client certificate, it return 403 error.

5
  • What's the error? Commented Oct 6, 2019 at 4:19
  • error gives like 403 Forbidden Commented Oct 6, 2019 at 4:30
  • Does your sever know the client cert? It needs the cert to verify it on its end. @Kahbazi, a WebRequestHandler is an HttpClientHandler according to the docs. Commented Oct 12, 2019 at 16:28
  • 1
    @SomnathKadam - You may be getting this error code due to TLS protocol. If your server application is configured with a fixed TLS version which your client not then you should be sending the request with provided TLS version (or all like System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;). Also, can you please post the resultContent, it should have the error details. Commented Oct 12, 2019 at 17:14
  • There are many possible reasons for this sort of failure, some of them rather obscure. I suggest turning on a trace, which will allow you to view each step of the handshake process and determine what is going wrong exactly. Commented Oct 12, 2019 at 18:27

2 Answers 2

7

I assume that your handler has no access to the private key for authentication.

This may be caused due to line 1 in your example, in which you import the certificate with the default key storage flags. Of course this is just a guess and I don't have your certificate to check this, but you can verify that by calling

// Sample for RSA, use DSA if required var privateKeyParams = ((RSA)certificate.PrivateKey).ExportParameters(true); 

which will cause a CryptographicException ("Not supported" or similar) if the key parameters cannot be accessed.

Please try the following instead for loading the certificate:

X509Certificate2 certificate = new X509Certificate2( certificateFilePath, "password", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.UserKeySet); 

Just a further sidenote; If you use this in production code, be sure to extend your server certificate validation callback (your 4th line) to actually validate the server certificate. See X509Chain.Build, which also allows you to modify the validation options to your needs (what the path validation actually does can be read in RFC5280).

Sign up to request clarification or add additional context in comments.

Comments

6
+25

The HttpStatus code 403 can caused by TLS issues due to not invoking API with the expected server TLS version. You can check the outcome of resultContent from the code line string resultContent = result.Content.ReadAsStringAsync().Result;

To set the SslProtocol, either you can set at Handler like (if you are targeting .Net 4.7 onwards or .Net core)

WebRequestHandler handler = new WebRequestHandler(); handler.SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; 

or at application level using ServicePointManager in Startup method (or .Net framework version before 4.7)

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; 

A side note suggestion - I would suggest you to use pure async/await pattern. Don't use the sync call on the IO request by invoking .Result.

2 Comments

I already set System.Net.ServicePointManager.SecurityProtocol, but not working on Windows 10 with framework 4.8.
Can you please the outcome of resultContent from the code line string resultContent = result.Content.ReadAsStringAsync().Result?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.