Client Side Certificate Demo

User/email:
Password:

https://sx509.w0.dk/ Click here to logon with Client Certificate (use Mozilla Firefox)



Video demonstration


Get your own client certificate

Create a client certificate on cacert.org

Without installing software you can go to cacert.org and create one.

Create a '*.p12' file with OpenSSL

NAME="John Doe"
EMAIL="john.doe@example.org"
FILE=${EMAIL/@/_}
openssl req -x509 -sha256 -nodes -subj "/C=DK/ST=Interstate/L=Capital/O=Acme/OU=IT/CN=$NAME/emailAddress=$EMAIL" -days 7300 -newkey rsa:2048 -keyout $FILE.key -out $FILE.pem
openssl pkcs12 -export -in $FILE.pem -inkey $FILE.key -out $FILE.p12

If you can not generate this PKCS12 file yourself, then grab a test one here: john.doe_example.org.p12 - it has no password.

Import the P12 client certificate into your browser

It is done differently for all browseres. Smartphones are worse.

Firefox

  1. Click the burger-menu in upper right corner
  2. Click Preferences
  3. Click Privacy & Security about:preferences#privacy
  4. Scroll down to the bottom
  5. Click button [View Certificates...]
  6. Click button [Import...]
import-firefox.png

Chrome

Open your settings in Google Chrome: chrome://settings/certificates and import the *.p12 file. Chrome says the certificate is untrusted, but you trust it as you generated it.

Now you can visit: https://sx509.w0.dk/

curl

A quick test can be done by using curl together with the P12-file:

$ curl -s --cert-type P12 --cert john.doe_example.org.p12 https://sx509.w0.dk/ | grep SSL_
<p>Source: <tt>Welcome: &lt;<?php if (preg_match("/=([A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,})/i", $_SERVER["SSL_CLIENT_S_DN"], $m)) echo $m[1] ?>&gt; '<?= $_SERVER["SSL_CLIENT_SERIAL"] ?>'</tt></p>
<caption>Environment variables which match <tt>SSL_*</tt></caption>
<tr><td>SSL_SERVER_NAME</td><td>x509.w0.dk</td></tr>
<tr><td>SSL_PROTOCOL</td><td>TLSv1.2</td></tr>
<tr><td>SSL_CLIENT_VERIFY</td><td>FAILED</td></tr>
<tr><td>SSL_CLIENT_SERIAL</td><td>9542F240CF4B0BC4</td></tr>
<tr><td>SSL_CLIENT_S_DN</td><td>/C=DK/ST=Interstate/L=Capital/O=Acme/OU=IT/CN=John Doe/emailAddress=john.doe@example.org</td></tr>
<tr><td>SSL_CLIENT_I_DN</td><td>/C=DK/ST=Interstate/L=Capital/O=Acme/OU=IT/CN=John Doe/emailAddress=john.doe@example.org</td></tr>
<tr><td>SSL_CLIENT_FINGERPRINT</td><td>08f7d7359d1d0fdeee9c1e3ac799314dad48267c</td></tr>
$_SERVER['SSL_CLIENT_I_DN'] = /C=DK/ST=Interstate/L=Capital/O=Acme/OU=IT/CN=John Doe/emailAddress=john.doe@example.org
$_SERVER['SSL_CLIENT_SERIAL'] = 9542F240CF4B0BC4
$_SERVER['SSL_CLIENT_S_DN'] = /C=DK/ST=Interstate/L=Capital/O=Acme/OU=IT/CN=John Doe/emailAddress=john.doe@example.org
$_SERVER['SSL_CLIENT_S_DN_CN'] = 
$_SERVER['SSL_CLIENT_S_DN_G'] = 
$_SERVER['SSL_CLIENT_S_DN_S'] = 
$_SERVER['SSL_CLIENT_VERIFY'] = FAILED

Documentation

A good page to start: Using SSL Client Certificates with PHP.

