I'm currently developing an Android application on which I need to do a SSLSocket Connected to a test server.
Thing is we won't buy a certificate for this server since it is a test server, not production.
While it works fine on Simulator, however on my S3 it gives me this error :
06-01 00:36:17.355: I/System.out(13629): java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
The exception is throws by the last line of this code :
mSf = (SSLSocketFactory) SSLSocketFactory.getDefault();
mSocket = (SSLSocket) mSf.createSocket("myTestingServer.com", 443);
mSocket.startHandshake();
I don't really care that the solution is either code or lower the security check as an Android user, since it is to test on my S3, once in production, the certificate should be good.
This is not a HTTP server, so I can't use org.apache.http.org.ssl
Maybe you want to ignore the certificate check
Warning : this code is not safe
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
#Override
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());
SSLSocketFactory sslsocketfactory = sc.getSocketFactory();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("google.com", 443);
...
Source : Using Java to connect with SSLSocket, trusting all certificates
Related
I am developing a native android app in java, that needs to communicate with a server, which is very old and only have TLSv1 connectivity with limited number of cipher suites available.
Building the app using Android Studio Chipmunk (2021.2.1)
compileSDK 31
minSDK 19
targetSDK 25
My code as follows:
System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2,SSL3");
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
ExecutorService ex = Executors.newSingleThreadExecutor();
Callable<String> connectedCallableTask = () -> {
SSLContext sslContext = SSLContext.getInstance("TLSv1");
sslContext.init( null, trustAllCerts, new java.security.SecureRandom());
SSLSocket sslSocket = (SSLSocket) sslFactory.createSocket(serverip, serverport);
sslSocket.startHandshake();
...
...
}
Future<String ContentFuture = ex.submit(connectedCallableTask);
...
...
The code stopped/crashed at sslSocket.startHandshake();
After researched for a while, I found out the cipher suites from the client is not accepted by the server.
After I talked to others, they shared a wireshark packets to me. One of the Cipher Suites the server accepts is "TLS_RSA_WITH_RC4_128_MD5". So, I thought I can simply add the following ciper suites in my client side code:
SSLParameters params = new SSLParameters();
params.setProtocols(new String[] {"TLSv1"});
params.setCipherSuites(new String[] {"TLS_RSA_WITH_RC4_18_MD5"});
sslSocket.setSSLParameters(params);
sslSocket.startHandshake();
It throws me an exception: Unsupported Cipher Suites
What could I do to connect to the old server, which I have no idea whats in there.
I am using standard way to connect to SSL server with self signed certificate described here: https://developer.android.com/training/articles/security-ssl.html for the "Unknown certificate authority".
Everything works up to the Android 7.
On Android 7 and above I am getting Certificate exception with the message: "java.security.cert.CertPathValidatorException: Trust anchor for certification path not found."
The only thing I managed to do is to create an "empty" X509TrustManager which accepts all certificates:
final TrustManager[] trustAllCerts = new TrustManager[]
{
new javax.net.ssl.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() { }
};
//and then
sSslContext = SSLContext.getInstance("TLS");
sSslContext.init(null, trustAllCerts, null);
but when I am adding the verification to the checkServerTrusted function:
public void checkServerTrusted(java.security.cert.X509Certificate[]
chain, String authType) throws CertificateException {
((X509TrustManager) trustManager.checkServerTrusted(chain, authType);
}
everything remains the same
I also checked the sources of the conscrypt library and I see that checkTrusted function puts the leaf to the untrusted chain if leafAsAnchor == null which is the case.
So is that possible to use self-signed certificate in this way or no?
Hello my application is live and it is using "https" protocol. The Google Play Team throws warning as below.
"Your app(s) listed at the end of this email use an unsafe
implementation of the interface X509TrustManager. Specifically, the
implementation ignores all SSL certificate validation errors when
establishing an HTTPS connection to a remote host, thereby making your
app vulnerable to man-in-the-middle attacks. An attacker could read
transmitted data (such as login credentials) and even change the data
transmitted on the HTTPS connection. If you have more than 20 affected
apps in your account, please check the Developer Console for a full
list.
To properly handle SSL certificate validation, change your code in the
checkServerTrusted method of your custom X509TrustManager interface to
raise either CertificateException or IllegalArgumentException whenever
the certificate presented by the server does not meet your
expectations. Google Play will block publishing of any new apps or
updates containing the unsafe implementation of the interface
X509TrustManager."
In my project I am using custom http client to handle HTTPS instead default httpClient. My code is as below.
public static HttpClient getNewHttpClient() {
try
{
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
}
catch (Exception e)
{
return new DefaultHttpClient();
}
}
public static class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
#Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
#Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
How to overcome with this problem?
Hoping for favorable answers.
Now that you have posted the code concerned, it is difficult to see what part of the quoted message you don't understand.
The fix is simply to remove the TrustManager part of the code altogether, root and branch, and use the default one, and then deal with whatever problems may then arise in the proper way, by adjusting the contents of the truststore also as to trust all the certificates you need to trust that aren't already trusted by default. If any, which there shouldn't be.
Why do you need custom SSLSocketFactory. You can use DefaultHttpClient and that will handle all https by default. Just for your info, that HttpClient is deprecated and use HttpURLConnection.
I've got a server serving at port 9443. It's using an ssl cert signed by godaddy for "example.com". I try to connect to a url like:
https://example.com:9443/api/v1/foo
and that works fine from an ios app I've written, and desktop browsers. If I try connecting from an android phone, I get a 400 bad request response. I tried the same through chrome for android, it gives me:
ERR_TUNNEL_CONNECTION_FAILED
The server is also listening to port 443, using a self-signed cert, and the android client works ok there (I do need some additional code there to make my app trust the self-signed cert).
Is there some restriction in android where https must use port 443? I was thinking that since I'm using a legitimate ssl cert, I wouldn't need any custom code to force the app to trust the cert. My connection code:
HttpParams params = new BasicHttpParams();
DefaultHttpClient client = new DefaultHttpClient(params);
HttpResponse response = client.execute(request);
Result result = new Result(response.getStatusLine().getStatusCode());
response.getStatusLine().getStatusCode(); // 400
response.getStatusLine().toString(); // HTTP/1.1 400 Bad Request
Thanks
Two possibilities, I think.
Searching for ERR_TUNNEL_CONNECTION_FAILED android leads me to this page, where the author claims:
Android for some unknown reason will not allow you to use unstandard
ports for SSL (i.e. only port 443 works when using https)
I confirmed this by trying a SSL website on port 2000 using my wifes
iphone on AT&T. Sure enough it worked fine. So its not AT&T. Also
worth pointing out it works fine on wifi.
Hopefully this is just a bug and will be fixed in the future.
However, this site claims that error occurs when accessing a site through a proxy. It's possible you may have a proxy configured on your Android phone that it's trying to use somehow.
The easiest way to tell which world you're in would be to check from a different Android phone, if you have one.
It may help you
public HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(
params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
#Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
#Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
I am doing a HTTPS request using a HttpsURLConnection.
The server I'm trying to contact has a self-signed certificate, so this logically causes the request to fail.
However, the failure isn't signaled to my program by an exception. It just fails and I can see why in the logcat.
03-22 17:54:35.203: W/System.err(21147): javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
03-22 17:54:35.203: W/System.err(21147): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:381)
Here is the code I use for the request:
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setUseCaches(false);
connection.setAllowUserInteraction(false);
connection.connect();
Ideally, I'd like my program to react like browser do: popup a dialog indicating that the certificate is not trusted and possibly add it to some key-store and retry the request.
But since I can't figure out a way of getting the exception, I really don't know what to do here.
Any clue ?
While huge is correct that you need to implement a custom TrustManager, you should absolutely not just blindly accept all SSL certificates.
Nikolay Elenikov has an excellent blog post describes how to set up a custom TrustManager to validate such certificates
You can do it like this:
SSLContext sc = SSLContext.getInstance("TLS");
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return;
}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return;
}
} };
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpURLConnection = connection = endPoint.openConnection();