Fix Java No Subject Alternative Names Present with keytool

Fix Java No subject alternative names present by adding DNS and IP SAN entries with keytool -ext SAN so the certificate matches the hostname or IP clients use.

Published

Updated

Read time 9 min read

Reviewed byDeepak Prasad

Fix Java No subject alternative names present banner with certificate SAN and hostname mismatch

Your Java client, SOAP call, or HttpsURLConnection reaches the server, trust checks pass, and then the handshake dies with No subject alternative names present or No subject alternative names matching IP address … found. The certificate is not necessarily invalid — Java reports this hostname-verification failure differently from browsers, and automated Java clients usually fail immediately instead of giving you a click-through warning.

Use the table below to jump to the cause that fits your URL and certificate. Each section reproduces the failure on Ubuntu with OpenJDK 25 and shows the keytool fix. For a full walkthrough of generating a correct self-signed cert, see Self-signed certificate with localhost and IP SAN.

Tested on: Ubuntu 26.04 LTS; OpenJDK 25.0.3; kernel 7.0.0-27-generic.


Prerequisites


What the error actually means

After TLS trust succeeds, Java runs hostname verification (RFC 2818 / RFC 6125). The rules differ for DNS names and IP literals:

URL you connect to What Java checks
https://app.example.com DNS:app.example.com in SAN, or CN fallback when no SAN extension exists
https://127.0.0.1 IP:127.0.0.1 in SAN — CN is not used for IP literals
https://192.168.1.10 IP:192.168.1.10 in SAN

When the certificate has no subjectAltName extension and you connect by IP, OpenJDK 25 reports:

text
javax.net.ssl.SSLHandshakeException: (certificate_unknown) No subject alternative names present
  caused by: java.security.cert.CertificateException: No subject alternative names present

When SAN exists but lists only DNS names and you connect by IP:

text
javax.net.ssl.SSLHandshakeException: (certificate_unknown) No subject alternative names matching IP address 127.0.0.1 found
  caused by: java.security.cert.CertificateException: No subject alternative names matching IP address 127.0.0.1 found

This is not a missing CA chain (chain from reply) and not an untrusted issuer (PKIX path building failed). The certificate simply does not name the host your client used.


Quick pre-check

Compare the URL your Java code opens with what is in the keystore file and what the running endpoint actually presents.

Inspect the keystore on disk:

bash
keytool -list -v -keystore server.p12 -storetype PKCS12 -storepass PASS -alias server

Look for SubjectAlternativeName under Extensions. Export and double-check with OpenSSL:

bash
keytool -exportcert -alias server -keystore server.p12 -storetype PKCS12 \
  -storepass PASS -rfc -file server.pem

openssl x509 -in server.pem -noout -text | grep -A2 "Subject Alternative Name"

Also inspect the certificate Java actually receives from the server:

bash
openssl s_client -connect 127.0.0.1:8443 -servername localhost -showcerts </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -ext subjectAltName
text
subject=CN=localhost
issuer=CN=localhost
X509v3 Subject Alternative Name:
    DNS:localhost, IP Address:127.0.0.1

If the SAN shown here differs from the keystore you edited, the service is reading another keystore, alias, secret, ingress certificate, or load balancer certificate.

For virtual-hosted TLS endpoints, set -servername to the same DNS name used by the Java client; otherwise the server may return a default certificate.

When testing an IP URL, replace 127.0.0.1:8443 with the same IP and port your Java client uses. SNI may not apply to IP-only endpoints, but the presented certificate must still contain the matching IP: SAN.

Observation Likely problem
No SubjectAlternativeName block IP connections will fail; DNS may fall back to CN only
DNSName: localhost only https://127.0.0.1 fails — needs IP:127.0.0.1
CN=127.0.0.1 but no SAN IP URL fails because CN is ignored for IP; localhost fails because the name differs
SAN names do not include your URL host Wrong hostname in certificate
Keystore SAN differs from s_client output Service is not using the keystore you edited

Find your cause

Likely cause Clues Go to
No SAN, client uses IP https://127.0.0.1 or LAN IP in Java URL No SAN, connect by IP
DNS SAN only, client uses IP Cert has DNS:localhost; URL uses 127.0.0.1 DNS SAN only
CN is IP, no IP SAN CN=192.168.1.10 in cert; still fails on IP URL CN is IP without SAN
Wrong DNS name in SAN DNS:www.example.com but URL is api.example.com Hostname mismatch
CA-signed cert lacks SAN CSR or signing omitted -ext SAN CA-signed cert missing SAN
Docs say localhost, config uses IP Tomcat/Kafka/Spring bind or call by IP localhost vs 127.0.0.1 split
Service presents another certificate Keystore has correct SAN; openssl s_client shows old or different cert Service using another cert
Different error text Trust or chain problem Not a SAN error

No SAN extension, connecting by IP

