I found some "standard code" from forums allowing me to skip the validation of trusted certificates in Java.
My code implements some old style WSDL client implementation. I'm using JDK 1.8.
public class myClass exteds Service{
public SessionProxy(String baseurl, SSLSocketFactory sslFactory, boolean compression) {
// Get the port
port = super.getPort(new QName("http://host.com/d3s/jel/dk/service/something/v2u1.wsdl", "Port"), Port.class);
// Set the endpoint address
Map<String, Object> context = ((BindingProvider) port).getRequestContext();
if (baseurl != null) {
context.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, baseurl);
}
SSLTool.disableCertificateValidation();
if (sslFactory != null) {
context.put(JAXWSProperties.SSL_SOCKET_FACTORY, sslFactory);
}
}
public String recordSessions(CasinoGameSessions sessions) throws
SystemFaultException, UserFaultException {
String result= "";
result += port.recordSessions(sessions) + "\n";
disposeSSLSocketFactory();
return result;
}
This is the SSLTool class I found (many other code samples are really similar to this one):
import javax.net.ssl.*;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
public class SSLTool {
public static void disableCertificateValidation() {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}};
// Ignore differences between given hostname and certificate hostname
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) { return true; }
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hv);
} catch (Exception e) {}
}
}
When I run my code, despite the fact I call SSLTool.disableCertificationValidation() I get the exception:
aused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[?:1.8.0_162]
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154) ~[?:1.8.0_162]
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2038) ~[?:1.8.0_162]
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1135) ~[?:1.8.0_162]
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385) ~[?:1.8.0_162]
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413) ~[?:1.8.0_162]
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397) ~[?:1.8.0_162]
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559) ~[?:1.8.0_162]
at sun.net.www.protocol.https.AbstractDelegateHttpsUR
This should mean my client still tries to validate the server certificate and to make the handshake with it.
Related
I am trying to download a file from a url using Apache commons FileUtils on AWS Lambda.
But i am get this exception.
javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:994)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1564)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:263)
at java.net.URL.openStream(URL.java:1045)
at org.apache.commons.io.FileUtils.copyURLToFile(FileUtils.java:1478)
I have using java 8 in AWS Lambda.
I have tried
System.setProperty("https.protocols", "SSLv3,TLSv1,TLSv1.1,TLSv1.2");
Security.setProperty("jdk.tls.disabledAlgorithms", "");
public static void addSslToTrustStore() throws NoSuchAlgorithmException, KeyManagementException {
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);
}
These were all the options I found online, but didn't worked for me.
File gets downloaded on my local with ou any exception but throws exception on lambda.
Please help me.
I have a Spring Boot API that runs locally, with a self-signed certificate, using the HTTPS protocol.
Obviously, when I send GET Requests from the browser, I receive the io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown error on the server side, which is normal, because the self-signed is not trusted by the browser. Postman works just fine for GET and POST.
However, I want to send GET requests from an Android client to the Spring API but, even I've used a function to allow all SSL traffic (yes, I know it's not recommended), I still can't send requests to the API, receiving the following output:
I/STATUS: 405
I/MSG: Method Not Allowed
I thought my allowAllSSL() function (HttpsTrustManager class) would solve the issue, because if I remove the function call, I receive the following error, which seems to match the one on the server side:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:239)
Now, you may think that the GET request is not implemented correctly in Spring, but it's not true, since the same GET request works just fine from Postman. I believe that the problem is still linked to the certificate, but I can't figure out what do I need to change. Here is my code:
Spring BOOT Rest Controller
#RestController
#RequestMapping("/post")
public class PostRequest {
#GetMapping("")
public String string(#RequestBody ImageRequest newEmployee){
....
The ImageRequest class contains just three private String members.
HttpsTrustManager class (to allow all SSL)
package com.example.androidclient;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
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;
public class HttpsTrustManager implements X509TrustManager {
private static TrustManager[] trustManagers;
private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};
#Override
public void checkClientTrusted(
X509Certificate[] x509Certificates, String s)
throws java.security.cert.CertificateException {
}
#Override
public void checkServerTrusted(
X509Certificate[] x509Certificates, String s)
throws java.security.cert.CertificateException {
}
public boolean isClientTrusted(X509Certificate[] chain) {
return true;
}
public boolean isServerTrusted(X509Certificate[] chain) {
return true;
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return _AcceptedIssuers;
}
public static void allowAllSSL() {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
SSLContext context = null;
if (trustManagers == null) {
trustManagers = new TrustManager[]{new HttpsTrustManager()};
}
try {
context = SSLContext.getInstance("TLS");
context.init(null, trustManagers, new SecureRandom());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
HttpsURLConnection.setDefaultSSLSocketFactory(context != null ? context.getSocketFactory() : null);
}
}
Android Request
HttpsTrustManager.allowAllSSL();
URL url = new URL("https://192.168.1.106:8443/post");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
conn.setRequestProperty("Accept", "application/json");
conn.setDoOutput(true);
conn.setDoInput(true);
JSONObject jsonParam = new JSONObject();
jsonParam.put("location", "Somewhere");
jsonParam.put("date", "22.05.2020");
jsonParam.put("imageBytes", strings[0]);
Log.i("JSON", jsonParam.toString());
DataOutputStream os = new DataOutputStream(conn.getOutputStream());
//os.writeBytes(URLEncoder.encode(jsonParam.toString(), "UTF-8"));
os.writeBytes(jsonParam.toString());
os.flush();
os.close();
Log.i("STATUS", String.valueOf(conn.getResponseCode()));
Log.i("MSG", conn.getResponseMessage());
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
return "ok";
}
Use this function in your android application.
Please note this will allow all ssl certificates without verification. I would encourage you to follow the recommended approach when dealing with self-signed certificates outlined here: https://developer.android.com/training/articles/security-ssl#java
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
#Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
I have found the solution on my own.
Apparently, the Connection.setDoOutput(true) method is working just for POST and PUT requests, but not for GET.
Thus, I have changed my RequestMapping to work on POST, like, this:
#RequestMapping(
value = "/post",
produces = "application/json",
method = RequestMethod.POST)
Now I receive 200 OK.
I have created 2 classes:
-This one extend OkHttp and have a new method getUnsafeOkHttpClient().
public class GetExampleOkHttp extends OkHttpClient {
public OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType)
throws CertificateException {
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType)
throws CertificateException {
}
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
} };
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory);
builder.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
And other Main class:
class ExampleOkHttpMain
public static void main(String[] args) throws IOException {
GetExampleOkHttp example = new GetExampleOkHttp();
example.getUnsafeOkHttpClient();
Request request = new Request.Builder()
.url("https://lachuzhnikov.kiev.ua/test.txt")
.build();
Response response = example.newCall(request).execute();
System.out.println(response.body().string());
}
}
But I still have an error:
Exception in thread "main" javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
1: Download https://sourceforge.net/projects/portecle/
2: Open firefox and go to page and export cer
3: Backup Java\jdk....\jre\lib\security\cacerts (eg: C:\Program Files\Java\jdk1.7.0_79\jre\lib\security)
4: Copy cacerts to another folder
5: Portecle open file cacerts (pass: changeit) import cer in step 2 and save
6: Copy and replace new cacerts Java\jdk....\jre\lib\security\cacerts
In my android app am using a okhttp client which trusts all ssl certificates. The problem is, am facing random SSLExceptions. For example 8 out of 10 calls fail due to SSLExceptions and 2 succeed.
Any pointers on why this might be happening?
Please let me know if you need more info.
stack trace:
javax.net.ssl.SSLException: Connection closed by peer
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
at com.squareup.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:103)
at com.squareup.okhttp.Connection.connect(Connection.java:143)
at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:185)
at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)
at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330)
at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
at com.squareup.okhttp.Call.getResponse(Call.java:273)
at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:230)
at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:201)
at com.squareup.okhttp.Call.execute(Call.java:81)
at retrofit.client.OkClient.execute(OkClient.java:53)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:326)
at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:278)
at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at retrofit.Platform$Android$2$1.run(Platform.java:142)
at java.lang.Thread.run(Thread.java:841)
This is how i create the okHttp client:
private OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
return createOkHttpClientWithTimeout(sslSocketFactory);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected OkHttpClient createOkHttpClientWithTimeout(SSLSocketFactory sslSocketFactory) {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setConnectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
okHttpClient.setReadTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
okHttpClient.setSslSocketFactory(sslSocketFactory);
okHttpClient.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
return okHttpClient;
}
Note: I know that trusting all SSL certificates is bad.
I try to use SOAPConnection to call https, and I have already point to keystore and truststore as follow:
System.setProperty("javax.net.ssl.keyStore", "C:/kei/tasks/MIP/Cert/ccc_acp.keystore");
System.setProperty("javax.net.ssl.keyStorePassword", "password");
System.setProperty("javax.net.ssl.trustStore", "C:/kei/tasks/MIP/Cert/trusteaistore.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "password");
System.setProperty("javax.net.debug", "all");
but I still get the
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present
I google and find the follow temporary solution
System.setProperty( "sun.security.ssl.allowUnsafeRenegotiation", "true" );
but even I set allowUnsafeRenegotation to true, I still get the
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present
And I try to use SOAPUI 5.1.3, and in preference> ssl, I set the keystore and keystore password (but no place to set truststore), this time I can connect to my target server through https!
so
1) why soapUI 5.1.3 does not need to set truststore (but only keystore), but still can connect to https server?
2) why use system property to point to the same keystore, but I cannot connect to https server using SOAPConnection?
3) why I set allowUnsafeRenegotitation system property to true, but it seems it still check the public cert. of the https server, and return CertificateException?
***************** edit on 15/5/2015
I post the code here
public static void main(String args[]){
System.setProperty("javax.net.ssl.keyStore", "C:/kei/tasks/MIP/Cert/ccc_acp.keystore");
System.setProperty("javax.net.ssl.keyStorePassword", "password");
MipCccSoapTest mipCccSoapTest = new MipCccSoapTest();
mipCccSoapTest.testHttpConnection();
}
private void testHttpConnection(){
try{
doTrustToCertificates();
URL url = new URL("https://10.7.3.43:9443/iboss/CustomerCareM1");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
HttpsURLConnection.getDefaultSSLSocketFactory();
System.out.println("ResponseCoede ="+conn.getResponseCode());
}catch(Exception ex){
ex.printStackTrace();
}
System.exit(0);
//end testing
}
// trusting all certificate
public void doTrustToCertificates() throws Exception {
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
return;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
return;
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
}
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);
}
and I get the following error
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
but the keystore should be correct as I use the same keystore in SOAPUI 5.1.3 which can successfully call the server.
**************** edit on 18/5/2015 *************
After I comment out the following code
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
return;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
return;
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
it can connect to the https server now.
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present
This is a problem with the servers certificate. You need to fix it there by adding a subject alternative section with the proper information so that it can be successfully validated. It has nothing to do with the trust chain, so no changes to keyStore or trustStore help. More information might be given if the servers URL or certificate would be known.
System.setProperty( "sun.security.ssl.allowUnsafeRenegotiation", "true" );
This is a TLS protocol level thing and has nothing to do with certificate validation.
In case you cannot fix the servers certificate see SSLHandshakeException: No subject alternative names present for a possible workaround (first hit when googling for this error message!).