This is a small HOW-TO to help configure Client Certificate Authentication with Tomcat.

Most the document deals with the creation of a self-managed CA and certificates, so it should be useful too to those willing to manage their own CA and generate certificates.

Note that the CA you can generate with this HOW-TO is a base level CA, it doesn’t have all the functionality the commercial CA’s offer but is free like in freedom and beer!!!

Client Certificate Authentication with Tomcat


1. Introduction

Sometimes the BASIC authentication is not enough to guarantee the identity of the user, there are several methods to overcome this lack of security, one of them is to give certificate to the prospective users and use them for authentication.

We’ll use Certificates because of it’s low cost, we don’t need any device such as OTP generators or USB keys.

In the following sections we’ll perform several steps, we’ll begin from scratch building a Certificate Authority (CA), then we’ll generate the client certificates and export them to a keystore format we can use with tomcat (we have chosen PKCS12 because it’s an Internet standard and it’s the most commonly used format).

The last steps explain how to configure tomcat, how to install a certificate issued by a CA and how to access the certificate data programatically.

2. Creating the CA

We’ll use CA.sh (CA.pl is another option if you feel more comfortable with Perl scripts), a shell scrip which comes bundled with openssl (note that there’s also a Perl script named CA.pl, well use CA because you may find that Perl is not installed on your machine) , I found it along with openssl.cnf in the following path: /etc/pki/tls, CA is under the misc subdirectory.

I’ll explain the steps carried out by the CA script or put the equivalent openssl command just in case those scripts are not present in the system.