The most common Stack Overflow and vendor KB scenario: keytool -genkeypair with only -dname "CN=localhost" and no -ext flag. Chrome and other browsers also require SAN for hostname matching; when your CA issued the cert outside keytool, add SAN with Subject Alternative Names in OpenSSL. Java services fail programmatically with this exact exception instead of a browser warning.

Generate a cert without SAN:

bash
mkdir -p ~/san-lab && cd ~/san-lab

keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -validity 365 \
  -dname "CN=localhost" -keystore no-san.p12 -storetype PKCS12 \
  -storepass changeit -keypass changeit -noprompt

Confirm SAN is absent:

bash
keytool -list -v -keystore no-san.p12 -storetype PKCS12 -storepass changeit -alias server \
  | grep -i "Subject Alternative"

No output means no SAN extension. A Java HttpsURLConnection to https://127.0.0.1:8443/ fails:

text
javax.net.ssl.SSLHandshakeException: (certificate_unknown) No subject alternative names present
  caused by: java.security.cert.CertificateException: No subject alternative names present

The same keystore may still work for https://localhost:8443/ because Java can match CN=localhost when no SAN extension exists. Do not rely on that — add explicit SAN entries.

Fix — regenerate with DNS and IP SAN:

bash
keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -validity 365 \
  -dname "CN=localhost" \
  -ext "SAN=DNS:localhost,IP:127.0.0.1" \
  -keystore with-san.p12 -storetype PKCS12 \
  -storepass changeit -keypass changeit -noprompt

Verify:

bash
keytool -list -v -keystore with-san.p12 -storetype PKCS12 -storepass changeit -alias server \
  | grep -A5 "SubjectAlternativeName"
text
SubjectAlternativeName [
  DNSName: localhost
  IPAddress: 127.0.0.1
]

After pointing Tomcat or Spring Boot at with-san.p12, both https://127.0.0.1 and https://localhost succeed under Java's default hostname verifier.


DNS SAN only, but client uses IP

Your certificate has SAN=DNS:localhost but the Java client opens https://127.0.0.1. SAN exists, so the error text changes:

text
javax.net.ssl.SSLHandshakeException: (certificate_unknown) No subject alternative names matching IP address 127.0.0.1 found
  caused by: java.security.cert.CertificateException: No subject alternative names matching IP address 127.0.0.1 found

Fix options:

  1. Preferred: Reissue the cert with -ext "SAN=DNS:localhost,IP:127.0.0.1".
  2. Workaround: Change the client URL to https://localhost when DNS SAN matches and /etc/hosts resolves it — fragile for production.

CN is an IP address without IP SAN

Putting the IP in Common Name alone does not satisfy Java for IP URLs. A cert with CN=127.0.0.1 and no -ext SAN still fails on https://127.0.0.1:

text
javax.net.ssl.SSLHandshakeException: (certificate_unknown) No subject alternative names present

Connecting to https://localhost with that cert fails differently:

text
javax.net.ssl.SSLHandshakeException: (certificate_unknown) No name matching localhost found

Fix — use an IP SAN entry, not CN alone:

bash
keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -validity 365 \
  -dname "CN=127.0.0.1" \
  -ext "SAN=IP:127.0.0.1,DNS:localhost" \
  -keystore ip-san.p12 -storetype PKCS12 -storepass changeit -noprompt

For LAN deployments, list every IP Java clients use:

bash
-ext "SAN=DNS:app.lab.local,IP:192.168.1.10,IP:10.0.0.5"

For IPv6 URLs, add the IPv6 literal as an IP: SAN entry too. Do not put IPv6 addresses under DNS:.


Service is using another certificate

If keytool -list -v shows the correct SAN but Java still fails, inspect the live endpoint with openssl s_client (see Quick pre-check). The running service may be using a different keystore, alias, Kubernetes TLS secret, ingress certificate, or load balancer certificate than the file you edited on disk.

Check:

  • Tomcat certificateKeystoreFile and certificateKeyAlias
  • Spring Boot server.ssl.key-store and server.ssl.key-alias
  • Kubernetes Secret mounted into the pod
  • Ingress or load balancer TLS configuration

In Kubernetes, the Java client validates the certificate presented by the Service, Ingress, or load balancer — not necessarily the certificate inside the backend pod. If the URL is https://10.96.x.x or an ingress IP, the certificate needs an IP: SAN for that address, or the client should use a DNS name that exists as DNS: SAN.

Restart or reload the service after replacing the certificate. Until the listener reloads, s_client keeps showing the old SAN even when the keystore file on disk is already fixed.


Hostname does not match SAN

When a certificate includes SAN entries, Java checks SAN first. A cert with SAN=DNS:www.example.com rejects https://api.example.com even if CN=api.example.com is in the subject.

Check what the client actually uses:

bash
openssl x509 -in server.pem -noout -ext subjectAltName

