Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using client certificate not in certificate store

I'm trying to authenticate myself against WebService using my client certificate, but, for some reasons (I explain), I don't want to load certificate from store, rather read it from disc.

The following:

// gw is teh WebService client
X509Certificate cert = new X509Certificate(PathToCertificate);
_gw.ClientCertificates.Add(ClientCertificate());
ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true;
_gw.DoSomeCall();

returns always 403 - the Service doesn't authorize me. But, when I save that certificate into CertStore, it works. (As stated in MSDN.)

Is it possible to use certificate not in store?

(the reason is, that I got windows service(client) sometimes calling webservice(server), and after unspecified amount of time the service 'forgets' my certificates and doesnt authorize against server, with no apparent reason)

like image 220
nothrow Avatar asked Oct 29 '09 13:10

nothrow


People also ask

What is the difference between client certificate and server certificate?

Client certificates tend to be used within private organizations to authenticate requests to remote servers. Whereas server certificates are more commonly known as TLS/SSL certificates and are used to protect servers and web domains.

Can I use same certificate for server and client?

It's technically possible for a TLS certificate to be used as both a server certificate and a client certificate. The TLS certificate for this very site has its key usage set that way, for instance. But the server which requires a client certificate does so to authenticate the client.

What does it mean when a website requires a client certificate?

If a client certificate is supplied in the browser's Certificate response to the server's challenge, the browser proves the user's possession of that certificate using the private key that matches that client certificate's public key.


2 Answers

What type of file is PathToCertificate? If it's just a .cer file, it will not contain the private key for the certificate and trying to use that certificate for SSL/TLS will fail.

However, if you have a PKCS7 or PKCS12 file that includes the public and private key for the certificate, your code will work (you might need to use the overload that takes a password if the private key has one).

To test this, I went to http://www.mono-project.com/UsingClientCertificatesWithXSP and created my client.p12 file following those instructions. I also created a simple HTTPS server using HttpListener for testing.

Then I compiled the following program into 'client.exe' and run like:

 client.exe https://<MYSSLSERVER>/ client.p12 password

where client.p12 is the PKCS12 file generated before and 'password' is the password I set for the private key of the certificate.

using System;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;

public class HttpWebRequestClientCertificateTest : ICertificatePolicy {

    public bool CheckValidationResult (ServicePoint sp, X509Certificate certificate,
            WebRequest request, int error)
    {
            return true; // server certificate's CA is not known to windows.
    }

    static void Main (string[] args)
    {
            string host = "https://localhost:1234/";
            if (args.Length > 0)
                    host = args[0];

            X509Certificate2 certificate = null;
            if (args.Length > 1) {
                    string password = null;
                    if (args.Length > 2)
                            password = args [2];
                    certificate = new X509Certificate2 (args[1], password);
            }

            ServicePointManager.CertificatePolicy = new HttpWebRequestClientCertificateTest ();

            HttpWebRequest req = (HttpWebRequest) WebRequest.Create (host);
            if (certificate != null)
                    req.ClientCertificates.Add (certificate);

            WebResponse resp = req.GetResponse ();
            Stream stream = resp.GetResponseStream ();
            StreamReader sr = new StreamReader (stream, Encoding.UTF8);
            Console.WriteLine (sr.ReadToEnd ());
    }
}

Let me know if you want me to upload the server code and the certificates used on both sides of the test.

like image 83
Gonzalo Avatar answered Sep 27 '22 19:09

Gonzalo


The potential problem could be caching of SSL sessions (Schannel cache). Only first request negotiates the SSL handshake. Subsequent requests will use the same session ID and hope that the server accept it. If the server clears the SessionId, the requests will fail with 403 error. To disable local ssl session caching (and force SSL negotiation for each request) you have to open windows registry folder:

[HKEY_LOCAL_MACHINE][System][CurrentControlSet][Control][SecurityProviders][SCHANNEL]

and add the key named ClientCacheTime (DWORD) with value 0.

This issue is covered here:

http://support.microsoft.com/?id=247658

like image 38
PanJanek Avatar answered Sep 27 '22 20:09

PanJanek