I have performed the following steps to create a CA:

  1. Create a directory to do our work, all commands will be executed under this directory (I have created certificatesTest under my home dir).
  2. Copy openssl.cnf and the misc directory to the chosen directory, remember that I found them under (/etc/pki/tls, I’m writing this HOW-TO on a Fedora-Core-4 powered machine, these locations can be different for other systems and/or versions). You can use locate CA.pl for finding the scripts.
  3. Verify that the configuration defined in openssl.cnf suits your needs, I had to change the following parameter:

    dir = ./CA instead of the default dir =../../CA

    Check also the remaining parameters, the certificate expiration is set to 365 days from the day of creation, if you need them to last longer raise this value.

  4. Define the system variable OPENSSL_CONF, this variable tells the script CA where to look for an alternative configuration file. The CA manpage says that you can define this variable in order to tell the script where to find the configuration file.
  5. I have found however that some parameter come hardcoded into the scripts (I’ve checked the shell and the Perl scripts and both suffer from this extravaganza), so you’ll have to open your favourite editor and modify these parameters in the scripts. Take special attention to the one defining where the CA is going to be created and the certificate expiration.
  6. Create a new CA:

    [root@localhost certificatesTest]# ./misc/CA -newca

    mkdir: cannot create directory `./CA’: File exists

    CA certificate filename (or enter to create)

    Making CA certificate …

    Generating a 1024 bit RSA private key …………………………………..++++++ …………………………………………++++++

    writing new private key to ‘./CA/private/./cakey.pem’

    Enter PEM pass phrase:<a secret passphrase>

    Verifying – Enter PEM pass phrase:<a secret passphrase>

    —– You are about to be asked to enter information that will be incorporated into your certificate request.

    What you are about to enter is what is called a Distinguished Name or a DN.

    There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter ‘.’, the field will be left blank. —–

    Country Name (2 letter code) [GB]:ES

    State or Province Name (full name) [Berkshire]:MADRID

    Locality Name (eg, city) [Newbury]:MADRID

    Organization Name (eg, company) [My Company Ltd]:Sabre-Wulf

    Organizational Unit Name (eg, section) []:OUN

    Common Name (eg, your name or your server’s hostname) []:TestCA

    Email Address []:raistlin@sabre-wulf.tk

    Note that we got a warning on the second line, this happens if you launch the command and the directory (named CA in our test) exists, this does not have any importance and the process should complete its task without any error because of this issue.

    This command created the CA directory structure and initializes some files such as index.txt and serial.

    If we don’t have the CA script or we want to know what goes on behind the curtain the process can also be performed the following way:

    mkdir -p ${CATOP}/{certs,crl,newcerts,private} Where ${CATOP} has been defined as the CA top directory)

    It creates the following files this way:

    echo “01″ > ${CATOP}/serial

    touch ${CATOP}/index.txt

    Then it ask for a CA certificate if no private key is found into the private directory. This step could be performed independently with the CA script or by executing openssl with the corresponding parameters:

    CA.pl -newcert

    The equivalent openssl command is: openssl req -new -x509 -keyout newreq.pem -out newreq.pem

    As we are creating the CA certificate, the command should be executed with this parameters (cakey.pem and cacert.pem are the filenames we have configured into openssl.cnf):

    openssl req -new -x509 -keyout CA/private/cakey.pem -out CA/cacert.pem

    We have created a new CA in the directory CA. The CA’s self-signed certificate is in the file CA/cacert.pem and it’s RSA key pair is in CA/private/cakey.pem

    CA/private/cakey.pem looks like this:

    [root@localhost certificatesTest]# cat CA/private/cakey.pem

    —–BEGIN RSA PRIVATE KEY—–

    Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,279840B77820951

    BTMp8vetCeroCeedt7PuWPEJUe/0YyzNK3ujNpUibDxp8hE4GGu6Tf9L0Vd2vDt1l

    yliCD6UM3CVKrH35hiwq0DHFrAMW/ZhWCrtSraPYESRcnpgYk9REJYVcjoDglvLa

    yW6tFzc/QC6wn+1VeFMj+Y1Rtmo3vPJRR0aT15Bh/bPFU7c6ydy8Q0cc2Qoiq0qh

    MI1pVrsEUkL2KSLx1w2fX4igjtpgotvt3ROxsjiNGz3cs9PpRefs/wRRHVW9UtOU

    L/oePs7sxv25/BLfDl4Xsgt5iP7MabUXkzR/WXfrg54Dnibbe014HJV4s7pudFWW

    gkgLTztK2FnAy1kQxG+6fNqBdia7mBGPOP8L/QXMYrWfp/Qo0Bu7Absm5YnP25da

    0nlLf5kOPplVsqMM34J1lu5W06FFRxJ8LMUNKraX04UBuRCwgxru8U50F1ZrqX2H

    Heem3ksMLVlWFItkdkOvEqV/6QP7BlgIhsVerIKThvs8d/xWiH2IOHGZPLiObyky

    0he0Mx3u+0W8aXy8s8lM7HbjnDkvUjXlDqzBI3wxglMgcwajdTl4vMPdxcOS8pJz

    pFK0GAaedS6uC4/xWuVR1Gnckp+XQTatNvHuXb1kH2P/DKShI5BYEUs6PTWBpRms

    9b2aAlI5fe3GoG4cmnMag+l9Th7r+tWT4mI73i/21MA2YVKeFsVMMMk+oxbcr9O+

    KPtLJIauMQP8/K+2ozKnOHXQ+V5vt6lMw13/6KhQSe85y/IcR6RJac5cdYKiA5WK

    vLVeQxFfo2KWRaY7e/a5D/4cBEOVSNLgS2XNrkpHHBVPynBMCVia9A==

    —–END RSA PRIVATE KEY—–

  7. This step is optional but could be useful in some scenarios, we’ll strip the certificate from all its text to keep only the -CERTIFICATE- section openssl x509 -in CA/cacert.pem -out CA/cacert.crt Place this file on your web site as http://mysite.com/ssl/cacert.crt.

    Your web server should have a mime entry for .crt files. Your certificate is ready to be downloaded by any browser and saved. It is important to publish the root CA Certificate on a web site as it is unlikely that people will have it already loaded on their browser.

    Somebody could fake your web site and fake your root CA Certificate. If you can have more than one way for users to get your certificate, it is unlikely that a cracker will be able to corrupt everything.

Now we have a working CA, it does not have all the functionality the commercial CA’s offer but it’s good enough for our needs.

3. Generating client certificates

To generate a client certificate we have to follow a well defined set of steps.

  1. We’ll generate a certificate request.

    [root@localhost certificatesTest]# ./misc/CA -newreq

    This command is equivalent to: openssl req -config /etc/openssl.cnf -new -keyout newreq.pem -out newreq.pem

    Generating a 1024 bit RSA private key ………………….++++++

    ..++++++ writing new private key to ‘newreq.pem’

    Enter PEM pass phrase:<another secret passphrase>

    Verifying – Enter PEM pass phrase:<another secret passphrase>

    —– You are about to be asked to enter information that will be incorporated into your certificate request.

    What you are about to enter is what is called a Distinguished Name or a DN.

    There are quite a few fields but you can leave some blank

    For some fields there will be a default value, If you enter ‘.’, the field will be left blank. —–

    Country Name (2 letter code) [GB]:ES

    State or Province Name (full name) [Berkshire]:MADRID

    Locality Name (eg, city) [Newbury]:MADRID

    Organization Name (eg, company) [My Company Ltd]:Sabre-Wulf

    Organizational Unit Name (eg, section) []:OUN

    Common Name (eg, your name or your server’s hostname) []:localhost

    Email Address []:raistlin@sabre-wulf.tk

    Please enter the following ‘extra’ attributes to be sent with your certificate request

    A challenge password []:josema

    An optional company name []:Sabre-Wulf

    Request (and private key) is in newreq.pem

    The certificate request and private key in newreq.pem looks like this:

    [root@localhost certificatesTest]# cat newreq.pem

    —–BEGIN RSA PRIVATE KEY—–

    Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,7A498A70B3D1B792

    vAJPEaYl7A1/B/XOGVQ5K3onaLd0+I75meMOlW/KGlCn2TvBbjQNxd9zB59DdmXT

    EhdDXcKksZclYSAb4UH1s6e2mRdj6FRCLjJb3YE8MFXthpR74nXJSkXZbXUP45Hn

    WY6pxO01W3ObOuEeQv8mSP8tR9XwKMLFSbULKTFGQPEKggxUw4zPboY8HxqgNS5/

    8KjKneNtNw3fv+QINP8YanLZjp7dw2tL9XHez7xutpVY12VnjACXzlORrbbdd7iw

    5iqvJs7WR1+fRzVs7ZDJkMjkTIkoWwctW9g/JSsfe30w0pLCr/SXHlNimZTKSLgr

    kQCJZnSX2+x4X74nGyyJ3sNaTx5gDwBK05XMjnuIxuKPciT0hRFD/VA2l8E/qxlB

    5QxHAysnyw2LPy3/7qNipT0pLFWwBqadkWf26EXyNYNsprlsizx8NA/8Sh6d+cwg 2

    6OeEH0S+wJ49LYaiHHvx9mBd+NRi0DU57vGbMKFrEdb7aDcxbm4NmcwoW7lFFJy

    7gmLTeXmBI2WFMXF+3Ddpro3lAqJiQAOkAcdX11sx87BwVjcArWLLf7aOUjHe4TH

    ljV2xMcbUu90PQw8Ns9xTw9Fv5f5gayBbS5yDwLG2BlZ5qlOQBmyN8CFos51QV7b

    IngAitZbC1F/kDdZy6aPl8vzgmOKShAmV+YMGpbIUI6kQNENpeDGE0lmwuHB5Rw7

    LRZl0SgYqx8R/b9DL/d+owY7X5sadRQaXVerD6Bu1nX114vxWNeMOloZmipmvY7t

    bXdQ/vAznFBh2/ab8yZADHGjJc5ME5TgJhFx42g3UmR03iJRUKVKog==

    —–END RSA PRIVATE KEY—–

    —–BEGIN CERTIFICATE REQUEST—–

    MIICEDCCAXkCAQAwgZ8xCzAJBgNVBAYTAkVTMQ8wDQYDVQQIEwZNQURSSUQxDzAN

    BgNVBAcTBk1BRFJJRDERMA8GA1UEChMIRVJJQ1NTT04xDDAKBgNVBAsTA1RTSzES

    MBAGA1UEAxMJbG9jYWxob3N0MTkwNwYJKoZIhvcNAQkBFipqb3NlLm1hbnVlbC54

    bS5tb2xpbmEucGFzY3VhbEBlcmljc3Nvbi5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD

    gY0AMIGJAoGBAMX+pRrP35HRlTbuByTF2iUrYXZXSN9Kxj5dP0lGTgQjYjXXJjBA

    rR9GF9Yl9Omx2EQO74SToraszLRUhsoa82edIP830bKepH7Ep+85ENQRljL0fwf8

    OhEMjkxlH0khX/GHTTtUyEmQl/S3jeg2mlw4yxZOWmC2hzFDEScsoCZNAgMBAAGg

    MDAVBgkqhkiG9w0BCQcxCBMGam9zZW1hMBcGCSqGSIb3DQEJAjEKEwhFcmljc3Nv

    bjANBgkqhkiG9w0BAQQFAAOBgQCpvKDPfFW4c7qoZpuvE0A00hCyibD1lyb5YbSA

    9tsm9HgY4h7M4Ec1HaDbgxE+5ltNjyOblJATfmddgbsm2m2/yrLEopceqd2+z6/N

    OakumumWVR9wT6W0qSoqA2xrRv8UQjWCsdIlSGMR7Lf0Q+FtWa0YR6CTWNzmx7aR

    wGcQzg==

    —–END CERTIFICATE REQUEST—–

    If we decode the certificate request we obtain the following:

    [root@localhost certificatesTest]# openssl req -text -noout < newreq.pem

    Certificate Request: Data: Version: 0 (0×0) Subject: C=ES, ST=MADRID, L=MADRID, O=Sabre-Wulf, OU=OUN, CN=localhost/emailAddress=raistlin@sabre-wulf.tk Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit):

    00:c5:fe:a5:1a:cf:df:91:d1:95:36:ee:07:24:c5:

    da:25:2b:61:76:57:48:df:4a:c6:3e:5d:3f:49:46:

    4e:04:23:62:35:d7:26:30:40:ad:1f:46:17:d6:25:

    f4:e9:b1:d8:44:0e:ef:84:93:a2:b6:ac:cc:b4:54:

    86:ca:1a:f3:67:9d:20:ff:37:d1:b2:9e:a4:7e:c4:

    a7:ef:39:10:d4:11:96:32:f4:7f:07:fc:3a:11:0c:

    8e:4c:65:1f:49:21:5f:f1:87:4d:3b:54:c8:49:90:

    97:f4:b7:8d:e8:36:9a:5c:38:cb:16:4e:5a:60:b6:

    87:31:43:11:27:2c:a0:26:4d

    Exponent: 65537 (0×10001) Attributes:

    challengePassword :josema

    unstructuredName :Sabre-Wulf

    Signature Algorithm: md5WithRSAEncryption

    a9:bc:a0:cf:7c:55:b8:73:ba:a8:66:9b:af:13:40:34:d2:10:

    b2:89:b0:f5:97:26:f9:61:b4:80:f6:db:26:f4:78:18:e2:1e:

    cc:e0:47:35:1d:a0:db:83:11:3e:e6:5b:4d:8f:23:9b:94:90:

    13:7e:67:5d:81:bb:26:da:6d:bf:ca:b2:c4:a2:97:1e:a9:dd:

    be:cf:af:cd:39:a9:2e:9a:e9:96:55:1f:70:4f:a5:b4:a9:2a:

    2a:03:6c:6b:46:ff:14:42:35:82:b1:d2:25:48:63:11:ec:b7:

    f4:43:e1:6d:59:ad:18:47:a0:93:58:dc:e6:c7:b6:91:c0:67:

    10:ce

  2. Now we will sign the certificate request:

    [root@localhost certificatesTest]# ./misc/CA -sign

    The equivalent openssl command is: openssl ca -policy policy_anything -out newcert.pem -infiles newreq.pem

    Using configuration from /home/raistlin/certificatesTest/openssl.cnf

    Enter pass phrase for ./CA/private/cakey.pem:<CA’s passphrase>

    Check that the request matches the signature

    Signature ok

    Certificate Details: Serial Number: 1 (0×1)

    Validity Not Before: Dec 13 16:08:34 2005 GMT Not After : Dec 13 16:08:34 2006 GMT

    Subject: countryName = ES stateOrProvinceName = MADRID localityName = MADRID organizationName = Sabre-Wulf organizationalUnitName = OUN commonName = localhost emailAddress = raistlin@sabre-wulf.tk

    X509v3 extensions: X509v3 Basic

    Constraints: CA:FALSE

    Netscape Comment: OpenSSL Generated Certificate

    X509v3 Subject Key Identifier: 62:A9:DE:51:89:16:9A:5A:3A:66:EE:BF:99:FE:74:71:96:11:91:19

    X509v3 Authority Key Identifier: keyid:6B:B1:49:62:2C:3B:37:2B:FF:C1:71:BC:58:32:1F:43:13:DF:D6:23 DirName:/C=ES/ST=MADRID/L=MADRID/O=Sabre-Wulf/OU=OUN/CN=TestCA/emailAddress=raistlin@sabre-wulf.tk serial:9D:43:56:A9:19:05:9A:59

    Certificate is to be certified until Dec 13 16:08:34 2006 GMT (365 days)

    Sign the certificate? [y/n]:y

    1 out of 1 certificate requests certified, commit? [y/n]y

    Write out database with 1 new entries Data Base Updated Certificate: Data: Version: 3 (0×2)

    Serial Number: 1 (0×1) Signature Algorithm: md5WithRSAEncryption

    Issuer: C=ES, ST=MADRID, L=MADRID, O=Sabre-Wulf, OU=OUN, CN=TestCA/emailAddress=raistlin@sabre-wulf.tk Validity Not Before: Dec 13 16:08:34 2005 GMT Not After : Dec 13 16:08:34 2006 GMT Subject: C=ES, ST=MADRID, L=MADRID, O=Sabre-Wulf, OU=OUN, CN=localhost/emailAddress=raistlin@sabre-wulf.tk

    Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:c5:fe:a5:1a:cf:df:91:d1:95:36:ee:07:24:c5: da:25:2b:61:76:57:48:df:4a:c6:3e:5d:3f:49:46: 4e:04:23:62:35:d7:26:30:40:ad:1f:46:17:d6:25: f4:e9:b1:d8:44:0e:ef:84:93:a2:b6:ac:cc:b4:54: 86:ca:1a:f3:67:9d:20:ff:37:d1:b2:9e:a4:7e:c4: a7:ef:39:10:d4:11:96:32:f4:7f:07:fc:3a:11:0c: 8e:4c:65:1f:49:21:5f:f1:87:4d:3b:54:c8:49:90: 97:f4:b7:8d:e8:36:9a:5c:38:cb:16:4e:5a:60:b6:

    87:31:43:11:27:2c:a0:26:4d

    Exponent: 65537 (0×10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 62:A9:DE:51:89:16:9A:5A:3A:66:EE:BF:99:FE:74:71:96:11:91:19 X509v3 Authority Key Identifier: keyid:6B:B1:49:62:2C:3B:37:2B:FF:C1:71:BC:58:32:1F:43:13:DF:D6:23 DirName:/C=ES/ST=MADRID/L=MADRID/O=Sabre-Wulf/OU=OUN/CN=TestCA/emailAddress=raistlin@sabre-wulf.tk serial:9D:43:56:A9:19:05:9A:59 Signature Algorithm: md5WithRSAEncryption ca:a4:f0:5f:1f:ef:35:9f:05:68:81:5d:92:86:5c:4e:06:6c: f2:55:6e:41:6a:4b:f8:3e:a0:2c:b1:28:67:3b:e1:6e:f5:c3: c0:22:bb:9d:9e:68:a3:5f:f9:c9:65:06:a2:a3:44:9a:46:00: 59:37:33:a6:b6:54:8c:0a:9f:1a:0d:fd:91:05:17:1d:94:1c: ae:a7:d4:64:73:ed:1f:5b:f4:0b:32:f1:d7:87:81:e0:11:d0: 99:17:fe:b0:d2:f7:f0:28:eb:a5:65:9a:ad:f2:2c:69:bf:b5: 21:d8:d6:f1:53:d6:39:2c:73:9c:a2:66:3b:bf:33:1a:a4:64: 57:0b —–BEGIN CERTIFICATE—–

    MIID5TCCA06gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBnDELMAkGA1UEBhMCRVMx

    DzANBgNVBAgTBk1BRFJJRDEPMA0GA1UEBxMGTUFEUklEMREwDwYDVQQKEwhFUklD

    U1NPTjEMMAoGA1UECxMDVFNLMQ8wDQYDVQQDEwZUZXN0Q0ExOTA3BgkqhkiG9w0B

    CQEWKmpvc2UubWFudWVsLnhtLm1vbGluYS5wYXNjdWFsQGVyaWNzc29uLmNvbTAe

    Fw0wNTEyMTMxNjA4MzRaFw0wNjEyMTMxNjA4MzRaMIGfMQswCQYDVQQGEwJFUzEP

    MA0GA1UECBMGTUFEUklEMQ8wDQYDVQQHEwZNQURSSUQxETAPBgNVBAoTCEVSSUNT

    U09OMQwwCgYDVQQLEwNUU0sxEjAQBgNVBAMTCWxvY2FsaG9zdDE5MDcGCSqGSIb3

    DQEJARYqam9zZS5tYW51ZWwueG0ubW9saW5hLnBhc2N1YWxAZXJpY3Nzb24uY29t

    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDF/qUaz9+R0ZU27gckxdolK2F2

    V0jfSsY+XT9JRk4EI2I11yYwQK0fRhfWJfTpsdhEDu+Ek6K2rMy0VIbKGvNnnSD/

    N9GynqR+xKfvORDUEZYy9H8H/DoRDI5MZR9JIV/xh007VMhJkJf0t43oNppcOMsW

    TlpgtocxQxEnLKAmTQIDAQABo4IBMDCCASwwCQYDVR0TBAIwADAsBglghkgBhvhC

    AQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFGKp

    3lGJFppaOmbuv5n+dHGWEZEZMIHRBgNVHSMEgckwgcaAFGuxSWIsOzcr/8FxvFgy

    H0MT39YjoYGipIGfMIGcMQswCQYDVQQGEwJFUzEPMA0GA1UECBMGTUFEUklEMQ8w

    DQYDVQQHEwZNQURSSUQxETAPBgNVBAoTCEVSSUNTU09OMQwwCgYDVQQLEwNUU0sx

    DzANBgNVBAMTBlRlc3RDQTE5MDcGCSqGSIb3DQEJARYqam9zZS5tYW51ZWwueG0u

    bW9saW5hLnBhc2N1YWxAZXJpY3Nzb24uY29tggkAnUNWqRkFmlkwDQYJKoZIhvcN

    AQEEBQADgYEAyqTwXx/vNZ8FaIFdkoZcTgZs8lVuQWpL+D6gLLEoZzvhbvXDwCK7

    nZ5oo1/5yWUGoqNEmkYAWTczprZUjAqfGg39kQUXHZQcrqfUZHPtH1v0CzLx14eB

    4BHQmRf+sNL38CjrpWWarfIsab+1IdjW8VPWOSxznKJmO78zGqRkVws=

    —–END CERTIFICATE—–

    Signed certificate is in newcert.pem

    newcert.pem looks like this:

    [root@localhost certificatesTest]# cat newcert.pem

    Certificate: Data: Version: 3 (0×2) Serial Number: 1 (0×1) Signature Algorithm: md5WithRSAEncryption Issuer: C=ES, ST=MADRID, L=MADRID, O=Sabre-Wulf, OU=OUN, CN=TestCA/emailAddress=raistlin@sabre-wulf.tk Validity Not Before: Dec 13 16:08:34 2005 GMT Not After : Dec 13 16:08:34 2006 GMT Subject: C=ES, ST=MADRID, L=MADRID, O=Sabre-Wulf, OU=OUN, CN=localhost/emailAddress=raistlin@sabre-wulf.tk Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit):

    00:c5:fe:a5:1a:cf:df:91:d1:95:36:ee:07:24:c5:

    da:25:2b:61:76:57:48:df:4a:c6:3e:5d:3f:49:46:

    4e:04:23:62:35:d7:26:30:40:ad:1f:46:17:d6:25:

    f4:e9:b1:d8:44:0e:ef:84:93:a2:b6:ac:cc:b4:54:

    86:ca:1a:f3:67:9d:20:ff:37:d1:b2:9e:a4:7e:c4:

    a7:ef:39:10:d4:11:96:32:f4:7f:07:fc:3a:11:0c:

    8e:4c:65:1f:49:21:5f:f1:87:4d:3b:54:c8:49:90:

    97:f4:b7:8d:e8:36:9a:5c:38:cb:16:4e:5a:60:b6:

    87:31:43:11:27:2c:a0:26:4d

    Exponent: 65537 (0×10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape

    Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 62:A9:DE:51:89:16:9A:5A:3A:66:EE:BF:99:FE:74:71:96:11:91:19 X509v3 Authority Key Identifier: keyid:6B:B1:49:62:2C:3B:37:2B:FF:C1:71:BC:58:32:1F:43:13:DF:D6:23 DirName:/C=ES/ST=MADRID/L=MADRID/O=Sabre-Wulf/OU=OUN/CN=TestCA/emailAddress=raistlin@sabre-wulf.tk serial:9D:43:56:A9:19:05:9A:59

    Signature Algorithm: md5WithRSAEncryption

    ca:a4:f0:5f:1f:ef:35:9f:05:68:81:5d:92:86:5c:4e:06:6cTha:

    f2:55:6e:41:6a:4b:f8:3e:a0:2c:b1:28:67:3b:e1:6e:f5:c3:

    c0:22:bb:9d:9e:68:a3:5f:f9:c9:65:06:a2:a3:44:9a:46:00:

    59:37:33:a6:b6:54:8c:0a:9f:1a:0d:fd:91:05:17:1d:94:1c:

    ae:a7:d4:64:73:ed:1f:5b:f4:0b:32:f1:d7:87:81:e0:11:d0:

    99:17:fe:b0:d2:f7:f0:28:eb:a5:65:9a:ad:f2:2c:69:bf:b5:

    21:d8:d6:f1:53:d6:39:2c:73:9c:a2:66:3b:bf:33:1a:a4:64:

    57:0b

    —–BEGIN CERTIFICATE—–

    MIID5TCCA06gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBnDELMAkGA1UEBhMCRVMx

    DzANBgNVBAgTBk1BRFJJRDEPMA0GA1UEBxMGTUFEUklEMREwDwYDVQQKEwhFUklD

    U1NPTjEMMAoGA1UECxMDVFNLMQ8wDQYDVQQDEwZUZXN0Q0ExOTA3BgkqhkiG9w0B

    CQEWKmpvc2UubWFudWVsLnhtLm1vbGluYS5wYXNjdWFsQGVyaWNzc29uLmNvbTAe

    Fw0wNTEyMTMxNjA4MzRaFw0wNjEyMTMxNjA4MzRaMIGfMQswCQYDVQQGEwJFUzEP

    MA0GA1UECBMGTUFEUklEMQ8wDQYDVQQHEwZNQURSSUQxETAPBgNVBAoTCEVSSUNT

    U09OMQwwCgYDVQQLEwNUU0sxEjAQBgNVBAMTCWxvY2FsaG9zdDE5MDcGCSqGSIb3

    DQEJARYqam9zZS5tYW51ZWwueG0ubW9saW5hLnBhc2N1YWxAZXJpY3Nzb24uY29t

    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDF/qUaz9+R0ZU27gckxdolK2F2

    V0jfSsY+XT9JRk4EI2I11yYwQK0fRhfWJfTpsdhEDu+Ek6K2rMy0VIbKGvNnnSD/

    N9GynqR+xKfvORDUEZYy9H8H/DoRDI5MZR9JIV/xh007VMhJkJf0t43oNppcOMsW

    TlpgtocxQxEnLKAmTQIDAQABo4IBMDCCASwwCQYDVR0TBAIwADAsBglghkgBhvhC

    AQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFGKp

    3lGJFppaOmbuv5n+dHGWEZEZMIHRBgNVHSMEgckwgcaAFGuxSWIsOzcr/8FxvFgy

    H0MT39YjoYGipIGfMIGcMQswCQYDVQQGEwJFUzEPMA0GA1UECBMGTUFEUklEMQ8w

    DQYDVQQHEwZNQURSSUQxETAPBgNVBAoTCEVSSUNTU09OMQwwCgYDVQQLEwNUU0sx

    DzANBgNVBAMTBlRlc3RDQTE5MDcGCSqGSIb3DQEJARYqam9zZS5tYW51ZWwueG0u

    bW9saW5hLnBhc2N1YWxAZXJpY3Nzb24uY29tggkAnUNWqRkFmlkwDQYJKoZIhvcN

    AQEEBQADgYEAyqTwXx/vNZ8FaIFdkoZcTgZs8lVuQWpL+D6gLLEoZzvhbvXDwCK7

    nZ5oo1/5yWUGoqNEmkYAWTczprZUjAqfGg39kQUXHZQcrqfUZHPtH1v0CzLx14eB

    4BHQmRf+sNL38CjrpWWarfIsab+1IdjW8VPWOSxznKJmO78zGqRkVws=

    —–END CERTIFICATE—–

  3. Under certain circumstances, e.g., where your certificate and private key are to be used in an unattended SSL server, you may wish to not encrypt the private key, i.e. Leave the key in the clear. This decision should be governed by your site’s security policy and threat model.

    [root@localhost certificatesTest]# openssl rsa < newreq.pem > newkey.pem Enter pass phrase: writing RSA key

    newkey.pem looks like this:

    [root@localhost certificatesTest]# cat newkey.pem

    —–BEGIN RSA PRIVATE KEY—–

    MIICXgIBAAKBgQDF/qUaz9+R0ZU27gckxdolK2F2V0jfSsY+XT9JRk4EI2I11yYw

    QK0fRhfWJfTpsdhEDu+Ek6K2rMy0VIbKGvNnnSD/N9GynqR+xKfvORDUEZYy9H8H

    /DoRDI5MZR9JIV/xh007VMhJkJf0t43oNppcOMsWTlpgtocxQxEnLKAmTQIDAQAB

    AoGAHdSZ54o+MugSxS3joaS1kzgP/RZ1gj7v02GVMWMIShNSrq31sPttmfKjkL4z

    QiprXQWrDJx5vXAXf2vkyvp4hXYNYji3VN9k2glZQXDkHeyTNJfvQZT4Ugl/i+0m

    qrW+TjBglFK/LFY8meSE4ntSxhYZ0UlM8mG1g/UF7aVwA3kCQQDiyH+WZ7yeGE99

    Xew+UOhIehqBCkwcRj5/Uw5jt5k0GQl5KLOgPZAj5X+aOrERvVI8OSzb9Ut+rKIE

    eJK/3CxDAkEA34CthKWaW8PJRxmcq0UcdTvMqefpp8w7dKnphK6tlTQjJn5s92TX

    4Lh4F872og6FvOWD8NvwYqKrmCZUWb6CLwJBAJPq5p05iGMtxBsnOcHjj75GNidY

    ihAfGQB/MfGEfR7n/a/TBmZMAUoIlNQJ2BiT/aFeQY4uTlGPVBXKdx1BBHUCQQDP

    TbgkB8JDiTbBBuWFCmZZ6qxrj5rus4UWMZ9SHP8OHDzaMHt7gAKoAhIJ60Jhj9zG

    F5AosKenpUBJsIuebhCrAkEAs/qh1C+Ts0957+Roczva9vjsJ5d/qZWN0kzonPOJ

    TWdknQQ/ty6F9cIcgVET7JfKnSUVCiT8Kw1Iz+jO/kP3zw==

    —–END RSA PRIVATE KEY—–

That’s it! The certificate, newcert.pem, and the private key newreq.pem (encrypted) or newkey.pem (unencrypted) are now ready to be used. It’s very convenient to rename the files to more descriptive names.

It’s important to keep the CA certificate (CA/cacert.pem) handy for use when developing and deploying SSL or S/MIME applications.

4. Exporting to PKCS12 or creating a JKS keystore.

Tomcat (the most used servlet container) currently operates only on JKS or PKCS12 format keystores. The JKS format is the format created by the keytool command-line utility included in the JDK. The PCKS12 format is an Internet standard and can be manipulated via OpenSSL.

Note however that support for PKCS12 has some limitations in the JDK.

  • To import an existing certificate signed by our own CA into a PKCS12 keystore using OpenSSL we will execute this command:

    [root@localhost certs]# openssl pkcs12 -export -in newcert.pem -inkey newkey.pem -out mycert.p12 -name tomcat -CAfile ../CA/cacert.pem -caname root -chain

    Enter Export Password:

    Verifying – Enter Export Password:

    We can also use the encrypted private key, its in the file newreq.pem, if we procced this way we will be asked for the security password that protects the private key:

    [root@localhost certs]# openssl pkcs12 -export -in newcert.pem -inkey newreq.pem -out mycert.p12 -name tomcat -CAfile ../CA/cacert.pem -caname root -chain

    Enter pass phrase for newreq.pem:

    Enter Export Password:

    Verifying – Enter Export Password:

  • If instead we want to create a keystore from scratch containing a single self signed certificate we can use the keytool issued with the JDK:

    [root@localhost certs]# $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA -keystore ./keystore

    Enter keystore password: josema

    What is your first and last name? [Unknown]: Jose Manuel Molina

    What is the name of your organizational unit? [Unknown]: OUN

    What is the name of your organization? [Unknown]: Sabre-Wulf

    What is the name of your City or Locality? [Unknown]: Madrid

    What is the name of your State or Province? [Unknown]: Madrid

    What is the two-letter country code for this unit? [Unknown]: ES

    Is CN=Jose Manuel Molina, OU=OUN, O=Sabre-Wulf, L=Madrid, ST=Madrid, C=ES correct? [no]: yes

    Enter key password for <tomcat> (RETURN if same as keystore password): changeit

    If we omit the “-keystore” parameter a file named “.keystore” will be created in the home dir or the user that has launched the command.

5. Configuring Tomcat

Now we are going to configure one secure socket in the $CATALINA_HOME/conf/server.xml file, where $CATALINA_HOME represents the directory into which you installed Tomcat 5. An example <Connector> element for an SSL connector is included in the default server.xml file installed with Tomcat. It will look something like this:

<– Define a SSL Coyote HTTP/1.1 Connector on port 8443 –>

<!– <Connector port=”8443″ minProcessors=”5″ maxProcessors=”75″

enableLookups=”true” disableUploadTimeout=”true” acceptCount=”100″

debug=”0″ scheme=”https” secure=”true”; clientAuth=”false” sslProtocol=”TLS”/> –>

This is the commented example that comes in the server.xml file provided with tomcat.

We will take care in the configuration of the following parameters, for more detailed information refer to the tomcat documentation (http://tomcat.apache.org).

  • clientAuth: Set this value to true if you want Tomcat to require all SSL clients to present a client Certificate in order to use this socket. Set this value to want if you want Tomcat to request a client Certificate, but not fail if one isn’t presented.

    (Note that I tested with want and my browser was not asked to present a certificate, hence the Servlet failed).

  • keystoreFile: Add this attribute if the keystore file you created is not in the default place that Tomcat expects (a file named .keystore in the user home directory under which Tomcat is running). You can specify an absolute pathname, or a relative pathname that is resolved against the $CATALINA_BASE environment variable.
  • keystorePass: Add this element if you used a different keystore (and Certificate) password than the one Tomcat expects (changeit).
  • keystoreType:Add this element if using a PKCS12 keystore. The valid values are JKS and PKCS12.
  • truststoreFile: The TrustStore file to use to validate client certificates.
  • trustStorePass: The password to access the TrustStore. This defaults to the value of keystorePass.
  • truststoreType:Add this element if your are using a different format for the TrustStore then you are using for the KeyStore. The valid values are JKS and PKCS12.

I copy below the <Connector> item I configured in my server.xml file:

<Connector port=”8443″ maxHttpHeaderSize=”8192″ maxThreads=”150″ minSpareThreads=”25″ maxSpareThreads=”75″ enableLookups=”false” disableUploadTimeout=”true” acceptCount=”100″ debug=”0″ scheme=”https” secure=”true” clientAuth=”true” sslProtocol=”TLS” keystoreFile=”/home/raistlin/Proyectos/TomcatClientAuth/webapp/certs/Sabre-Wulf.jks” truststoreFile=”/home/raistlin/certificatesTest/certs/mycert.p12″ truststorePass=”josema” truststoreType=”PKCS12″ />

6. Installing a certificate from a CA

To obtain and install a certificate from a CA we don’t own, in addition to the previous section we must should perform the following steps.

In order to obtain a certificate from the CA of your choice you have to create a so called Certificate Signing Request (CSR)

  1. Create a local Certificate (as described in section 3):

    [root@localhost certs]# $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA -keystore ./keystore

    Note that in some cases we will need to enter the website domain in the “first and lastname” in order to obtain a working certificate.

  2. The CSR is then created with:

    [root@localhost certs]# $JAVA_HOME/bin/keytool -certreq -keyalg RSA -alias tomcat -file certreq.csr -keystore <keystore_filename>

Now we have a file called certreq.csr that we can submit to the CA, in return we will get a certificate.

To import the certificate into the keystore we’ll have to import a Chain Certificate or Root Certificate into our keystore, then we’ll import the certificate.

  1. Download a Chain Certificate from the CA that generated your Certificate.
  2. Import the Chain Certificate into the keystore:

    keytool -import -alias root -keystore <keystore_filename> -trustcacerts -file <chain_cert_filename>

  3. Finally we import our certificate:

    keytool -import -alias tomcat -keystore <keystore_filename> -trustcacerts -file <cert_filename>

7. Using Client-Certificate Authentication

Client-certificate authentication is a more secure method of authentication than either basic or form-based authentication. It uses HTTP over SSL, in which the server and, optionally, the client authenticate one another using public key certificates (commonly known as PKI authentication).

SSL provides data encryption, server authentication, message integrity and optional client authentication for a TCP/IP connection.

Here is an example Servlet that retrieves the information contained in the certificate.

package com.Sabre-Wulf.servlets;

/** * */

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public class PruebaX509 extends HttpServlet

{

@Override

protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException

{

// TODO Auto-generated method stub

this.doPost(arg0, arg1);

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException

{

java.security.cert.X509Certificate[] certs = (java.security.cert.X509Certificate[]) request.getAttribute(“javax.servlet.request.X509Certificate”);

if (certs != null)

{

for (int i=0; i < certs.length ; i++) {

if(certs[i]!=null) {

System.out.println(“Certificate n. ” + i);

System.out.println(“Subject: ” + certs[i].getSubjectX500Principal().getName()); System.out.println(“Issuer: ” + certs[i].getIssuerX500Principal().getName());

System.out.println(“SerialNumber:” + certs[i].getSerialNumber().toString()); } } }else{ System.out.println(“No certicates on request.”);

}

}

This Servlet shows in the console the information contained in the certificate the user agent has authenticated with to the application servlet.

8. Conclusion

We have performed the basic steps in the creation of a CA and certificates using the tools that come with OpenSSL. We did not cover advanced topics such as constraining a certificate to be SSL-only or S/MIME-only.

We have also configured tomcat to present a certificate itself and request a certificate to the user for authentication, in this example we have covered a mutual authentication use case.

Right now I’m having some problems with The browser Firefox, when I try to access the Client Certificate Protected site I get this message:

Your certificate contains the same serial number as another certificate issued by the certificate authority.

Please get a new certificate containing a unique serial number

This does not happen if you use a browser like Opera or Explorer, I’ve seen solutions like:

  • Uncheck SSL3.0, TLS1.0 under Edit > Preferences > Security in the FireFox browser.

    This solution was not applicable, TLS 1.0 and SSL3.0 deactivation make it impossible to communicate with Tomcat.

  • Generate a random serial number.

    This didn’t worked for me either, I had some problems with the private key awhem importing the certificate into a keystore, I have to say that I only tried one time and didn’t spend any time solving this.

I have evetually resolved this problem, I performed the full proccess again, following this same guide and now Firefox does not complain about the duplciity of certificates with the same serial, I guess that this was caused by some strange CA mix in the CA’s imported in the Firefox security manager. Anyway I now get a new error:

Could not establish an encrypted connection because your certificate was rejected by localhost. Error Code: -12271.

Again this is very strange, tomcat has the client certificates correctly configured, it’s own certificate correctly configured and again all goes fine if you use Opera.

9. Glossary

  • CA: Certificate Authority
  • SSL: Secure Socket Layer
  • RSA stands for Rivest, Shamir and Adleman (Ronald Rivest, Adi Shamir, and Leonard Adleman), the creators of the public-key encryption and authentication algorithm.
  • JKS: Java KeyStore
  • PKCS12:
  • JDK: Java Development Kit
  • CSR: Certificate Signing Request.
  • OTP: One Time Password.