Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nginx - how to access Client Certificate's Subject Alternative Name (SAN) field

I have an Nginx server which clients make requests to with a Client certificate containing a specific CN and SAN. I want to be able to extract the CN (Common Name) and SAN (Subject Alternative Names) fields of that client cert.

rough example config:

server {
listen 443 ssl;
ssl_client_certificate /etc/nginx/certs/client.crt;
ssl_verify_client on; #400 if request without valid cert

location / {
    root    /usr/share/nginx/html;

}
location /auth_test {
    # do something with the CN and SAN.
    # tried these embedded vars so far, to no avail
    return 200 "
    $ssl_client_s_dn 
    $ssl_server_name
    $ssl_client_escaped_cert
    $ssl_client_cert
    $ssl_client_raw_cert";
}
}

Using the embedded variables exposed as part of the ngx_http_ssl_module module I can access the DN (Distinguished Name) and therefore CN etc but I don't seem to be able to get access to the SAN.

Is there some embedded var / other module / general Nginx foo I'm missing? I can access the raw cert, so is it possible to decode that manually and extract it?

I'd really rather do this at the Nginx layer as opposed to passing the cert down to the application layer and doing it there.

Any help much appreciated.

like image 574
joeweoj Avatar asked May 30 '18 21:05

joeweoj


2 Answers

You can extract them with the Nginx-builtin map, e.g. for CN:

map $ssl_client_s_dn $ssl_client_s_dn_cn {
    default "";
    ~,CN=(?<CN>[^,]+) $CN;
}
like image 190
js. Avatar answered Oct 08 '22 16:10

js.


I'm not a lua expert, but here's what I got working:

local openssl = require('openssl')

dnsNames = {}
for k,v in pairs(openssl.x509.read(ngx.var.ssl_client_raw_cert):extensions()) do
    for k1,v1 in pairs(v:info()) do
        if(type(v1)=='table') then
            for k2,v2 in pairs(v1) do
                if(type(v2)=='table') then
                    for k3,v3 in pairs(v2) do
                        if(k3=='dNSName') then
                            table.insert(dnsNames, v3:toprint())
                        end
                    end
                end
            end
        end
    end
end
ngx.say(table.concat(dnsNames, ':'))
like image 23
Terry Hardie Avatar answered Oct 08 '22 14:10

Terry Hardie