When working with Java Keytool to generate certificates for internal Jira/Confluence deployments, many developers encounter a puzzling behavior: even when specifying both a short hostname (like 'jira') in the SubjectAlternativeName (SAN) extension and a fully qualified domain name (like 'jira.example.com') as the Common Name (CN), browsers only validate the SAN entry.
keytool -genkeypair \
-alias jira \
-keyalg RSA \
-keysize 2048 \
-keystore keystore.jks \
-dname "CN=jira.example.com, OU=IT, O=Example Inc, L=New York, S=NY, C=US" \
-ext san=dns:jira \
-validity 365
The correct syntax for including multiple SAN entries in Java Keytool is often misunderstood. The proper format uses commas to separate values:
keytool -genkeypair \
-ext "san=dns:jira,dns:jira.example.com,dns:internal-jira,dns:jira.local"
This approach ensures the certificate will be valid for all specified names. The order doesn't matter - all specified names will be equally valid.
Modern browsers follow RFC 2818 (HTTP Over TLS) which states that when a SAN extension is present, the CN should be ignored for name validation. This explains why your browsers only accept the SAN entry despite having a proper CN.
When submitting the CSR to Windows PKI, you'll need to ensure your INF file properly captures all SAN entries:
[NewRequest]
Subject = "CN=jira.example.com, OU=IT, O=Example Inc, L=New York, S=NY, C=US"
Exportable = TRUE
KeyLength = 2048
KeySpec = 1
KeyUsage = 0xA0
MachineKeySet = True
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = PKCS10
[Extensions]
2.5.29.17 = "{text}"
_continue_ = "dns=jira&"
_continue_ = "dns=jira.example.com&"
_continue_ = "dns=internal-jira"
For Tomcat deployments, you can implement a 301 redirect in your web.xml to ensure all traffic goes to the FQDN:
<web-app>
<security-constraint>
<web-resource-collection>
<web-resource-name>SecureRedirect</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<security-role>
<role-name>ssl-redirect</role-name>
</security-role>
</web-app>
The recommended approach is to:
- Include both short name and FQDN in SAN
- Generate with proper keytool command
- Verify with openssl before deployment
openssl x509 -in certificate.crt -text -noout | grep -A 1 "Subject Alternative Name"
This will show you all valid names for the certificate.
When working with Java keytool (specifically Java 7+ versions that support SAN extensions), many administrators encounter a common problem: browsers only validate the first SAN entry while ignoring the Common Name (CN). This becomes particularly problematic when users access services through multiple hostnames (shortname vs FQDN).
The proper way to specify multiple DNS names in a single -ext parameter is:
keytool -genkeypair \
-alias jira \
-keyalg RSA \
-keysize 2048 \
-keystore keystore.jks \
-dname "CN=jira.example.com, OU=IT, O=Example Corp, L=City, ST=State, C=US" \
-ext "san=dns:jira,dns:jira.example.com,dns:internal-jira.example.net"
After generating the CSR and getting it signed by your CA, verify the SANs using:
keytool -list -v -keystore keystore.jks -alias jira
Modern browsers (Chrome, Firefox, Safari) follow RFC 6125 which states:
- If SANs exist, CN is ignored for validation
- Only the first SAN entry is considered in some implementations
For environments where you must support legacy clients that rely on CN:
<Connector port="443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
keystoreFile="/path/to/keystore.jks"
keystorePass="changeit"
clientAuth="false" sslProtocol="TLS"
server="Apache-Coyote/1.1" />
Combine this with a redirect valve in server.xml:
<Valve className="org.apache.catalina.valves.RewriteValve" />
Then create a rewrite rule in conf/Catalina/localhost/rewrite.config:
RewriteCond %{HTTP_HOST} ^jira$
RewriteRule ^(.*)$ https://jira.example.com$1 [R=301,L]
When working with Windows PKI (certreq):
- Generate the CSR with proper SANs as shown above
- Include the -ext parameter when importing the signed certificate back:
keytool -importcert \
-keystore keystore.jks \
-alias jira \
-file signed_cert.cer \
-trustcacerts \
-ext "san=dns:jira,dns:jira.example.com"