How to fix the java.security.cert.CertificateException: No subject alternative names present error?
I fixed the problem by disabling HTTPS checks using the approach presented here:
I put following code into the the ISomeService
class:
static {
disableSslVerification();
}
private static void disableSslVerification() {
try
{
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
Since I'm using the https://AAA.BBB.CCC.DDD:9443/ISomeService
for testing purposes only, it's a good enough solution, but do not do this in production.
Note that you can also disable SSL for "one connection at a time" ex:
// don't call disableSslVerification but use its internal code:
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
httpsConn.setHostnameVerifier(allHostsValid);
httpsConn.setSSLSocketFactory(sc.getSocketFactory());
}
Java CertificateException No subject alternative names matching IP address ... found
Your certificate should include that ip value as a subject alternative name value (of type IPAddress : key=7).
http://web.archive.org/web/20160201235032/http://www.jroller.com/hasant/entry/no_subject_alternative_names_matching
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names matching IP address
Well, if the API is hosted on an IP address, the SSL certificate has to define that IP address as Subject Alternative Name. This however won't work for services like Let's Encrypt.
I guess the main cause of the issue is that you're trying to access the API by its IP address rather than its FQDN. Changing the URL of the API to the appropriate DNS name for the IP address in your source code should yield in everything working, as long as the DNS name resolves to something related to the domain the wildcard certificate was issued for (e.g. api.myappdomain.au
).
CertificateException: No subject alternative names present
The CN (Common name) i.e. IP on certificate is different and the IP i am calling is different.
...
HTTP transport error: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present.
When a name is present in the Common Name (CN), it must also be present in the Subject Alternate Name (SAN). You have a malformed certificate (and it might have other problems). See Baseline Requirements for the Issuance and Management of Publicly-Trusted Certificates, Section 9 (pages 9 & 10):
9.2.2 Subject Common Name Field
Certificate Field: subject:commonName (OID 2.5.4.3)
Required/Optional: Deprecated (Discouraged, but not prohibited)
Contents: If present, this field MUST contain a single IP address or
Fully-Qualified Domain Name that is one of the values contained in the
Certificate’s subjectAltName extension (see Section 9.2.1).
Bruno can probably cite the relevant section from RFC 6125.
SSLHandshakeException: No subject alternative names present
Thanks,Bruno for giving me heads up on Common Name and Subject Alternative Name. As we figured out certificate was generated with CN with DNS name of network and asked for regeneration of new certificate with Subject Alternative Name entry i.e. san=ip:10.0.0.1. which is the actual solution.
But, we managed to find out a workaround with which we can able to run on development phase. Just add a static block in the class from which we are making ssl connection.
static {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
{
public boolean verify(String hostname, SSLSession session)
{
// ip address of the service URL(like.23.28.244.244)
if (hostname.equals("23.28.244.244"))
return true;
return false;
}
});
}
If you happen to be using Java 8, there is a much slicker way of achieving the same result:
static {
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> hostname.equals("127.0.0.1"));
}
Mule - java.security.cert.CertificateException: No subject alternative names present
You're sending an HTTPS request to 0.0.0.0
and the certificate you're running there doesn't list 0.0.0.0
as SAN.
You should either:
- Change the request
host
to match what is in your certificate, - Add a SAN for
0.0.0.0
in the certificate.
No subject alternative names present exception when creating web service client
You seem to be confused between "importing" and "generating" the certificate.
You openssl s_client
command doesn't generate the certificate, it retrieves the certificate in use on that server.
The keytool -import
command you use afterwards imports that certificate, as it is, into your truststore. There is no point using -ext san=ip:xxx.xx.xx.xx
there: you're not generating the certificate, you're only importing it.
If you're in control of that server, you should generate (or get a certificate from somewhere else) with an IP address SAN (since Java follows the specification strictly on this).
If you're not in control of that server, use its host name (provided that there is at least a CN matching that host name in the existing cert).
In general, it's not great to import directly a certificate obtained solely from a server like this into your trust store, since you're assuming that that particular connection wasn't tampered with.
Related Topics
Converting Between Java.Time.Localdatetime and Java.Util.Date
How to Convert a String with Unicode Encoding to a String of Letters
What Is the Best Approach for Using an Enum as a Singleton in Java
How to Change UI Depending on Combo Box Selection
Java.Util.Date Format Conversion Yyyy-Mm-Dd to Mm-Dd-Yyyy
Java: Error: Variable Might Not Have Been Initialized
Casting Object Array to Integer Array Error
Jsp - What Is Wrong with Scriptlets, and What to Use Instead
Add Jar Files to a Spark Job - Spark-Submit
How to Query Xml Using Namespaces in Java with Xpath
Java Simpledateformat("Yyyy-Mm-Dd'T'Hh:Mm:Ss'Z'") Gives Timezone as Ist
Regex to Match Only Commas Not in Parentheses
Returning Null as an Int Permitted with Ternary Operator But Not If Statement
Javafx Controller Class Not Working