Generating self-signed certificates for Tomcat and its client(s)

Russell Bateman
August 2022

This is a script that generates

  1. the server certificat for Tomcat and
  2. a certificate for Tomcat's client.

Here are the gen-certs.sh commands in careful, tabular-parallel form for whatever clarity that provides. Note that "changeit" is used for the key, trust store and password phrase.

You are expected to invoke thus: gen-certs.sh username

gen-certs.sh:

#!/bin/sh

    FQDN="OU=Unit,O=Organization,L=City,S=State,C=US"
USERNAME=$1

if [ -z "$USERNAME" ] ; then
  echo "You must supply username as argument"
  exit 0
fi

echo "1. Generate Tomcat's certificate..."
keytool -genkeypair -keyalg RSA -dname "CN=Tomcat,${FQDN}"      -alias tomcat                        -keystore server.jks      -storepass changeit -keypass changeit

echo "2. Generate the client's certificate..."
keytool -genkeypair -keyalg RSA -dname "CN=${USERNAME},${FQDN}" -alias ${USERNAME} -storetype pkcs12 -keystore ${USERNAME}.p12 -storepass changeit -keypass changeit

echo "3. Export the client's certificate as storetype PKCS12..."
keytool -exportcert                  -file ${USERNAME}.crt      -alias ${USERNAME} -storetype pkcs12 -keystore ${USERNAME}.p12 -storepass changeit

echo "4. Import the client's certificate as a CA into Tomcat's keystore..."
keytool -importcert -v -trustcacerts -file ${USERNAME}.crt      -alias ${USERNAME}                   -keystore server.jks      -storepass changeit                   -noprompt

echo "5. Validate the server's certificate..."
keytool -list       -v                                                                               -keystore server.jks      -storepass changeit

echo "6. Validate the client's certificate..."
$ openssl pkcs12 -info               -in ${USERNAME}.p12                                                                       -password pass:changeit -passout pass:changeit

Additional options to specify include

Sample invocation and output

Observation: the bulk of the output below comes out of keytool -list and openssl x509 -info which validate/display the resulting server.jks and ${USERNAME}.p12 artifacts.

$ gen-certs.sh russ
1. Generate Tomcat's certificate...
2. Generate the client's certificate...
3. Export the client's certificate as storetype PKCS12...
Certificate stored in file <russ.crt>
4. Import the client's certificate as a CA into Tomcat's keystore...
Certificate was added to keystore
[Storing server.jks]
5. Validate the client's certificate...
Keystore type: PKCS12
Keystore provider: SUN

Your keystore contains 2 entries

Alias name: russ
Creation date: Aug 9, 2022
Entry type: trustedCertEntry

Owner: CN=russ, OU=Unit, O=Organization, L=City, ST=State, C=US
Issuer: CN=russ, OU=Unit, O=Organization, L=City, ST=State, C=US
Serial number: 8d5bac1
Valid from: Tue Aug 09 05:07:40 MDT 2022 until: Mon Nov 07 04:07:40 MST 2022
Certificate fingerprints:
	 SHA1: AE:38:F3:AB:7C:B2:84:2F:49:18:9D:DB:8C:92:D9:B6:EA:D6:7E:E9
	 SHA256: E2:FF:7E:A7:69:0C:29:AA:58:74:B4:A9:46:20:9A:86:82:13:38:78:43:2C:0E:C3:46:18:00:45:E4:0B:71:FB
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 87 19 C3 80 FA 3A 08 C6   5F 51 26 BF 24 F9 6F 0B  .....:.._Q&.$.o.
0010: 08 78 BB 35                                        .x.5
]
]


*******************************************
*******************************************

Alias name: tomcat
Creation date: Aug 9, 2022
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Tomcat, OU=Unit, O=Organization, L=City, ST=State, C=US
Issuer: CN=Tomcat, OU=Unit, O=Organization, L=City, ST=State, C=US
Serial number: 68c12ad3
Valid from: Tue Aug 09 05:07:40 MDT 2022 until: Mon Nov 07 04:07:40 MST 2022
Certificate fingerprints:
	 SHA1: 0A:05:58:49:AA:7A:CD:76:AE:8A:E1:8B:20:D6:6B:36:41:31:AD:9A
	 SHA256: 8E:46:90:64:FF:C9:C3:B3:EA:F9:85:3A:13:32:94:4A:0F:47:E4:59:BC:96:EE:F9:46:8A:BB:27:CA:86:62:C5
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 4B 91 10 DE E1 B4 42 B4   BA 02 D3 72 29 7C 63 23  K.....B....r).c#
0010: C5 91 9C C7                                        ....
]
]


*******************************************
*******************************************

