Skip to main content
  1. Posts/

Using Self-Signed Multi-Domain Certificates

Self-signed certificates are usually used for TLS authentication on non-production environments. We’ll discuss here how to generate proper certificate for your server.

TL;DR: Include Subject Alternative Names (SAN) extension when generating self-signed certificate. It also allows you to use the same certificate on multiple hosts.

Steps for setting up TLS authentication on JVM:

  1. Generate self-signed certificate keypair and install it in keystore on server
  2. Export generated server certificate and distribute it to clients
  3. Install server certificate to client truststore

For mutual TLS certification it also necessary to do the same steps for the client: generate client keypair, export certificate and install to server truststore.

You may use keytool from JDK to generate keypair:

keytool -genkeypair \
    -keystore server-keystore.pkcs12 \
    -deststoretype pkcs12 \
    -dname "CN=mydomain.local" \
    -keypass changeit \
    -storepass changeit \
    -keyalg RSA \
    -validity 1825 \
    -keysize 4096 \
    -alias mydomain.local

then export certificate:

keytool -export \
    -alias mydomain.local \
    -file mydomain.local.crt \
    -keystore server-keystore.pkcs12 \
    -keypass changeit \
    -storepass changeit

and import it into client’s truststore:

keytool -import \
    -alias mydomain.local \
    -file mydomain.local.crt \
    -keystore client-truststore.pkcs12 \
    -deststoretype pkcs12 \
    -keypass changeit \
    -storepass changeit \
    -noprompt

Then you can run server with command:

java -jar server.war \
    -Djavax.net.ssl.keyStore=server-keystore.pkcs12 \
    -Djavax.net.ssl.keyStorePassword=changeit

java -jar client.jar \    
    -Djavax.net.ssl.trustStore=client-truststore.pkcs12 \ 
    -Djavax.net.ssl.trustStorePassword=changeit

Unfortunately, you may encounter exception with following message:

“Certificate for <mydomain.local> doesn’t match any of the subject alternative names: []”

To understand the cause we need to look at RFC 2818 (the HTTPS specification):

If the hostname is available, the client MUST check it against the server’s identity as presented in the server’s Certificate message, in order to prevent man-in-the-middle attacks. … If a subjectAltName extension of type dNSName is present, that MUST be used as the identity. Otherwise, the (most specific) Common Name field in the Subject field of the certificate MUST be used. Although the use of the Common Name is existing practice, it is deprecated and Certification Authorities are encouraged to use the dNSName instead.

So, hostname MUST either match to Common Name (CN) or, preferably, it must be included in “Subject Alternative Names” (SAN) entries of the certificate.

The expected result is that the SAN Entries to include the CN as well like below where CN=domain.local also in SAN DNSName=domain.local.

The advantage of using Subject Alternative Names in certificate is that it is possible to use same certificate for different hosts, e.g. for localhost, dev- and test- servers.

Let’s check our generated certificate:

keytool -list -v \
    -alias mydomain.local \
    -file mydomain.local.crt \
    -keystore server-keystore.pkcs12 \
    -keypass changeit \
    -storepass changeit

…will result:

Alias name: mydomain.local
Creation date: Dec 31, 2017
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=mydomain.local
Issuer: CN=mydomain.local
Serial number: 3abb318a
Valid from: Sun Dec 31 10:06:30 CET 2017 until: Fri Dec 30 10:06:30 CET 2022
Certificate fingerprints:
         MD5:  22:99:E6:C0:87:C0:A6:54:84:81:E6:AC:AD:78:A8:B5
         SHA1: 7C:A7:D9:BC:42:E2:C9:83:18:46:7B:E5:BB:E7:23:F9:A5:D1:E1:C1
         SHA256: D5:74:EA:8D:AC:31:C8:54:27:12:C4:8C:4D:73:33:AE:8F:58:E3:E7:37:74:D4:79:76:D3:FD:84:23:B4:54:86
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3

Extensions: 

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: D3 C3 EF AA 09 6B 92 EF   24 A4 79 C5 46 25 33 AF  .....k..$.y.F%3.
0010: D2 FF 6D 8F                                        ..m.
]
]

We can see that Subject Alternative Names (SAN) extension is not present in the certificate. We need to generate certificate again:

keytool -genkeypair \
    -keystore server-keystore.pkcs12 \
    -deststoretype pkcs12 \
    -dname "CN=mydomain.local" \
    -keypass changeit \
    -storepass changeit \
    -keyalg RSA \
    -validity 1825 \
    -keysize 4096 \
    -alias mydomain.local \
    -ext SAN=dns:mydomain.local,dns:mydomain.dev,dns:mydomain.test,dns:localhost

Note the SAN extension containing Common Name as well as extra host names where this certificate could be used.

Now examine our new certificate:

$ keytool -list -v \
>         -alias mydomain.local \
>         -file mydomain.local.crt \
>         -keystore server-keystore.pkcs12 \
>         -keypass changeit \
>         -storepass changeit
Alias name: mydomain.local
Creation date: Dec 31, 2017
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=mydomain.local
Issuer: CN=mydomain.local
Serial number: 7a292cb6
Valid from: Sun Dec 31 12:01:18 CET 2017 until: Fri Dec 30 12:01:18 CET 2022
Certificate fingerprints:
         MD5:  C5:DE:DE:62:88:69:B8:27:39:F4:04:02:8B:95:F5:AA
         SHA1: 56:C4:BF:D9:5A:7D:37:F8:58:A4:0C:21:3C:95:92:64:70:88:DD:98
         SHA256: 9F:00:DE:AD:0E:67:42:CE:68:2D:29:03:D6:EE:CF:2B:9F:84:AF:FE:4C:A8:9D:C6:BF:A4:BD:CE:B1:4D:24:E2
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3

Extensions: 

#1: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  DNSName: mydomain.local
  DNSName: mydomain.dev
  DNSName: mydomain.test
  DNSName: localhost
]

#2: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 10 18 0A A4 96 E1 0F 14   47 DA 2D 60 A7 B0 1B 77  ........G.-`...w
0010: 12 23 07 42                                        .#.B
]
]

Now you see that SubjectAlternativeName extension is present. This certificate can be used on following hosts:

  • mydomain.local
  • mydomain.dev
  • mydomain.test
  • localhost

Conclusion #

Always generate self-signed certificate with Subject Alternative Names section. You will be ab eto use this certificate on multiple hosts as well.

Links #