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
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).
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
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
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 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.
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();