How to Generate Java KeyStore with Subject Alternative Name (SAN) Using Java 1.7 keytool – Complete Guide with CSR Example


3 views

Many developers encounter issues when trying to generate certificates with Subject Alternative Names (SANs) using Java 1.7's keytool utility. The key challenge is that while the -ext parameter appears to accept SAN specifications, these extensions often don't get properly included in the resulting Certificate Signing Request (CSR).

SANs are crucial in modern PKI implementations because:

  • They allow certificates to secure multiple domain names
  • They enable certificates to work with both IP addresses and hostnames
  • They're required for many modern security protocols

After extensive testing, here's the proper way to generate a keystore with SANs in Java 1.7:

keytool -genkeypair -alias myserver -keyalg RSA -keysize 2048 \
  -keystore keystore.jks -storepass changeit -keypass changeit \
  -dname "CN=primary.example.com, OU=IT, O=MyCompany, L=City, ST=State, C=US" \
  -ext SAN=dns:primary.example.com,dns:alt.example.com,ip:192.168.1.1

The solution involves several important technical details:

# 1. Use a single -ext parameter with all SAN entries comma-separated
# 2. DNS entries must be prefixed with dns:
# 3. IP entries must be prefixed with ip:
# 4. The entire SAN specification must be one continuous string

To confirm your SANs were properly included, use OpenSSL to examine the CSR:

openssl req -in myrequest.csr -noout -text

Look for the X509v3 Subject Alternative Name section in the output.

If you still face issues, consider these alternatives:

# Using OpenSSL to generate the key and CSR first:
openssl req -new -newkey rsa:2048 -nodes -keyout server.key \
  -out server.csr -subj "/CN=server.example.com" \
  -reqexts SAN -config <(cat /etc/ssl/openssl.cnf \
  <(printf "[SAN]\nsubjectAltName=DNS:server.example.com,DNS:alt.example.com"))

# Then import into Java keystore:
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial \
  -in server.csr -out server.crt -days 365
keytool -importcert -file server.crt -alias server \
  -keystore keystore.jks -storepass changeit
  • Ensure all Java versions in your environment are consistent
  • Verify the keytool version matches your Java installation
  • Check for hidden character encoding issues in the -ext parameter
  • Confirm your CA supports the SAN extensions you're requesting

For enterprise deployments:

  1. Always test certificates in staging first
  2. Document your exact keytool command parameters
  3. Consider automating certificate generation through scripts
  4. Maintain proper certificate lifecycle management

Many developers working with Java 1.7 encounter difficulties when trying to generate certificates with Subject Alternative Names (SANs) using the built-in keytool utility. The issue manifests when you specify SAN extensions during key generation, but they don't appear in the resulting Certificate Signing Request (CSR).

keytool -keystore keystore.jks -storepass changeme -keypass changeme -alias server \
-genkeypair -keysize 2048 -keyalg RSA \
-dname "CN=server.example.com, OU=Development, O=Company, L=City, S=State, C=US" \
-ext san=dns:server.example.com,ip:192.168.1.1

The keytool implementation in Java 1.7 has a known limitation where SAN extensions specified during key generation aren't properly included in the CSR. While the extensions are stored in the keystore, they're not exported when creating the CSR.

Here are three reliable methods to generate certificates with SANs that work with Java 1.7:

1. Using OpenSSL to Generate the CSR

This is often the most reliable approach:

openssl req -new -newkey rsa:2048 -nodes -keyout server.key \
-out server.csr -subj "/CN=server.example.com" \
-config <(cat /etc/ssl/openssl.cnf \
<<<"[req]\nreq_extensions = v3_req\n[v3_req]\nsubjectAltName = DNS:server.example.com,IP:192.168.1.1")

2. Creating the Certificate Directly with keytool

For self-signed certificates, you can bypass the CSR step:

keytool -genkeypair -alias server -keyalg RSA -keysize 2048 \
-keystore keystore.jks -storepass changeme -keypass changeme \
-dname "CN=server.example.com" \
-ext san=dns:server.example.com,ip:192.168.1.1 \
-validity 365

3. Post-processing with Java Code

You can use Java code to modify the certificate after generation:

import sun.security.tools.keytool.CertAndKeyGen;
import sun.security.x509.*;

KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("keystore.jks"), "changeme".toCharArray());

CertAndKeyGen keyPair = new CertAndKeyGen("RSA", "SHA256WithRSA");
keyPair.generate(2048);

X509Certificate[] chain = new X509Certificate[1];
chain[0] = keyPair.getSelfCertificate(
    new X500Name("CN=server.example.com"), (long)365*24*3600);

// Add SAN extension
GeneralNames subjectAltNames = new GeneralNames();
subjectAltNames.add(new GeneralName(new DNSName("server.example.com")));
subjectAltNames.add(new GeneralName(new IPAddressName("192.168.1.1")));

chain[0] = X509CertImpl.toImpl(chain[0]);
chain[0].set(X509CertImpl.toImpl(chain[0]).getVersion3Extension(
    "2.5.29.17", new DerValue(DerValue.tag_Sequence, 
    subjectAltNames.encode())));

ks.setKeyEntry("server", keyPair.getPrivateKey(), 
    "changeme".toCharArray(), chain);

After implementing any of these approaches, verify the SAN is properly included:

keytool -list -v -keystore keystore.jks -alias server

Look for the "X509v3 Subject Alternative Name" section in the output.

  • Java 1.8 and later versions properly handle SAN extensions in CSRs
  • For production environments, consider upgrading to newer Java versions
  • Always test certificates in a development environment first
  • Remember that self-signed certificates are typically not trusted by browsers

While the Java 1.7 keytool utility has limitations with SANs in CSRs, several workarounds exist. The OpenSSL approach is generally the most reliable for generating CSRs with SANs that can be submitted to Certificate Authorities. For internal/testing purposes, the self-signed certificate approach may be sufficient.