Keytool SubjectAlternativeName
I'm trying to get the certificates just right for our Jira/Confluence deployments in house. People access them differently, either from the hostname or the FQDN. I'm using Java 7's keytool so I have access to the server alternate name functionality:
-ext san=dns:jira
...and I hand it...
jira.example.com
...as the CN when generating the certificate. I then generate a signing request, hand the CSR off to our Win2k8r2 PKI for a certreq
to get the key signed and import the key back into the keystore.
Now when I have it setup as I've said above my browsers (Chrome, Firefox, Safari) seem to think the jira
is the only valid name even though when I inspect the certificate the CN shows the FQDN.
If I drop the ext
it will use the CN which is the FQDN.
When I have multiple ext
statements it just uses the last one and I've tried to string multiple DNS:foo
under one ext
entries together with various punctuation.
Another angle I've run across is to setup the web server to do a 301 to the FQDN. I'm fine with this as well but I'm stuck with Tomcat so "switch to Apache/nginx" won't work for me. This seems to be the only documentation I've come across to do something like that with Tomcat but its 3 years old and it's the end of the day for me. Have they added that functionality to Tomcat6?
I realize this question is pretty old but for anyone who may find it useful I'll mention what works for me:
- use CN to enter some human friendly name like "our cool JIRA server" ;-)
- enter san like this:
-ext san=dns:jira,dns:jira.example.com
BTW, you can also add IP addresses if you like. I personaly use the following for my development computer:
keytool -certreq ... -file server.csr -keystore server.keystore ... -ext san=dns:localhost,dns:myComputerName,ip:127.0.0.1,ip:::1
NOTE: I use java8 keytool; I hope this works in java7 keytool as well but I haven't tested it
To verify the CSR has the SAN subject alternative names embedded, use the keytool to print the CSR:
keytool -printcertreq -file test.csr
If it worked, you will get something like:
#1: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
DNSName: test.example.com
DNSName: test
]
Note -- to get the two entries as above (test.example.com and test), you had to create the CSR as noted in "tomorrow's" answer as "-ext san=dns:test.example.com,dns:test".
Do not follow the misleading keytool documentation [{-ext ext}*] which indicates that zero or more "-ext" entries can be passed in on the command line:
-ext san=dns:test.example.com -ext san=dns:test
This will not work, you will only get the last extension DNS entry (san=dns:test).
Generate your multi-domain certificates with OpenSSL
and not with keytool
then convert key and certificate to a Java Keystore to use with Tomcat. The following example generates a self-signed certificate, it should be easy enough to adapt for a "real" certificate.
Generate an openssl.cnf following the guide in the link above then run these commands:
# Generates a self-signed certificate + key, omit if you already have one
openssl req -config openssl.cnf -x509 -days 3650 -newkey rsa:2048 \
-out self-signed-certificate.pem -keyout pub-sec-key.pem
# Remove passphrase from key
openssl rsa -in pub-sec-key.pem -out new.key
# Generate PKCS12 keystore
openssl pkcs12 -export -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES \
-export -in self-signed-certificate.pem -inkey new.key -name alias \
-out keystore.p12
# Convert PKCS12 to JKS
keytool -importkeystore -destkeystore keystore.jks -deststoretype JKS \
-srcstoretype PKCS12 -srckeystore keystore.p12
Pay attention to the alias value to -name
in the above example. That's the name of the certificate you have to pass to tomcat
.
For the sake of completion, I'll include how issuing a certificate with SANs may work with a Certificate Authority:
SAN = email:copy
...
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName=${ENV::SAN}
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
Run this command to generate a Key + CSR containing SANs (untested):
SAN="DNS: domain1.example.com, DNS: domain2.example.com" openssl req \
-config /path/to/openssl.conf \
-subj "/C=XX/ST=XX/L=xxx/O=My Org/OU=My OU/CN=main.example.com" \
-newkey rsa:2048 -out file.csr -keyout out.key \
-infiles /path/to/csr/file.csr
Run this command to issue a certificate:
SAN="DNS: domain1.example.com, DNS: domain2.example.com" openssl ca \
-config /path/to/openssl.conf -policy policy_anything \
-subj "/C=XX/ST=XX/L=xxx/O=My Org/OU=My OU/CN=main.example.com" \
-infiles /path/to/csr/file.csr