6. Validate the client's certificate...
MAC: sha1, Iteration 100000
MAC length: 20, salt length: 20
PKCS7 Data
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 10000, PRF hmacWithSHA256
Bag Attributes
    friendlyName: russ
    localKeyID: 54 69 6D 65 20 31 36 36 30 30 34 33 35 33 37 35 38 38
Key Attributes: 
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIduumSvwdXSwCAggA
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECEVx61Pe+6WCBIIEyO3MeqZyONTi
+wUIfFKYeYPTZoH3jjLwYqx51ovmhjVPmxlRCg0f0JYxtlLdsVzZ2KilmSgFLbTg
0jLyjyYBnjPg6ugRhG1saRJqCBjf9jL8jIypgvbfNzMSLh3YSEBf9+6rvnASE6qT
dAZJMXJNoQ4P21SIPeFyOZDz+JpecEtNueEGSNl8B+8Pa/g2dS1OE+7AdPPLJyPB
Vdo2wFVdmf+rQY/Kpu5t3bAeqcSTAA2ot1msRoWEo34eBZlQn+Q2gQr5KVMZDBNN
wwp18tCLRRzrcEJnVF8aRjUzQg5FLE3cE57jGyJYmWvqdFVgR20yEFgr0D3g1WT4
oXkMBsCLcr4Uu3wnsQmyiwBeqJd/jCMAeCpt+KU6Ck/dWHJvVN527qangRfywlpz
jPjN5AzaFlSKM4SdSS+6PkVGeMp8uj+VOcvaPuCd5xNTZLKXR1e6yjBfmASoeUre
LagSV2fnuLNaODGRs01gP21NqXeeyWtby1QIv7oV+T8hPIdNxKveTxh+WtkbgwCi
bHwthk0yPp6INKFZA+yGMZeJPL5+Szue2pxs5lWj5s+8+zuq1N4T3T9oEh+naV+q
raXplQw/TEMX4KTagV712cvUZhna5eBDSUegJiUd7P8k/7D03aJRnvxxdfCi/qMx
GQ9pfpfETaF9o51rFLqVvNLH5jxtK8hpTKs4yCcD6syX8vitf4zaH+lZTDhxSfT+
UmuwfGyviB3eXX6SXxq4d9EoyzTf8+dS8rieW/xmYV4ojSKNBuQo0b9iObIBSQFi
Cmy5I6qstPl9NFhSLQXuG6pRdo63ynKGq9o/2WEfSjh3lVnOHmyTUVEbUlZOfCpq
CJN5eFzgyPKT4aJanoAqv51SXt6nITC1bkGycDIC3RlWT6OEQ7nWqNAVJRFglfsL
Zz9HYi9xlX9YSGHZy/7u9mS/kzzGNp9du2KxS5jtoR/JXnL+pLMgmwyN5iE/Jrhc
KvC5Zg9vZe6vDDLX87qw7SNfp5onxfzwK/m/nuW7H18mpf4CJZ/MMPmEOBBnxtno
YxdwLsWiRnXhh9/zhOm/EO/i73txmHA8kXlcKgFyQjb14imMgN9Lbjz2XPcEYmrD
AGBratcsxAaDxS7g2BcA1744OtvZ8SamhwMv4ilh+nAeFwYg8ohFicbq2esaXa2X
LKmp9hwdR9OeXIVdZieL2RIMvDaaDWcfi0dZGlu4uwkNaHrTb+We/N/x1xYQhv+B
+y/k/ITu2/i38PWKkhWU+Q/TVeSqEg6zPScpt4P1LZqZL3qFkLUMBcqn7f+sSdS/
U6VBAPfmfLtsQtSQfnbXzXQ2PrqLFu6Gt63zGlQU8bHS4eUTIBcNkcjAOiAber3S
Xo8qFGoX7DmWWccNdUoU2K3a/7+DdQdPMu3InltSuuXnq76Q+/9P6+NGFZZEMH0W
bHlpKfSkLDa8XnYrs/BwG/YqrLBkml7cYcJO6Y4tEljKtJwQZXIL+SOBbuXJkUOR
h++0tagDTAVdhT6sDNs45AIHf2S4hqKiHdVOYWqgewgDqCrMTuYD0fRPg7afd6ws
2mCpWVnZ0o7rwR0TOAifKUQXvqsOvonHwMH2DwGtIatVNj0fzvo5t5UfjMSYkECl
WdTZTSn8aJRk7o5NmwRg5A==
-----END ENCRYPTED PRIVATE KEY-----
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 10000, PRF hmacWithSHA256
Certificate bag
Bag Attributes
    friendlyName: russ
    localKeyID: 54 69 6D 65 20 31 36 36 30 30 34 33 35 33 37 35 38 38