Reissue with every DNS name in the URL — wildcards only when your CA supports DNS:*.example.com and the hostname matches the wildcard rules.


CA-signed certificate missing SAN

Internal PKI teams sometimes sign a CSR that omitted SAN. OpenSSL does not copy extensions from the bootstrap self-signed cert by default — you must pass -ext SAN=... on keytool -certreq and ensure the CA preserves SAN at signing time.

Correct CSR flow:

bash
keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -validity 365 \
  -dname "CN=app.lab.local" \
  -ext "SAN=DNS:app.lab.local,IP:10.0.0.5" \
  -keystore server.p12 -storetype PKCS12 -storepass changeit -noprompt

keytool -certreq -alias server -keystore server.p12 -storetype PKCS12 \
  -storepass changeit -file server.csr \
  -ext "SAN=DNS:app.lab.local,IP:10.0.0.5"

After the CA returns the signed .crt, import with chain import order and confirm SAN survived:

bash
keytool -list -v -keystore server.p12 -storetype PKCS12 -storepass changeit -alias server

If SAN disappeared after CA signing, ask the CA to reissue with the SAN extension from your CSR.


localhost vs 127.0.0.1: both need SAN entries

Kafka, Elasticsearch, and Tomcat docs often say localhost while health checks hit 127.0.0.1. Java treats those as different identities.

Client URL Required SAN
https://localhost:8443 DNS:localhost
https://127.0.0.1:8443 IP:127.0.0.1
NOTE
List every hostname and IP address from your config files, Kubernetes probes, and JDBC URLs in one -ext "SAN=..." string at generation or CSR time. keytool cannot add SAN to an already issued certificate.

Quick lab reproduction

Reproduce the IP failure in a throwaway directory:

bash
cd ~/san-lab
keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -validity 365 \
  -dname "CN=localhost" -keystore no-san.p12 -storetype PKCS12 \
  -storepass changeit -noprompt

Wire no-san.p12 into a Java HTTPS listener, then call https://127.0.0.1:PORT/ from HttpsURLConnection with default hostname verification. Expect No subject alternative names present.

Safe fix:

bash
keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -validity 365 \
  -dname "CN=localhost" \
  -ext "SAN=DNS:localhost,IP:127.0.0.1" \
  -keystore fixed-san.p12 -storetype PKCS12 -storepass changeit -noprompt

Restart the service with fixed-san.p12 and retry the same IP URL.


Distinguish from other Java SSL errors

Error Meaning Guide
No subject alternative names present No SAN; IP URL This page
No subject alternative names matching IP address X found SAN lacks that IP This page
No name matching hostname found SAN/CN do not match DNS URL This page
Public keys in reply and keystore don't match Wrong CSR alias Public keys mismatch

References


Summary

No subject alternative names present means Java could not match your HTTPS URL to the certificate SAN extension — most often because you connected by IP and the cert has no IPAddress SAN. Confirm the live endpoint with openssl s_client, not only the keystore file. Regenerate or reissue with keytool -genkeypair or keytool -certreq plus -ext "SAN=DNS:hostname,IP:127.0.0.1" for every DNS name and IP literal your clients use. CN alone is not enough for IP URLs.


Frequently Asked Questions

1. What does No subject alternative names present mean in Java?

Java hostname verification failed because the server certificate has no Subject Alternative Name extension and you connected using an IP address. For HTTPS over an IP literal, RFC 2818 requires an IPAddress SAN entry. Java does not fall back to the Common Name for IP connections.

2. How do I fix No subject alternative names present with keytool?

Regenerate the certificate with keytool -genkeypair and -ext "SAN=DNS:hostname,IP:127.0.0.1" listing every DNS name and IP address clients use in the URL. For CA-signed certs, create a new CSR with -certreq -ext SAN=... and have the CA reissue the certificate.

3. Why does https://localhost work but https://127.0.0.1 fails?

When the certificate has no SAN extension, Java may still match the Common Name for DNS hostnames like localhost. IP literals require an explicit IP:127.0.0.1 entry in the SAN extension. Add both DNS:localhost and IP:127.0.0.1 to cover both URLs.

4. Can I put an IP address in the CN field instead of SAN?

No for Java clients connecting by IP. CN=192.168.1.10 without an IPAddress SAN still fails with No subject alternative names present. Use -ext "SAN=IP:192.168.1.10" or include both DNS and IP entries your clients need.

5. Is this the same as PKIX path building failed?

No. No subject alternative names present is hostname verification after the certificate is already trusted. PKIX path building failed means the JVM does not trust the issuer chain. Fix SAN on the server cert; fix truststore or CA chain for PKIX errors.

6. Can I disable hostname verification instead of fixing the certificate?

Custom HostnameVerifier or trust-all settings are development-only workarounds. Production fix is to reissue the certificate with correct DNS and IP SAN entries matching the URLs your Java clients, Tomcat, or Spring Boot apps use.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …