javax.net.ssl.SSLHandshakeException? - java

I'm trying to connect to a WCF server using HTTPS connection (UrlHttpsConnection class) and always get the error "Trust anchor for certification path not found".
I found thousands examples on the Web about that issue but nothing that really helps me.
My WCF service works with a certificate signed by an internal CA that has been added to the list of trusted CAs on my smartphone. If I call the url https://myserver/myservice/test from Chrome on my smartphone, I no longer have warning, the certificate is considered as valid. From my app, I keep getting the error message.
Do you know why my app does not consider the server certificate as valid while Chrome does ? How can I fix that ?
For security reasons, I don't want ignore the SSL verification.
Thank you in advance for your suggestions.

Try this way but i used retrofit for api calling..
public class ApiClient {
//public final static String BASE_URL = "https://prod.appowiz.com/app/services/";
public final static String BASE_URL_SECURE = "Pass your url";
public static ApiClient apiClient;
private Retrofit retrofit = null;
private static Retrofit storeRetrofit = null;
public Retrofit getClient(Context context) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL_SECURE)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
}
public static Retrofit getStore() {
if (storeRetrofit == null) {
final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[0];
}
}};
// Install the all-trusting trust manager
final SSLContext sslContext;
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.sslSocketFactory(sslSocketFactory).hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
.build();
storeRetrofit = new Retrofit.Builder()
.baseUrl(BASE_URL_SECURE)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
} catch (NoSuchAlgorithmException | KeyManagementException e1) {
CustomLogHandler.printErrorlog(e1);
}
}
return storeRetrofit;
}
for api calling create interface..
public interface ApiInterface {
#POST("device/add_device_name")
Call<AddDeviceNameVo> addDeviceName(#Body JsonObject body);
}
called api into activity or fragment like this way..
apiInterface = ApiClient.getStore().create(ApiInterface.class);

Related

How to bypass HTTPS SSL certificate verification in Android using Kotlin and Retrofit

I'm trying to send a POST request to node server from an Android client.
I'm getting java.lang.ExceptionInInitializerError error while Creating okhttpClient that suppose to bypass Android's SSL certificate verification process
This is my code:
object RetrofitServiceBuilder {
private val interceptor = run {
val httpLoggingInterceptor = HttpLoggingInterceptor()
httpLoggingInterceptor.apply {
httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
}
}
private val trustAllCerts : Array<X509TrustManager> = arrayOf(object : X509TrustManager {
#Throws(CertificateException::class)
override fun getAcceptedIssuers(): Array<X509Certificate>? = null
override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) {}
override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) {}
})
private val sslContext = SSLContext.getInstance("TLS").apply {
init(null, trustAllCerts, SecureRandom())
}
private val hostNameVerifier : HostnameVerifier =
HostnameVerifier { hostname, session -> true; }
private val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
//This is the part where i get the error
.sslSocketFactory(sslContext.socketFactory, trustAllCerts[0])
.hostnameVerifier(hostNameVerifier)
.build()
private val retrofit = Retrofit.Builder()
.baseUrl("https://xx.xxx.xxx.x:xxxx/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
fun<T> buildService(service: Class<T>): T {
return retrofit.create(service)
}
}
Anyone know how to correctly write this certificate verification bypass code?

is it possible to attach the certificate without store in trust store in sslcontext

is it possible to attach the certificate without store in trust store in sslcontext
This is my code while running my code its not x509 format exception i am getting
#Bean(name="custRest")
#Primary
public RestTemplate restTemplate() throws Exception {
char[] password = "password".toCharArray();
SSLContext sslContext = SSLContextBuilder
.create()
.loadTrustMaterial(ResourceUtils.getFile("C:\\test\\test.der"), password,
new TrustSelfSignedStrategy())
.build();
HttpClient client = HttpClients.custom().setSSLContext(sslContext).build();
return new RestTemplateBuilder().requestFactory(new HttpComponentsClientHttpRequestFactory(client))
.build();
}
how to config in conf\nginx.conf of nginx.
server {
listen 10000; // nginx port
server_name localhost;
charset utf-8;
location /certs/ {
# where your cert files to be stored in nginx server machine. I suppose it is under /data/certs.
alias /data/certs/;
autoindex off;
}
}
url of access = http://[nginx server ip ]:10000/certs/test.cer
The below is sample of building restTemplate
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HttpContext;
import org.springframework.web.client.RestTemplate;
// suppose your server ip is 10.0.0.1
final static String URL = "http://10.0.0.1:10000/certs/test.cer";
final static String PWD = "123456";
private RestTemplate sslTemplate() throws Exception {
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(new URL(URL), PWD.toCharArray())
// .loadTrustMaterial(new File(FILE_PATH), PWD.toCharArray())
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
#Override
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
return false;
}
};
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).setRetryHandler(retryHandler)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
return restTemplate;
}