subject=C = US, ST = State, L = City, O = Organization, OU = Unit, CN = russ

issuer=C = US, ST = State, L = City, O = Organization, OU = Unit, CN = russ

-----BEGIN CERTIFICATE-----
MIIDYTCCAkmgAwIBAgIEFvvAdDANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJV
UzEOMAwGA1UECBMFU3RhdGUxDTALBgNVBAcTBENpdHkxFTATBgNVBAoTDE9yZ2Fu
aXphdGlvbjENMAsGA1UECxMEVW5pdDENMAsGA1UEAxMEcnVzczAeFw0yMjA4MDkx
MTEyMTdaFw0yMjExMDcxMTEyMTdaMGExCzAJBgNVBAYTAlVTMQ4wDAYDVQQIEwVT
dGF0ZTENMAsGA1UEBxMEQ2l0eTEVMBMGA1UEChMMT3JnYW5pemF0aW9uMQ0wCwYD
VQQLEwRVbml0MQ0wCwYDVQQDEwRydXNzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAo5USeJobr6cXKe3RgaoCUzrHofgj8bv8hmI2b+aW49yrlkmVQQyT
eKRVlPsCroI4JKpASwDnt6AI5T56lInXCC9ADDTcpudKvgaJF7cRiRu5zOWWDZgf
HWKi20pTn6HeMNsH7xsm3KmYubw6BjaWZ/wbE2VvRHgvuhs1wo6uUnU2zxlPqJHj
zSqSlBjo+s4XR9hcEVH9Idr7gZwhWvkjQi0PF7wZCbogMHKuRLSbiwnEPeNJ80fk
tPMIzEAFBRUZVOFIhfWWsEc4SqrTEKh3B4mQ7Upg+y0VdaX5MN1vOCbGHZMlJtfd
lVw/JcEs0mDUevBD8Ris3A2r2DuaBHKFowIDAQABoyEwHzAdBgNVHQ4EFgQUH5FQ
n8uQEgePl801xz55grBlBlgwDQYJKoZIhvcNAQELBQADggEBAIdn46vSFPd2q5SC
p0j8AAA7+R3gar7XLdC4e+0qygmlzyZImExzSoNdRhpJlicpNjSVzpeFfkrRNnz6
xEyHSsRmbvx38cUIHv9yMbGDZA0YG1nLvLet3weT0zmCuFgbtD6XQIEo4MRNLo2X
pYkP4y5ZOO/bXxfNNX83Q/9VgZ8Y2QMxRagFozZ3i05i9AccXMj7FWRFlexpFxcE
Ft/U16CUICQRaf6zreb+Szvy5NrRv1wA+G5AUpHIydJOOb8djCZlLipGu6Yv2xxy
hfV70ybo+SJfzuwCO1S+064xxXLx2dWPhsaDE28iRDidqqYde5SdcAzZMfFj46I/
J9KFcCE=
-----END CERTIFICATE-----

$ ll
-rw-rw-r--  1 russ russ   869 Aug  9 05:07 russ.crt
-rw-rw-r--  1 russ russ  2693 Aug  9 05:07 russ.p12
-rw-rw-r--  1 russ russ  3673 Aug  9 05:07 server.jks

What to do with these artifacts?

server.jks

Tomcat's keystore artifact is put somewhere in the filesystem where Tomcat can access it, e.g.: ${CATALINA_BASE}/certificates. On my server, this ends up being /opt/tomcat/certificates, which is a custom subdirectory I'm adding to Tomcat.

Tomcat is informed of this keystore by adding the following paragraph to ${CATALINA_BASE}/conf/server.xml just after (or in place of if you wish to disallow non-TLS access) <Connector port="8080" ... /> in that file. I'm doing this in Tomcat 9:

<Connector port="8443" protocol="HTTP/1.1"
        connectionTimeout="20000"
        scheme="https"
        secure="true"
        SSLEnabled="true">
    <SSLHostConfig>
        <Certificate certificateKeyAlias="tomcat"
                certificateKeystoreFile="certificates/server.jks"
                certificateKeystorePassword="changeit" />
    </SSLHostConfig>
</Connector>

${USERNAME}.p12

The username certificate, here russ.p12, can be used to authenticate the client by importing it into the browser or other client software. The reason this works is because of step 4 where the client's certificate is imported into the server's keystore. This is to force Tomcat to trust the client.

Authenticating the client is not rigidly required nor always something you want to do in your microservice architecture.

Sometimes, you want the client to vet the server to ensure that client data isn't wrongly sent to some server. In this case, you want to set the server's certificate up in a trusted store such that, if missing, the software the client uses will refuse to work. And example of this would be Apache NiFi's InvokeHTTP processor.

To accomplish this, you would...

Useful links