When nginx has been configured it can be verified with curl:

$ curl -v -o /dev/null https://x509.w0.dk/ 2|& grep Req
* TLSv1.2 (IN), TLS handshake, Request CERT (13):

The Nginx conf:

log_format sslclient
    '"$ssl_client_s_dn" $ssl_client_serial $ssl_client_fingerprint'
    ' $remote_addr - $remote_user [$time_iso8601]'
    ' "$request" $status $body_bytes_sent $request_time'
    ' "$http_referer" "$http_user_agent"';

server {
    listen 443 ssl;
    listen [::]:443 ssl; # only for IPv6
    server_name sx509.w0.dk;
    root /var/www/sx509.w0.dk;
    access_log /var/log/nginx/sx509.w0.dk/access.log sslclient;
    error_log /var/log/nginx/sx509.w0.dk/error.log;
    index index.php index.html;

    ssl_certificate /root/.acme.sh/sx509.w0.dk/fullchain.cer;
    ssl_certificate_key /root/.acme.sh/sx509.w0.dk/sx509.w0.dk.key;
 
    # Entries required for client side certificate
    ssl_verify_client optional_no_ca;
    ssl_verify_depth 1;

    location ~ \.php$ {
	# email: Match a string without '=' and ','
	# Example: emailAddress=john.doe@example.org,CN=John Doe,OU=IT,O=Acme,
    	set $ssl_foo_email "";
	if ($ssl_client_s_dn ~ "([^=]+@[^,]+)") {
		set $ssl_foo_email $1;
	}
        fastcgi_param SSL_FOO_EMAIL $ssl_foo_email;

        fastcgi_param SSL_CIPHER $ssl_cipher;
        fastcgi_param SSL_CIPHERS $ssl_ciphers;
        fastcgi_param SSL_CLIENT_CERT $ssl_client_cert;
        fastcgi_param SSL_CLIENT_ESCAPED_CERT $ssl_client_escaped_cert;
        fastcgi_param SSL_CLIENT_FINGERPRINT $ssl_client_fingerprint;
        fastcgi_param SSL_CLIENT_I_DN $ssl_client_i_dn;
        fastcgi_param SSL_CLIENT_I_DN_LEGACY $ssl_client_i_dn_legacy;
        fastcgi_param SSL_CLIENT_RAW_CERT $ssl_client_raw_cert;
        fastcgi_param SSL_CLIENT_S_DN $ssl_client_s_dn;
        fastcgi_param SSL_CLIENT_S_DN_LEGACY $ssl_client_s_dn_legacy;
        fastcgi_param SSL_CLIENT_SERIAL $ssl_client_serial;
        fastcgi_param SSL_CLIENT_V_END $ssl_client_v_end;
        fastcgi_param SSL_CLIENT_VERIFY $ssl_client_verify;
        fastcgi_param SSL_CLIENT_V_REMAIN $ssl_client_v_remain;
        fastcgi_param SSL_CLIENT_V_START $ssl_client_v_start;
        fastcgi_param SSL_CURVES $ssl_curves;
        fastcgi_param SSL_PROTOCOL $ssl_protocol;
        fastcgi_param SSL_SERVER_NAME $ssl_server_name;
        fastcgi_param SSL_SESSION_ID $ssl_session_id;
        fastcgi_param SSL_SESSION_REUSED $ssl_session_reused;

        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php-fpm.sock;
    }

    location / {
    }
}

Download

client-certificate.x509.demo-files.2020-12-21.tar.gz

etc/nginx/sites-available/x509.w0.dk.conf
etc/nginx/sites-available/sx509.w0.dk.conf
var/www/x509.w0.dk/
var/www/x509.w0.dk/import-firefox.png
var/www/x509.w0.dk/index.php
var/www/x509.w0.dk/john.doe_example.org.p12
var/www/sx509.w0.dk/
var/www/sx509.w0.dk/index.php

Links