问题
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
回答1:
Your certificate should include that ip value as a subject alternative name value (of type IPAddress : key=7).
http://www.jroller.com/hasant/entry/no_subject_alternative_names_matching
回答2:
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();
回答3:
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
回答4:
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
回答5:
I have solved the issue using 3 Steps
Creating a class . The class has some empty implementations
class MyTrustManager implements X509TrustManager { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } @Override public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException { // TODO Auto-generated method stub } @Override public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException { // TODO Auto-generated method stub }
Creating a method
private static void disableSSL() { try { TrustManager[] trustAllCerts = new TrustManager[] { new MyTrustManager() }; // Install the all-trusting trust manager SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HostnameVerifier allHostsValid = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { e.printStackTrace(); }}
Call the disableSSL() method from where exception being thrown. It worked fine.
来源:https://stackoverflow.com/questions/29157861/java-certificateexception-no-subject-alternative-names-matching-ip-address