Resolving SSLHandshakeException: No Subject Alternative Names Present in Java HTTPS SOAP Service Calls

Dec 03, 2025 · Programming · 12 views · 7.8

Keywords: Java | HTTPS | SOAP | SSLHandshakeException | Subject Alternative Name | HostnameVerifier

Abstract: This article provides an in-depth analysis of the SSLHandshakeException encountered when invoking HTTPS SOAP web services in Java, particularly focusing on errors caused by missing Subject Alternative Names (SAN) in certificates. It begins by explaining the root cause: when the hostname of the service URL does not match the Common Name (CN) in the certificate, Java strictly adheres to RFC 2818 specifications, requiring certificates to include SAN entries for server identity verification. The article then presents two solutions: the recommended production solution of regenerating certificates with proper SAN entries, and a temporary workaround for development phases using a custom HostnameVerifier to bypass hostname verification. Detailed code implementations are provided, including static blocks and Java 8 Lambda expressions, with complete examples. Additionally, the article discusses the differing requirements for IP addresses versus hostnames in certificate validation, emphasizing the necessity of SAN for IP address verification. By integrating the best answer and supplementary information, this guide offers comprehensive troubleshooting strategies to effectively resolve SSL handshake issues in various scenarios.

Problem Background and Exception Analysis

When invoking HTTPS SOAP web services in Java applications, developers often encounter the javax.net.ssl.SSLHandshakeException with the error message java.security.cert.CertificateException: No subject alternative names present. This exception typically occurs when the hostname of the service URL does not match the Common Name (CN) in the server certificate. Java strictly follows HTTPS specifications (RFC 2818, Section 3.1), requiring certificates to include Subject Alternative Name (SAN) entries for server identity verification; otherwise, this exception is thrown.

Root Cause and Specification Requirements

According to RFC 2818, when accessing a service using a hostname, Java first checks for SAN entries in the certificate. If SAN is absent, it falls back to CN for verification. However, when using an IP address to access a service, the certificate must include a SAN entry of type IP address, not a DNS name. This is because IP addresses have special requirements in certificate validation and cannot rely solely on CN. For example, if the service URL is https://23.28.244.244 but the certificate's CN is set to a domain name (e.g., example.com) and lacks an IP address-type SAN, Java will reject the connection and throw the aforementioned exception.

Solution One: Regenerate Certificate (Recommended for Production)

The long-term and secure solution is to regenerate the server certificate, ensuring it includes correct SAN entries. For IP address access, the certificate should contain an entry like san=ip:23.28.244.244; for hostname access, it should include san=dns:example.com. This can be achieved by specifying SAN extensions in the Certificate Signing Request (CSR) using tools like OpenSSL. For instance, add the -extensions san parameter during certificate generation. This method adheres to security best practices, avoiding potential hostname spoofing attacks.

Solution Two: Custom HostnameVerifier (Workaround for Development)

In development or testing environments where immediate certificate updates are not feasible, a custom HostnameVerifier can be used to temporarily bypass hostname verification. This should be implemented in a static block to set the global verifier upon class loading. Below is an example code demonstrating how to skip verification for a specific IP address (e.g., 23.28.244.244):

static {
    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            if (hostname.equals("23.28.244.244")) {
                return true;
            }
            return false;
        }
    });
}

In Java 8 or later, Lambda expressions can simplify the code:

static {
    HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> hostname.equals("127.0.0.1"));
}

This approach is suitable only for controlled environments, as it reduces security and may expose the application to man-in-the-middle attacks. For actual deployments, Solution One should be prioritized.

Code Integration and Considerations

In SOAP service invocation code, the custom HostnameVerifier should be placed in the class initiating HTTPS connections. For example, add the above static block to the class containing the invokeWS method from the problem. Ensure the verification logic targets only trusted hostnames or IP addresses, avoiding wildcard matches to minimize risks. Additionally, developers should note that this workaround may affect all HTTPS connections in the application, so it is advisable to remove or replace it with a formal certificate after testing.

Supplementary Discussion and Best Practices

Beyond the above solutions, developers should consider using truststores (e.g., cacerts) to manage certificates and update them regularly to reflect server changes. In microservices or cloud environments, dynamic certificate management tools (e.g., Let's Encrypt) can automate SAN entry additions. For large-scale deployments, combining log monitoring and exception handling is recommended to quickly detect SSL handshake failures. In summary, resolving SSLHandshakeException hinges on understanding Java's strict verification mechanisms and selecting the appropriate solution based on the environment: prioritize certificate updates for production and use custom verifiers temporarily for development.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.