3

I'm trying to develop an ASP.net site that reads the clientCertificate to ensure a smart card was used to access the website (trying to do away with username/password login).

The process I have in my mind is:

  1. User registers an account and C# records user's clientCertificate (public).
  2. The user can then log in the next time with that same clientCertificate, and they are now an authenticated user if hash valid.
  3. I will use the code below to ensure authenticity of certificate. The browser should deal with private keys and ensure the certificate was NOT faked.
  4. Based on Subject+certificate combination, C# assigns them their role-access.

The following code can be used for authenticity of certificate right?

X509Certificate x509Cert = new X509Certificate(Request.ClientCertificate.Certificate);
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] hashvalue = sha.ComputeHash(Request.ClientCertificate.Certificate);
byte[] x509Hash = x509Cert.GetCertHash();
// compare x509Hash WITH hashvalue to ensure they are a match. 
// If not, possibly faked certificate, not a real smartcard???

Is this how SmartCard authentication process should work???

Dexter
  • 6,170
  • 18
  • 74
  • 101

3 Answers3

2

See this thread, sir. You do not need to verify authenticity explicitly in your code. IIS will do it for you.

Does IIS do the SSL certificate check or do I have to verify it?

IIS even tries to check revocation lists (however, this is often disabled if the CRL is large). An OCSP responder should be used to validate in cases where the CRL is very large or latency in checking it is high http://www.axway.com/products-solutions/email-identity-security/identity-security/va-suite.

Community
  • 1
  • 1
mikey
  • 5,090
  • 3
  • 24
  • 27
  • So in the C# code, when I grab Request.ClientCertificate.Certificate and Request.ClientCertificate.Subject--it is guaranteed that the person didn't just make a copy of the person's smartcard certificate and copy the public key? (in other words, IIS will ensure Request.ClientCertificate.Certificate will be unique and authentic every time?) – Dexter Apr 20 '12 at 15:43
  • IIS will help you ensure the certificate provided is valid. Btw, the public key is public. Everybody can have it: http://en.wikipedia.org/wiki/Secure_Socket_Layer – Ulises Apr 20 '12 at 16:00
  • Yeah, of course, that's my point. If I'm checking the public key in my code as a way to determine if this user is truly the user that registered with my code&database before---then that's a security flaw, because publickeys are public to everyone. I was wondering if I needed privatekey-publickey-combo checking to ensure authenticity. – Dexter Apr 20 '12 at 16:14
  • Dexter, in the past I've used the SUBJECTCN field as the users identifier. It depends on the smart card. You can but shouldn't use public key as the key. If the user loses their card and is reissued a new one the public key usually changes, but the SUBJECTCN (or some other field, it really depends on what type of smart card we're talking about) stays the same. In addition, you cannot check the private/public combo to ensure authenticity because you have no access to the users private key. The type of authenticity checking you're after is done in the SSL handshake as Bruno states. – mikey Apr 20 '12 at 19:55
  • IIS checks that the cert the user presents is signed by a trusted CA. If you tighten up your list of trusted CAs you can be relatively sure the certificate presented is legit. – mikey Apr 20 '12 at 19:56
2

If you just need to authenticate users with client certificates you should do this in IIS. You do not need to add any code at all to your application:

Specify Whether to Use Client Certificates (IIS 7)

Unless you need to link client certificates with database accounts or perform an additional validation step. But still for client certificate authentication I would stick with IIS settings.

Update: In case you need to manipulate the client certificate you can do:

X509Certificate2 x509Cert2 = new X509Certificate2(Page.Request.ClientCertificate.Certificate);

And then access its properties such as:

x509Cert2.Subject

However, leave the validation piece up to IIS. If the client presents a bad certificate your asp.net code will not even execute since IIS will reject it

Ulises
  • 13,229
  • 5
  • 34
  • 50
  • Yes, I am linking the client certificate (smartcard) with a database account with higher privileges. I have to be 100% certain, the smartcard actually belongs to them, and isn't just a copy or fake certificate with the same public key. – Dexter Apr 20 '12 at 15:41
  • Ok, in that case get the properties of the request cert object (X509Certificate2) with Page.Request.ClientCertificate.Certificate, such as "x509Cert2.Subject". However, leave the validation piece up to IIS. If the client presents a bad certificate your asp.net code will not even execute since IIS will reject it. – Ulises Apr 20 '12 at 15:45
  • So my code is correct then? I just check if the hash and certificate is valid (certificate.IsValid), and maybe put it in a try { } catch {} and that will be enough to ensure the person has a correct smartcard? The catch will trigger and I can fail the log in, because the code couldn't grab the certificate (because it's fake). – Dexter Apr 20 '12 at 15:50
  • IIS ensures the client certificate provided is valid (not expired, issued by a trusted authority, etc). Once IIS says it's good then it hands the request to asp.net (your code). At this point you have a valid certificate and if you wish to do any processing with the certificate you can extract the client certificate from the request using the code above. In my opinion, in a production server where IIS has been configured "certificate.IsValid" is redundant (maybe useless). – Ulises Apr 20 '12 at 15:55
  • Well what I mean is, let's say a user uses his smartcard to register on my site. Then he goes to a phishing site, and happens to use his smartcard there. Now the phisher has his .ClientCertificate (public keys), and has his .Subject line. Now if phisher generates the same certificate as a file and plugs it in his browser, will IIS check public+private keys (or send private+public key to certificate authority to check) to ensure that this is the REAL certificate or one that the phisher generated himself. So I don't have to do any further public-private key validation to authenticate the user? – Dexter Apr 20 '12 at 16:03
  • So by the time my code calls x509Cert2.Subject, it should be guaranteed that the certificate is authenticated through AES hash checking with certificate authority. Meaning I don't even have to check if the public key is valid. Just put try/catch around .Subject and if I can access subject then it means it's an authentic unique certificate belonging to the user. – Dexter Apr 20 '12 at 16:07
  • The phisher scenario won't work since client certificates are digitally signed by Certificate Authorities. IIS will take care of checking it's good. That's correct, in your code you don't have to mess with the keys to ensure the certificates are valid, as I mentioned, at this point you will be already dealing with valid certificates (thanks to IIS). – Ulises Apr 20 '12 at 16:09
  • Well that's cool, a lot less work then. So now I wonder why the example code I found, checks to ensure the casted X509 certificate has the same hash as the raw Request.ClientCertificate.PublicKey hash. I wonder what security purpose that servers. – Dexter Apr 20 '12 at 16:12
  • All I will do now, is make a database table, with "subject", "clientcertificate" and "userid" and match privileged user accounts to the X509Certificate2 certificate and subject line. – Dexter Apr 20 '12 at 16:17
