03May

Authenticating people with Apache2 and national electronic ID cards.

Written by in National ID cards

Certificates stored on ID cards can be used to identify people online. In simplest terms the webserver tells browser what kind of certificates it accepts and if browser has them then authentication procedure is started. Official ID card software integrates with browser and adds certificates from the hardware backed ID card to the “Your Certificates” list.

Apache configuration has a few points to keep in mind besides regular https setup. Directives that need to be added are SSLCACertificateFile, SSLCARevocationPath, SSLCARevocationCheck, SSLVerifyClient, SSLVerifyDepth and SSLOptions. This guide is meant for Ubuntu operating system but should work in any other Linux as well.

Build certificate chain file.

Firstly you need to get full CA chain in PEM format and merge it into one certificate chain file. This includes root certificate, all intermediate certificates and any other issuance certificates if needed. Each country and CA has its own sources were to find these certificates.

SSLCACertificateFile /etc/ssl/mycatest/cachain.pem

Check certificate revocation lists

As the national ID card certificates can be revoked if the card gets stolen or lost then we must check also certificate revocation lists CRL to be sure that we don’t let any bad guys in. Usually each certificate has included path to the public CRL lists. These CRL-s are update periodically, for example once of twice a day so don’t forget to build a script to keep them updated. You can also use and modify script from the Estonian ID card renewal guide http://id.ee/public/renew.sh . SSLCARevocationCheck enables CRL check. It has options leaf and chain. Leaf checks only end-entity cert while chain verifies all of the certificates in the chain and is recommended setting.

Download all of these CRL-s into one folder and use following command to convert these to PEM format if needed

$ for f in *.crl; do openssl crl -in $f -out $f -inform DER; done

It is optional but recommended to merge all of the CRL files into one because if CRL distribution list is missing from some CA certificate then CRL check will fail. “error 44 at 2 depth lookup:Different CRL scop” or “AH02039: Certificate Verification: Error (3): unable to get certificate CRL”.

cat *.crl > all.crl

Make symlinks based on filename hash into same folder next to the PEM CRL-s

$ for f in *.crl; do ln -s $f `openssl crl -hash -noout -in $f`.r0; done

Now add the CRL folder to the Apache vhost config and enable CRL check.

SSLCARevocationPath /etc/ssl/mycatest/crl
SSLCARevocationCheck chain

Make server ask from browser to authenticate with certificate.

Firstly SSLVerifyClient require|optional means that browser must or may send certificate authentication status. If require is used then without certificate the browser shows SSL error message. Optional is sometimes better because it allows script execution to proceed and application can show proper error message when SSL variables are missing SSLVerifyDepth says how many certificates in the chain must be verified and SSLOptions make the certificate details available for the PHP scripts in $_SERVER array. SSLVerifyclient and SSLVerifyDepth can also be added to the Location or Directory contexts.

SSLVerifyClient optional
SSLVerifyDepth 3
SSLOptions +StdEnvVars +ExportCertData

Full apache2 ID card certificate authentication config

In summary all the extra vhost directives in https vhost config are.

SSLCACertificateFile /etc/ssl/mycatest/cachain.pem
SSLCARevocationFile /etc/ssl/mycatest/crl/all.crl
SSLCARevocationCheck chain
SSLVerifyClient optional
SSLVerifyDepth 3
SSLOptions +StdEnvVars +ExportCertData

Debugging Apache2 client certificate authentication

Browser must ask for pin code and server make SSL parameters available if all is correctly configured. If browser does not ask pin code then either server does not have correct CA certificates installed or ID card official browser integration software is not installed.  If SSL error happens after asking for pin code then cachain.pem does not contain root certificate or some intermediate certificate.

Openssl command line tool helps to verify which acceptable CA certificates server knows about. Use following command:

$ openssl s_client -port 443 -host ee.smartid.ee -servername ee.smartid.ee -prexit

After connection type command for GET request and see what acceptable CA names are printed out.

GET / HTTP/1.1
HOST: ee.smartid.ee

Output must contain something like this:

Acceptable client certificate CA names
/C=EE/O=AS Sertifitseerimiskeskus/CN=EID-SK 2011/emailAddress=pki@sk.ee
/C=EE/O=AS Sertifitseerimiskeskus/2.5.4.97=NTREE-10747013/CN=ESTEID-SK 2015
/C=EE/O=AS Sertifitseerimiskeskus/CN=ESTEID-SK 2011/emailAddress=pki@sk.ee
/C=EE/O=AS Sertifitseerimiskeskus/CN=EE Certification Centre Root CA/emailAddress=pki@sk.ee

If server accepts the correct CA name then you can manually verify, if the certificate on the card is indeed signed by one of the CA certificates configured in server. For this go to your browser and look for your hardware backed certificates. In Chrome open preferences and search “certificates” and click on “Manage certificates”. If Chrome browser has just been restarted then PIN code is asked from you before you can see your certificate under “Your certificates”. If no pin code is asked and certificate is missing then make sure your card reader is installed and card inserted with official ID card management software and restart the browser. Pin code asking should look like this image 

Once it is done then export your certificate to the file and verify it via openssl command line tool. Exporting is best done via same browser “Your certificates” tab to make sure the very same certificate is checked that browser has. In Chrome click view->Details->Export->Base64-encoded ASCII, single certificate.

Openssl command for verifying certificate looks like:
$ openssl verify -CAfile /etc/ssl/mycatest/cachain.pem exportedcert.pem
exportedcert.pem: OK

View of exporting the certificate looks like this: