Wednesday, 24 August 2016

SSL Client Authentication, Certificate Authorisation and IBM HTTP Server

Context

To enable IBM HTTP Server (IHS) to "authorise" incoming requests based upon the "identity" of the client. This goes above and beyond SSL Client ( aka Mutual ) Authentication, where a server will require a client to present a valid certificate which both parties trust.

This leverages the SSLClientAuthRequire directive in IHS

Detail

I tested this using IHS 8.5.5.8 on both Red Hat Linux and IBM AIX, using the Firefox browser in both cases.

In the case of Linux, I created a pair of self-signed personal certificates on my Mac, imported them into Firefox ( using the PKCS12 keystone format which includes my personal key ), and configured IHS to accept ONE of the TWO certificates using the Common Name (CN) attribute.

Client Setup

Define Self-Signed Certificates

vi davehay1.conf

[req]
default_bits           = 2048
default_keyfile        = davehay.key
distinguished_name     = macintosh
attributes             = req_attributes
prompt                 = no
output_password        = passw0rd

[macintosh]
C                      = GB
ST                     = Hampshire
L                      = Winchester
O                      = IBM
OU                     = ICCTE
CN                     = macintosh1.uk.ibm.com

[req_attributes]
challengePassword      = passw0rd


vi davehay2.conf

[req]
default_bits           = 2048
default_keyfile        = davehay.key
distinguished_name     = macintosh
attributes             = req_attributes
prompt                 = no
output_password        = passw0rd

[macintosh]
C                      = GB
ST                     = Hampshire
L                      = Winchester
O                      = IBM
OU                     = ICCTE
CN                     = macintosh2.uk.ibm.com

[req_attributes]
challengePassword      = passw0rd

Create Self-Signed Certificates

The first also generates a private key

openssl req -config davehay1.conf -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout davehay.key -out davehay1.crt

The second uses the existing private key

openssl req -config davehay2.conf -x509 -sha256 -nodes -days 365 -key davehay.key -out davehay2.crt -new

Generate PKCS12 Certificate Stores - required for import into client browser

openssl pkcs12 -export -out davehay1.p12 -inkey davehay.key -in davehay1.crt -password pass:passw0rd

openssl pkcs12 -export -out davehay2.p12 -inkey davehay.key -in davehay2.crt -password pass:passw0rd


Import PKCS12 Stores into Firefox

This is available via the Preferences -> Advanced -> Certificates -> View Certificates dialogue



Send Mac Personal Certificates to IHS

cp *.crt wasadmin@bpm856:~

wasadmin@bpm856's password: 
davehay1.crt                                                                                                                                                              100% 1237     1.2KB/s   00:00    
davehay2.crt                                                                                                                                                              100% 1237     1.2KB/s   00:00    



Server Setup

Create Key/Trust store - required for IHS

/opt/IBM/HTTPServer/bin/gskcapicmd -keydb -create -db /opt/IBM/HTTPServer/ssl/keystore.kdb -pw passw0rd -type cms -expire 3650 -stash

Generate a Self-Signed Certificate - presented by IHS to client

/opt/IBM/HTTPServer/bin/gskcapicmd -cert -create -db /opt/IBM/HTTPServer/ssl/keystore.kdb -stashed -dn "cn=bpm856.uk.ibm.com,dc=uk,dc=ibm,dc=com" -label bpm856.uk.ibm.com_ss -default_cert yes

Add Mac Personal Certificates - required to establish trust between client browser and IHS

/opt/IBM/HTTPServer/bin/gskcapicmd -cert -add -db /opt/IBM/HTTPServer/ssl/keystore.kdb -stashed -file ~/davehay1.crt 

/opt/IBM/HTTPServer/bin/gskcapicmd -cert -add -db /opt/IBM/HTTPServer/ssl/keystore.kdb -stashed -file ~/davehay2.crt 


Validate Key/Trust store

/opt/IBM/HTTPServer/bin/gskcapicmd -cert -list -db /opt/IBM/HTTPServer/ssl/keystore.kdb -stashed

Certificates found
* default, - personal, ! trusted, # secret key
! CN=macintosh1.uk.ibm.com,OU=ICCTE,O=IBM,L=Winchester,ST=Hampshire,C=GB
! CN=macintosh2.uk.ibm.com,OU=ICCTE,O=IBM,L=Winchester,ST=Hampshire,C=GB
*- bpm856.uk.ibm.com_ss


Add SSLClientAuthRequire directive to IHS httpd.conf

...
SSLClientAuthRequire (CN = "macintosh1.uk.ibm.com" )


This means that IHS will only accept requests when presented with the macintosh1.uk.ibm.com personal certificate.

Functional Test using Firefox on Client

Access IHS: -

https://bpm856.uk.ibm.com:8443/

When prompted, choose to present macintosh1.uk.ibm.com personal certificate

Should be able to access IHS, as IHS "trusts" this certificate via the SSLClientAuthRequire directive.

Close Firefox

Re-run functional test - choose macintosh2.uk.ibm.com personal certificate

Should receive "You don't have permission to access / on this server." and this message: -

[Wed Aug 24 19:59:49 2016] [error] [client 192.168.153.1] [7feb140008c0] [31411] SSL0279E: SSL Handshake Failed due to fatal alert from client. Client sent fatal alert [level 2 (fatal), description 48 (unknown_ca)]  [192.168.153.1:60794 -> 192.168.153.200:8443] [19:59:49.000695476] 0ms

in IHS error_log, and: -

192.168.153.1 - - [24/Aug/2016:19:59:56 +0100] "GET / HTTP/1.1" 403 273
192.168.153.1 - - [24/Aug/2016:19:59:56 +0100] "GET /favicon.ico HTTP/1.1" 403 284
192.168.153.1 - - [24/Aug/2016:19:59:56 +0100] "GET /favicon.ico HTTP/1.1" 403 284


in IHS access_log, all because macintosh2.uk.ibm.com is NOT in the SSLClientAuthRequire directive.

As we discovered, the directive isn't a catch-all - the match has to be 100%, wildcards aren't an option - the match has to be for the precise value of the certificate's CN ( in this case ).

If, for example, a certificate has a wildcard ( * ) in the CN, such as *.uk.ibm.com, that's precisely what needs to go in the directive, wrapped in double-quotes.

This is nicely documented here: -

Simple when you know how :-)

No comments:

Note to self - use kubectl to query images in a pod or deployment

In both cases, we use JSON ... For a deployment, we can do this: - kubectl get deployment foobar --namespace snafu --output jsonpath="{...