Reputation: 722
I'm trying to implement a selfsigned certificate into my webserver, and it's working already with firefox and chrome (both from the server itself and from a remote machine)... but I can't get it to work with java. I've already created a keystore file that contains my certificate, but every time I try to connect to the Server it gives me a SSLHandshakeException: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names matching IP address 192.168.178.71 found
The code I'm using for this test is:
public static void main(String[] args) {
System.setProperty("javax.net.ssl.keyStore", HTTPStest.class.getResource("keystore.jks").getFile());
System.setProperty("javax.net.ssl.keyStorePassword", "lead");
URL url;
InputStream is = null;
BufferedReader br;
String line;
try {
url = new URL("https://192.168.178.71/");
is = url.openStream(); // throws an IOException
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (MalformedURLException mue) {
mue.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
if (is != null) is.close();
} catch (IOException ioe) {
// nothing to see here
}
}
}
And when checking my certificate with openssl it gives me this:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=DE, ST=BY, L=MU, O=LEAD, CN=LEAD CA/[email protected]
Validity
Not Before: Mar 20 00:55:13 2015 GMT
Not After : Mar 17 00:55:13 2025 GMT
Subject: C=DE, ST=BY, L=BE, CN=192.168.178.71
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:ed:9b:27:2b:ab:7d:88:48:a3:21:54:98:24:be:
2d:72:4a:de:9c:05:de:95:3a:01:d5:46:09:d2:9c:
9f:29:b0:12:0c:86:28:88:51:a3:b9:c9:93:33:3c:
8a:5c:f2:fe:49:e2:1e:9e:5a:4b:fb:63:41:9a:13:
e5:bc:03:77:a0:5e:f2:b1:1f:db:f9:a4:03:07:8c:
41:54:8c:bc:2e:da:cd:72:67:5b:2f:d5:83:fd:d0:
bf:ea:bb:49:e0:21:2f:b3:f2:51:57:7c:81:d2:4b:
91:12:73:13:6a:29:3b:59:90:2d:8d:50:cc:2b:f2:
76:a8:41:ac:0a:11:8b:63:3b:d4:5c:91:5c:1e:41:
33:6f:3e:fe:ed:f4:c3:26:77:d9:e2:0b:2c:09:5c:
20:31:09:59:19:5c:15:75:eb:15:ef:b8:d8:7d:a2:
2d:f4:f8:7f:3a:7c:e0:ad:c0:3b:86:1e:4f:b1:b9:
c3:60:f8:fa:3c:5a:5a:72:bf:f9:95:c3:d4:8d:2b:
22:3f:f8:a2:37:b3:c2:16:fa:9e:2d:f9:b5:78:6d:
4f:88:95:84:12:f3:f5:c2:09:9f:51:ed:73:da:4d:
9b:c3:2f:99:6d:d7:e9:f3:e0:c4:8b:73:09:25:1f:
93:5c:dc:d7:fa:5c:47:59:ff:70:70:09:72:4a:8c:
3f:c5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
FD:5F:79:74:31:E3:12:22:50:F8:C5:BE:A7:45:8B:10:65:8F:FC:A8
X509v3 Authority Key Identifier:
keyid:C5:2F:3A:53:A7:AF:96:E2:25:09:46:8A:11:B6:B9:5D:79:55:04:D9
X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage:
Digital Signature, Key Encipherment
X509v3 Subject Alternative Name:
DNS:192.168.178.71, DNS:www.example.com, DNS:mail.example.com, DNS:ftp.example.com
Netscape Comment:
OpenSSL Generated Certificate
Signature Algorithm: sha256WithRSAEncryption
7a:17:44:18:8e:31:11:b9:0a:fc:bf:d2:61:2f:16:24:56:24:
11:04:9e:2e:dc:65:d1:31:12:af:3d:ff:57:80:6b:45:70:f2:
e3:d8:2d:dd:d1:1d:05:ba:2e:92:d1:80:e8:93:0c:02:b2:47:
d1:5c:10:54:cb:4d:e5:52:f4:1d:c4:d2:26:a5:8e:4c:a3:44:
c0:6a:1d:74:27:89:6f:f4:dc:90:cc:3b:59:50:b7:38:5b:31:
da:21:01:d4:e6:4f:7a:23:23:d5:c5:61:29:32:1a:1e:bb:f9:
e1:3b:4f:a9:d8:d6:1d:f5:cf:15:04:18:8b:77:28:44:ef:ae:
33:8c:1e:72:d6:8c:c4:cc:7c:17:b8:f4:e5:d0:34:4f:d5:3d:
d7:59:4d:40:f3:42:1e:0c:26:98:73:98:a5:c2:d9:ea:2b:2a:
05:c3:f5:0b:e1:b6:d7:91:4a:09:15:21:1b:bc:d1:96:5e:bd:
47:9f:ab:27:e9:44:fc:00:e1:49:e4:74:1b:48:ff:56:01:03:
e7:9b:d2:bc:0a:53:39:95:52:5f:de:d8:fe:10:e8:53:5f:b4:
de:18:2d:50:a4:12:f8:48:37:66:4b:e1:18:21:69:ce:f3:0d:
2f:3d:03:22:bf:f6:91:3f:23:0b:58:4f:5f:be:82:67:ab:65:
98:15:e0:78:33:c6:50:38:39:42:ac:a5:bd:13:16:ca:58:64:
ce:a7:e8:88:e8:2f:eb:d5:7e:9e:75:51:da:50:b4:41:d1:83:
a8:a8:a3:18:25:b8:87:9d:c8:18:a0:db:7a:57:b1:31:e3:34:
a8:92:b7:4b:75:c4:34:09:3d:a2:de:69:b2:d5:2f:9e:97:b7:
c8:b5:df:8a:a8:d8:e2:b0:96:9e:56:39:40:c5:64:bf:fb:b2:
b8:cb:e1:29:24:a7:ce:00:34:d6:a9:11:c4:bf:8e:ae:c8:5c:
50:38:42:b9:15:9e:db:6b:00:ff:93:e8:0a:d3:00:13:0a:31:
3b:cc:93:ad:92:09:9d:97:dd:42:28:07:43:91:39:86:2e:54:
97:4a:a6:57:96:07:69:90:62:58:eb:0b:39:44:05:74:ad:f5:
bc:6a:41:5e:79:dd:27:99:32:67:c3:82:14:df:4b:44:a9:7e:
63:29:4e:c3:a3:ef:fa:1d:14:da:54:77:fb:6c:d8:c6:cc:5f:
99:06:38:f0:2c:78:41:f7:a1:5a:d6:29:1d:5f:df:f9:3b:7b:
cf:9f:73:f3:6c:b4:cf:0b:8e:39:7a:f1:35:3e:8d:66:12:4f:
f4:b1:04:6c:1f:d6:27:75:91:43:82:a4:74:a8:77:84:f9:ca:
14:71:8a:ac:da:3b:39:2d
Can anyone help me solve this problem? I know that I could just go for a hostname, but I would like to have it work this way too
Upvotes: 22
Views: 196455
Reputation: 1
From the Himadri Pant's answer, he didn't mention about buildSocketFactory(). So, this is my full code included with Himadri Pant's code snippet
HttpsURLConnection urlConnection = (HttpsURLConnection) new URL("https://test.test/api").openConnection();
urlConnection.setSSLSocketFactory(buildSocketFactory());
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("get");
urlConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession sslSession) {
return true;
}
});
urlConnection.getOutputStream();
Create new method for buildSocketFactory()
private SSLSocketFactory buildSocketFactory() {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
return sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException("Failed to create a SSL socket factory", e);
}
}
Upvotes: 0
Reputation: 185
This error kept driving me crazy, until after I decided to watch Netflix and blow off some mental steam. I came back to my laptop, and the first thought that dropped in my mind was to check on my domain name with my hosting service provider. It turned out my domain name had expired and all I had to do was to renew my subcription.
Upvotes: -1
Reputation: 215
I had the same issue while accessing the API via IP address. So if you are in a position like me where you cannot make much changes in the code or the certificate itself, then you can simply add the CN name in your host file. So in windows operating system, I edited the following file
C:\Windows\System32\drivers\etc\hosts
and added following entry in it
10.10.10.10 xyz.domain.com
The domain name can be found in the CN in the certificate by hitting the the IP address in the browser.
If the CN name is like *.domain.com, then you can set the domain name as per your convenience such as abc.domain.com
But as per my opinion, this should be done only for local testing. The production environments should have the proper domain- address called instead of an IP address.
Upvotes: 0
Reputation: 179
- listar: keytool -list -v -keystore cacerts
- importar: keytool -importcert -file your-cert.crt -keystore cacerts -alias "ldap cert"
Verify JAVA_HOME is the same as keytool under you run the code
The hostname or domain in your .cert must be equals as the domain server
you must be valid a cert using a tool to confirm the name of the .cert, for example, this is a command using windows:
- CheckSSLCert.exe yourserverip [port]
the code:
public DirContext dirContext(String currentPassword, String distinguishedName) throws Exception {
log.info("getConnection configuration");
try {
Hashtable<String, String> env = new Hashtable<>();
String keystore = System.getProperty("java.home") + System.getProperty("file.separator") + "lib" + System.getProperty("file.separator") + "security" + System.getProperty("file.separator") + "cacerts";
System.setProperty("javax.net.ssl.trustStore", keystore);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldaps://yourserverldap.hostname:636");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "your ldap user");
env.put(Context.SECURITY_CREDENTIALS, "your pass");
env.put(Context.SECURITY_PROTOCOL, "ssl");
return new InitialDirContext(env);
} catch (Exception e) {
log.info("error " + e.getMessage());
throw e;
}
}
Upvotes: 0
Reputation: 1919
I was having the same problem so sharing my experience. These values should be same.
Take the CN value of the certificate and save into /etc/hosts and try to access it with this URI. It will work
Upvotes: 2
Reputation: 11
Instead of using ip address as your url. You can try using FQDN in the url
Upvotes: 0
Reputation: 832
I have resolved the said
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names matching IP address
error by adding one alternative subject name (DNS) in the server certificate (having CN=example.com) which after prints the part of certificate as below:
Subject Alternative Name:
DNS: example.com
I used KeyExplorer on windows for generating my server certificate. You can follow this link for adding alternative subject names (follow the only part for adding it).
Upvotes: 0
Reputation: 991
Your certificate should include that ip value as a subject alternative name value (of type IPAddress : key=7).
Upvotes: 11
Reputation: 480
1- Modify the file: /etc/ssl/openssl.cnf, for example:
subjectAltName=DNS:api.electoralsystem
2- Generate private key
jmendoza@jmendoza:~$ openssl genrsa -aes256 -out electoralsystem-cakey.pem 2048 -alias electoralsystem-cakey.pem
Generating RSA private key, 2048 bit long modulus
....................+++++
.......................................+++++
e is 65537 (0x010001)
Enter pass phrase for electoralsystem-cakey.pem:
Verifying - Enter pass phrase for electoralsystem-cakey.pem:
3- Generate cacert x509
jmendoza@jmendoza:~$ openssl req -new -x509 -sha256 -key electoralsystem-cakey.pem -days 365 -out electoralsystem-cacert.pem
Enter pass phrase for electoralsystem-cakey.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:VE
State or Province Name (full name) [Some-State]:CARACAS
Locality Name (eg, city) []:CARACAS
Organization Name (eg, company) [Internet Widgits Pty Ltd]:JMENDOZA
Organizational Unit Name (eg, section) []:TI
Common Name (e.g. server FQDN or YOUR name) []:api.electoralsystem
Email Address []:[email protected]
openssl x509 -in electoralsystem-cacert.pem -text
4- Generate keystore pkcs12
jmendoza@jmendoza:~$ openssl pkcs12 -export -in electoralsystem-cacert.pem -inkey electoralsystem-cakey.pem -out electoralsystem-store.p12 -name "electoralsystem-store"
Enter pass phrase for electoralsystem-cakey.pem:
Enter Export Password:
Verifying - Enter Export Password:
5- If you need it, convert the PKCS12 keystore to JKS keytstore using keytool command
jmendoza@jmendoza:~$ keytool -importkeystore -destkeystore electoralsystem-store.jks -deststorepass jmendoza -srckeystore electoralsystem-store.p12 -srcstoretype PKCS12 -srcstorepass jmendoza -alias electoralsystem-store
Importando el almacén de claves de electoralsystem-store.p12 a electoralsystem-store.jks...
6- On the client, import certificate in keytstore
jmendoza@jmendoza:~$ keytool -importcert -file electoralsystem-cacert.pem -keystore ldap-server-smmt.jks
Introduzca la contraseña del almacén de claves:
Import certificate in keytstore
Invoke API - https://api.electoralsystem:8081/yyyy/xxxxx
7- Configure certificates on the api server
Configure certificates on the api server
8- Summary generated files
jmendoza@jmendoza:~$ ls -lt
total 1332
-rw-rw-r-- 1 jmendoza jmendoza 2482 jul 25 10:15 ldap-server-smmt.jks
-rw-r--r-- 1 jmendoza jmendoza 2442 jul 25 10:04 electoralsystem-store.jks
-rw------- 1 jmendoza jmendoza 2792 jul 25 10:01 electoralsystem-store.p12
-rw-r--r-- 1 jmendoza jmendoza 1509 jul 25 09:45 electoralsystem-cacert.pem
-rw------- 1 jmendoza jmendoza 1766 jul 25 09:38 electoralsystem-cakey.pem
Note: configure DNS api.electoralsystem on the client's docker or server
Upvotes: 0
Reputation: 2291
The reason why this fails is because the hostname of the target endpoint and the certificate common name (CN
in certification Subject
does not match).
For e.g., from a JVM, when trying to connect to an IP address (WW.XX.YY.ZZ
) and not the DNS name (https://stackoverflow.com), the HTTPS connection will fail because the certificate stored in the java truststore cacerts
expects common name to match the target address.
To mitigate this HostnameVerifier needs to be verify the connection despite the mismatch https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#HostnameVerifier
HttpsURLConnection urlConnection = (HttpsURLConnection) new URL("https://test.test/api").openConnection();
urlConnection.setSSLSocketFactory(buildSocketFactory());
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("get");
urlConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession sslSession) {
return true;
}
});
urlConnection.getOutputStream();
Upvotes: 14
Reputation: 3054
The reason, we get above error is that CN(Common name) defined in your certificate is not matching with the domain the application is running on. For e.g, In your certificate, the CN name is defined as www.example.com or an IP but you may be running the application say a URL which is like http://localhost:8080/api
So to fix the above error simply use one of the below approaches
Run the application on the same ‘CN’, as defined in your certificates.
OR
Along with CN name you can add Subject alt names in your certificate, which is like adding more than one domain in the certificate. Link below describes the process of adding multiple domains(subject-alt-name) to jks file and also to a certificate.
Follow this link: Learn how to add subject alt names and resolve the above error
Upvotes: 4