How to fix the "java.security.cert.CertificateException: No subject alternative names present" error?
Solution 1
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());
}
Solution 2
I've the same problem and solved with this code. I put this code before the first call to my webservices.
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
return hostname.equals("localhost"); // or return true
}
});
It's simple and works fine.
Here is the original source.
Solution 3
This is an old question, yet I had the same problem when moving from JDK 1.8.0_144 to jdk 1.8.0_191
We found a hint in the changelog:
we added the following additional system property, which helped in our case to solve this issue:
-Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true
Solution 4
The verification of the certificate identity is performed against what the client requests.
When your client uses https://xxx.xxx.xxx.xxx/something
(where xxx.xxx.xxx.xxx
is an IP address), the certificate identity is checked against this IP address (in theory, only using an IP SAN extension).
If your certificate has no IP SAN, but DNS SANs (or if no DNS SAN, a Common Name in the Subject DN), you can get this to work by making your client use a URL with that host name instead (or a host name for which the cert would be valid, if there are multiple possible values). For example, if you cert has a name for www.example.com
, use https://www.example.com/something
.
Of course, you'll need that host name to resolve to that IP address.
In addition, if there are any DNS SANs, the CN in the Subject DN will be ignored, so use a name that matches one of the DNS SANs in this case.
Solution 5
To import the cert:
- Extract the cert from the server, e.g.
openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
This will extract certs in PEM format. - Convert the cert into DER format as this is what keytool expects, e.g.
openssl x509 -in certs.txt -out certs.der -outform DER
- Now you want to import this cert into the system default 'cacert' file. Locate the system default 'cacerts' file for your Java installation. Take a look at How to obtain the location of cacerts of the default java installation?
- Import the certs into that cacerts file:
sudo keytool -importcert -file certs.der -keystore <path-to-cacerts>
Default cacerts password is 'changeit'.
If the cert is issued for an FQDN and you're trying to connect by IP address in your Java code, then this should probably be fixed in your code rather than messing with certificate itself. Change your code to connect by FQDN. If FQDN is not resolvable on your dev machine, simply add it to your hosts file, or configure your machine with DNS server that can resolve this FQDN.
Glory to Russia
Updated on October 11, 2021Comments
-
Glory to Russia over 2 years
I have a Java web service client, which consumes a web service via HTTPS.
import javax.xml.ws.Service; @WebServiceClient(name = "ISomeService", targetNamespace = "http://tempuri.org/", wsdlLocation = "...") public class ISomeService extends Service { public ISomeService() { super(__getWsdlLocation(), ISOMESERVICE_QNAME); }
When I connect to the service URL (
https://AAA.BBB.CCC.DDD:9443/ISomeService
), I get the exceptionjava.security.cert.CertificateException: No subject alternative names present
.To fix it, I first ran
openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
and got following content in filecerts.txt
:CONNECTED(00000003) --- Certificate chain 0 s:/CN=someSubdomain.someorganisation.com i:/CN=someSubdomain.someorganisation.com -----BEGIN CERTIFICATE----- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -----END CERTIFICATE----- --- Server certificate subject=/CN=someSubdomain.someorganisation.com issuer=/CN=someSubdomain.someorganisation.com --- No client certificate CA names sent --- SSL handshake has read 489 bytes and written 236 bytes --- New, TLSv1/SSLv3, Cipher is RC4-MD5 Server public key is 512 bit Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : RC4-MD5 Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Session-ID-ctx: Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Key-Arg : None Start Time: 1382521838 Timeout : 300 (sec) Verify return code: 21 (unable to verify the first certificate) ---
AFAIK, now I need to
- extract the part of
certs.txt
between-----BEGIN CERTIFICATE-----
and-----END CERTIFICATE-----
, - modify it so that the certificate name is equal to
AAA.BBB.CCC.DDD
and - then import the result using
keytool -importcert -file fileWithModifiedCertificate
(wherefileWithModifiedCertificate
is the result of operations 1 and 2).
Is this correct?
If so, how exactly can I make the certificate from step 1 work with IP-based adddress (
AAA.BBB.CCC.DDD
) ?Update 1 (23.10.2013 15:37 MSK): In an answer to a similar question, I read the following:
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).
What exactly does "use" mean?
- extract the part of
-
Glory to Russia over 10 yearsI can't access the service via
http://www.example.com/someservice
. Is it correct that in order for the certificate to work with IP-based address (https://AAA.BBB.CCC.DDD:9443/ISomeService
), I need set allCN
fields toAAA.BBB.CCC.DDD
(replacesomeSubdomain.someorganisation.com
byAAA.BBB.CCC.DDD
in the file above) and import the resulting certificate file? -
Bruno over 10 yearsYou can't do anything about the CN or the cert if you're not in control of the server.
-
John over 9 yearsThe approach mentioned in the link mentioned above appears to be blocked (nakov.com/blog/2009/07/16/…) . Can anyone update the link ?
-
user over 8 yearsOr you could just replace the entire body of the verify() function with
return hostname.equals("localhost");
, if that is what you want to do. Theif
is completely superfluous. -
tyoc213 over 8 yearsto access to the ip address for test purposes you can modify temporarily your
/etc/hosts
file or equivalent -
dacDave about 8 yearsThis was a simple and quick fix that got us around testing in a vendor's test environment that did not have a proper certificate. Thanks a million!
-
ThunderWiring about 8 years@JuanM.Hidalgo that worked for me, placed the code above right before the call to
HttpsURLConnection connection = (HttpsURLConnection) obj.openConnection();
. Also, does this ignores every certificate? Since i saw that such a workaround is vulnerable to security. Thank you! -
Jus12 almost 8 yearsdisabling HTTPS check is not a "solution". You should say I found a "patch".
-
galeop almost 8 yearsIn my code I was sending the request to a public IP, but the certificate CN was a host name. So in my code, I replaced the IP by the hostname, and configured my /etc/hosts to associate this hostname to the IP. Solved !
-
bonapart3 about 7 years
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
is now deprecated. -
hitesh141 almost 7 yearsjava.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
-
Woland over 6 years"If FQDN is not resolvable on your dev machine, simply add it to your hosts file" – helped. Thanks a lot!
-
pkgajulapalli over 6 yearsI did the same thing but still, the issue persists. Is there anything else that can be done using this approach?
-
user64141 about 6 yearsHere are the import statements: import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate;
-
Shankar over 5 yearsThis will cause vulnerability on Pre_prod and Production. 1. Make host entry on windows host file 2. Or else add IP or FQDN names on Subject alternative names fields in the certs
-
Stephan Richter over 5 yearsCertificate check and hostname check are there for a good reason. While ignoring all warnings may be a workaround, this is definitly not a solution. It defies all security SSL is intended to provide.
-
jasie over 4 yearsplease add explanatory text to your code. See stackoverflow.com/help/how-to-answer
-
Marek Puchalski over 4 yearsThis is a security flaw. This is how one disables certificate verification in the first place. Everyone who copy-pastes this solution will create a security bug in their software.
-
Akhil S Kamath over 4 yearsthis answer solved my SSL cert exception and non LDH characters issue, I could see there is a bug reported in open JDK, bugs.openjdk.java.net/browse/JDK-8170265
-
Raymond Chiu over 3 yearsAdding the "-ext ip:<IP_ADDRESS>" in the keytool genkey command do fix the issue. Please note that when the keytools asking the first and last name, you need to put also the <IP_ADDRESS> answer to generate the cert.
-
rogerdpack about 3 yearsIt works, though it just continues on to some other error, disabling SSL entirely finally worked stackoverflow.com/a/19542614/32453
-
bharal about 3 yearsthis is the only solution that works! if the java team actually cared about security they would, you know, make this a simpler problem to solve
-
bharal about 3 yearsit's crazy, but nobody alive knows what that check they're doing actually prevents. just engineers adding things because they read it on a thoughtworks blog
-
mvreijn over 2 years@bharal The check is preventing man-in-the-middle attacks on your secure connections. Better not disable all certificate verification unless you are 100% sure it will only be used in a development environment.