NTLM authentication using spring

I have a service I want to use in my application. The service uses NTLM authentication for authentication and I am trying to make a REST call with NTLM Auth.
I tried the suggestion in this thread How to set NTLM authentication in rest template Header in Spring
But it gave me a 500 error (the 401 went away though)
Only Web services with a [ScriptService] attribute on the class definition can be called from script.
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) throws NoSuchAlgorithmException, KeyManagementException {
// IF you want to disable the ssl certification validation
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
String user = "username";
String password = "password";
String domain = "domain"; // optional
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new NTCredentials(user, password, null, domain));
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setDefaultCredentialsProvider(credentialsProvider)
.build();
HttpComponentsClientHttpRequestFactory customRequestFactory = new HttpComponentsClientHttpRequestFactory();
customRequestFactory.setHttpClient(httpClient);
RestTemplate build = builder.requestFactory(() -> customRequestFactory).build();
return build;
}

javax.net.ssl.SSLHandshakeException: Handshake failed in Android 7.0

I am calling API to login but I am getting error of ssl handshake in Android 7.0, other than this version everything is working fine. I am using retrofit.
Following is the error.
SSL handshake terminated: ssl=0xcbcd0340: Failure in SSL library, usually a protocol error
error:1000043e:SSL routines:OPENSSL_internal:TLSV1_ALERT_INAPPROPRIATE_FALLBACK (external/boringssl/src/ssl/s3_pkt.c:610 0xebc87640:0x00000001)
Also as said by someone to add the following code so that this issue will be resolved but still no luck,
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
.build();
okHttpClient.connectionSpecs(Collections.singletonList(spec));
I have even tried to letgo trust each and every certificate but still no luck. Following is the code.
public static OkHttpClient.Builder sslSocketFactory(OkHttpClient.Builder okHttpClient)
{
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[]{};
}
}
};
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_0)
.allEnabledCipherSuites()
.build();
// 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 javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
//////// OkHttpClient.Builder builder = new OkHttpClient.Builder();
okHttpClient.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
okHttpClient.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Following are my ssllabs tested using android 7.0
ssllabs test
In all other android versions all API's are working fine I do get response, but I am not able to get response in version 7.0.
Actually it's more likely to be a ssl_ciphers server-side settings problem.
Assuming nginx, change your ssl_ciphers settings to the one recommended by openHab :
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;
Don't forget to reload (systemctl reload nginx) and now all problematic android devices should work just fine.

OkHTTP (v3.0.0-RC1) Post Request with Parameters

UPDATE
I'm using okHttp library, version 3.0.0 RC-1. I have a url and I have to send a post request with parameters. For example: https://myurl.com/login?username=123456&password=12345
I have code like this:
public String okHttpRequest(){
try {
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 null;
}
}
};
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null,trustAllCerts, new java.security.SecureRandom());
final javax.net.ssl.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;
}
}).build();
final OkHttpClient client = new OkHttpClient();
HttpUrl url = HttpUrl.parse("https://myUrl.com/login").newBuilder()
.addQueryParameter("username", "123456")
.addQueryParameter("password", "123456")
.build();
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Log.d("Request:", "Is NOT sent " + request.toString() + " METHOD: " + request.method());
e.printStackTrace();
}
#Override
public void onResponse(Response response) throws IOException {
Log.d("Request:", "Is sent " + response.toString());
}
});
}catch(Exception e){
e.printStackTrace();
}
return "okHttp is Working!!! ";
}
Whenever I try, It fails, so onFailure method is executing. What is the problem? Am I adding request params incorrectly? Please help...
Yes, you are adding the query parameters incorrectly. Here's how it should be done:
final OkHttpClient client = new OkHttpClient();
HttpUrl url = HttpUrl.parse("https://myUrl.com/login").newBuilder()
.addQueryParameter("password", "123456")
.addQueryParameter("username", "123456")
.build();
Request request = new Request.Builder()
.url(url)
.build();
(...)
The problem is that you are submitting your data in the body of the request, as if it were a HTML form submit, and not as a query parameter, as you intended. Using HttpUrl allows you to add query parameters to your URL.
Worth noting that you can also simply do this:
Request request = new Request.Builder()
.url("https://myurl.com/login?username=123456&password=12345")
.build();
So:
Use HttpUrl and it's builder to create your URL and add parameters.
Use FormBody to create the content of your request (as if it were a html form you're submitting), if you need it.
Also, make sure you have internet permission in your app, make sure you have an active internet connection, etc, but it seems you already have.
Note: this is for OkHttp 2.x (since that's what I use), but it should be the same or similar for 3.x.
Let me know if it works for you.

Categories