1

Client-certificate authentication is done during the SSL/TLS handshake.

It is usually done using a Public Key Infrastructure, whereby the server has a (fixed) list of trusted CA certificates which it uses to verify the client certificate (in the same way as clients to it for the server). Once the certificate is presented to your application after this stage, you will know that:

  • the client has the private key for that certificate (guaranteed by the Certificate Verify message in the TLS handhsake (the SSL/TLS stack will verify this for you, no need to implement anything);
  • the client has the identity described in the certificate, because you will have verified it against your trusted CA.

The verification against a trusted CA requires the user to be registered with that CA in advance. You can't just authenticate any certificate if it hasn't been issued by a CA you trust. (Mapping the certificate's subject to a local user ID is another matter: you could do this upon first connection if needed: have your own database or directory service to map the Subject DN to another kind of user ID in your application, for example.)

User registers an account and C# records user's clientCertificate (public). The user can then log in the next time with that same clientCertificate, and they are now an authenticated user if hash valid.

It sounds like you want to allow any certificate to be presented and use it for the initial registration, without necessarily resorting to a commonly trusted CA.

This is possible in principle, and I've done this to explore alternatives to PKI in Java.

To do this, you need to let any certificate through as far as the SSL/TLS handshake is concerned, and verify the certificate itself later. (You do need to use some form of verification.) You are still guaranteed with this that the client has the private key for the public key certificate it has presented.

Doing this requires two steps:

  • You need to be able to advertise the fact that you're going to accept any certificate, by sending an empty list of certification authorities in the Certificate Request TLS message (explicitly allowed by TLS 1.1).
  • Configure the SSL/TLS stack to trust any certificate (once again, when you do this, do not forget to implement your own verification system within your application, otherwise anything will really get through).

In .Net, while it should be possible to address the second point using a remote certificate validation callback, I have never found a way to alter the first point (this was also asked in this question).

In Java, the JSSE's X509TrustManager allows you to address both points.

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • No I am only allowing users who have the type of smartcard that I am looking for, to have access to the system. I think I would have to contact the certificate authority, request a server certificate, then 'complete' certificate request, and then plug that into the system, before I can start allowing clients to register their Clientcertificates with the server database. I am guessing I have to use try/catch to check if the user has entered a valid certificate, or otherwise, an error will pop up when they have an invalid private key. – Dexter Apr 20 '12 at 17:30
  • Having the same type of smartcard doesn't mean that all your users have certs from the same CA. (It may be the case if they're given by the CA within your environment, for example.) Your server cert doesn't have to be from one of the CAs from which you're going to accept client certs (it's rather independent). You don't even have to try/catch: if the user comes with a cert that's not recognised by a CA that you've configured, the SSL/TLS connection won't even be established (so no HTTP(S) connection either). From a UI point of view, this will look like `ssl_error_blablabla` in their browser. – Bruno Apr 20 '12 at 17:46
  • Well right now I'm testing in my Dev environment with a self-signed server certificate, and just reading the client certificate (regardless I'm not checking any CAs) so it always says SSL error but it allows you into the website. When I cast as X509Certificate2, it throws a CryptographyException if you alter the bytes of the certificate and then try to compute a hash. So the exception can let you know if something fishy is going on with this certificate. That is one way your server-side code can ensure authenticity (otherwise you'd need verify client certificate revocation and some IIS setting – Dexter Apr 20 '12 at 18:59
  • I don't think you're talking about the same certificate. Make sure your server certificate is trusted by your browser (import it explicitly if needed) before experimenting with this, at least to know on which side you get the error. The exception you're talking about is about the certificate verification itself (i.e. its signature and who signed it), not about the fact that its public key has a private key held only be the actual client. These are completely different aspects (see [this](http://security.stackexchange.com/a/13953/2435) perhaps). – Bruno Apr 21 '12 at 01:39