Java 证书例外“找不到匹配 IP 地址的主体替代名称... ”
原标题:Java CertificateException "No subject alternative names matching IP address ... found"
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/emailAddress=test@gmail.com
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
最佳回答
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
问题回答
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();
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
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
Execute the following steps
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 []:xxxx@gmail.com
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
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).
Instead of using ip address as your url. You can try using FQDN in the url
import .cert using keytool (java):
- 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 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;
}
}
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:WindowsSystem32driversetchosts
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.
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);
}
}
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.
相关问题
Spring Properties File
Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...
What do you say of chopping type-4 UUID in this manner
Check this,
List<String> list = new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
String value = (""+UUID.randomUUID().getLeastSignificantBits()).substring(3, ...
combining decorator and state pattern in java - question about OO design
I am in the middle of solving a problem where I think it s best suited for a decorator and a state pattern. The high level setting is something like a sandwich maker and dispenser, where I have a set ...
Unable to execute stored Procedure using Java and JDBC on SQL server
I have been trying to execute a MS SQL Server stored procedure via JDBC today and have been unsuccessful thus far. The stored procedure has 1 input and 1 output parameter. With every combination I ...
Logging a global ID in multiple components
I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications.
[App A] -> [App B] -> [App C]
We set a ...
Java Library Size
If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is:
How will the larger, mostly unused ...
How to get the Array Class for a given Class in Java?
I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this:
Class arrayOfFooClass = java.lang....
SQLite , Derby vs file system
I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database.
How hard is it to migrate ...