I am totally new on this and after some research, trying to make a SSL/TLS connection with server to allow SOAP call outside defined network. I am using OKHttp3 library to make the call and sharing a .P12 file with private key and setting a SSL Socket Factory as shown below
setupKeyCert(context);
final OkHttpClient client = new OkHttpClient();
client.newBuilder()
.connectTimeout(30, TimeUnit.SECONDS)
.sslSocketFactory(sslContext.getSocketFactory(), mainX509TrustManager);
and setting keystone and Trust Manager in
setupKeyCert()
as
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
KeyManagerFactory keyManagerFactory = null;
if(buildEnvironment == "prod")
{
keyStore.load(context.getAssets().open(Constants.CERT_PROD_FILE), password);
keyManagerFactory = KeyManagerFactory.getInstance("X509");
keyManagerFactory.init(keyStore, Constants.CERT_PROD_VALUE.toCharArray());
} else
{
keyStore.load(context.getAssets().open(Constants.CERT_FILE), Constants.CERT_VALUE.toCharArray());
keyManagerFactory = KeyManagerFactory.getInstance("X509");
keyManagerFactory.init(keyStore, Constants.CERT_VALUE.toCharArray());
}
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
//Adding TrustManagerFactory
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
mainX509TrustManager = (X509TrustManager) trustManagers[0];
sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(keyManagers, null, null);
} catch (FileNotFoundException f)
{
Log.e("Excption File", String.valueOf(f));
} catch (Exception i)
{
Log.e(TAG, "Exception", i);
}
Where Constant.CERT_PROD_FILE refers to constant string which contain file name.
When debugging or making call, I am getting below error
javax.net.ssl.SSLProtocolException: SSL handshake terminated:
ssl=0x8a163cc0: Failure in SSL library, usually a protocol error
error:10000410:SSL
routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE
(external/boringssl/src/ssl/s3_pkt.c:610 0x9f7e3d00:0x00000001)
I am not sure what am I missing and I have tried different solution including bug related to android 7 issue but it's still not working. I tried to debug and can only see the above error, so not sure if the issue is with server or client. Thanks for help in advance.
Related
Android self-signed client side CA certificate authentication fails, Can anyone share their experience dealing with similar issues? With the same credentials we are able to get it to work using CURL client.
We followed this GIST however we could not get through it.
Following it just led us to have this exception gets thrown:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374)
Try the following code
// Input stream for self signed CA certificate
InputStream caIs = getInputStream(caCert);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(caIs);
String alias = certificate.getSubjectX500Principal().getName();
Log.d(TAG, String.format("Alias: %s", alias));
// KeyStore for trusted CA certificate(s)
KeyStore trustedStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustedStore.load(null);
trustedStore.setCertificateEntry(alias, certificate);
// Create trust managers to be used for connecting to servics(s)
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustedStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
// KeyStore for X.509 certificate/key
KeyStore keyStore = KeyStore.getInstance("PKCS12");
InputStream clientIs = getInputStream(clientKeyCert);
keyStore.load(clientIs, "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, "password".toCharArray());
// Create key managers to be uses for connecting to service(s)
KeyManager[] keyManagers = kmf.getKeyManagers();
// Create the SSL context
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
// Test by connecting ta server proteced by self signed certificate
OkHttpClient client = new OkHttpClient.Builder().sslSocketFactory(sslContext.getSocketFactory()).build();
Call call = client.newCall(new Request.Builder().url("https://testurl.com").build());
Response response = call.execute();
Log.d(TAG, response.message());
I'm trying to develop an app to communicate with amazon alexa using OKhttp3. Everything was working fine while I was trying the app on an android API 26.
But once I started using an android API 19 every request to https://avs-alexa-na.amazon.com/ started failing.
Before working for API 19 this was how I used this function to open the down channel.
final String url = "https://avs-alexa-na.amazon.com/";
final String version = "v20160207";
final Request request = new Request.Builder()
.get()
.header("Authorization", "Bearer " + myApplication.getAccessToken())
.url(url + version + "/directives")
.build();
try {
final OkHttpClient client = new OkHttpClient();
Response response = client.newCall(request).execute();
Log.i("Down channel", "opened");
} catch (Exception ex) {
Log.e("Down channel", "error Sending request " + ex.getLocalizedMessage());
}
But now this same function returns javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb969de80: Failure in SSL library, usually a protocol error error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x8d954990:0x00000000)
So after following some posts on line I learned that android 19 doesn't install by default TLSv1.2 so I added a function to install it and started having this error :unexpected end of stream on Connection{avs-alexa-na.amazon.com:443, proxy=DIRECT# hostAddress=avs-alexa-na.amazon.com/54.239.39.74:443 cipherSuite=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 protocol=http/1.1}
I started exploring other ways working with certificates (my certificate, and the one from amazon gotten by openssl s_client -connect avs-alexa-eu.amazon.com:443:
SSLContext sslContext;
TrustManager[] trustManagers;
try {
final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
final InputStream certInputStream = activity.getResources().openRawResource(R.raw.cert);
InputStream avscertInputStream = activity.getResources().openRawResource(R.raw.amazon_avs_cert);
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
final Certificate cert = certificateFactory.generateCertificate(certInputStream);
final Certificate avscert = certificateFactory.generateCertificate(avscertInputStream);
keyStore.setCertificateEntry("amazon_avs", avscert);
keyStore.setCertificateEntry("cert", cert);
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
trustManagers = trustManagerFactory.getTrustManagers();
sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, trustManagers, null);
return new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagers[0])
.build();
} catch (Exception e) {
e.printStackTrace();
return new OkHttpClient();
}
But it led to a java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
I'm lost, I don't know what I did wrong or what I did not do. Thanks for you help.
i have implemented the certificate and keystore to my app and succeeded in making request to my server , but now i want to accept another server's HTTPS (for online payment) to be able to integrate it in my app but volley says that it doesn't accept it , can i accept this domain without their keystore
and this is my code for accepting my server's certificate
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = getApplicationContext().getResources().openRawResource(R.raw.keystore);
try {
// Initialize the keystore with the provided trusted certificates
// Provide the password of the keystore
trusted.load(in, KEYSTORE_PASSWORD);
} finally {
in.close();
}
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(trusted);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory sf = context.getSocketFactory();
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
I'm writing an Android's app with SSL connection (not HTTP). I read a lot of tutorials about HTTPS in Android but it keeping product error "SSL socket factory is abstract cannot be instantiated." with SSLSocketFactory sf = new SSLSocketFactory(truststore).
My question is: How can I add key store to Android?.
This is my example:
public void run() {
try {
KeyStore trusted = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.keystore);
try {
trusted.load(in, "1234567".toCharArray());
SSLSocketFactory sSLSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); // <<<<< Line 40
SSLSocket sslSocket = (SSLSocket) sSLSocketFactory.createSocket("10.0.2.2", 9998);
sslSocket.startHandshake();
Log.i("SSLsocket", "true");
} finally {
in.close();
}
} catch (Exception e) {
throw new AssertionError(e);
}
}
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:322)
at com.example.begood.voip.SSlconnection.run(SSlconnection.java:40)
Try something like this, given your trustStore:
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(trustStore, "password".toCharArray());
KeyManager[] keymanagers = kmfactory.getKeyManagers();
TrustManagerFactory tmf=TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
SSLContext sslContext=SSLContext.getInstance("TLSv1.2");
sslContext.init(keymanagers, tmf.getTrustManagers(), new SecureRandom());
SSLSocketFactory factory=sslContext.getSocketFactory();
I successfully got the server to use a certificate in the form of a JKS file. HTTPS is working as expected when used with web browsers and other web clients.
For Android, my team uses the following to persuade OkHttp to accept the certificate.
static KeyStore readKeyStore() throws KeyStoreException, CertificateException, NoSuchAlgorithmException
{
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
// get user password and file input stream
char[] password = "password".toCharArray();
java.io.InputStream fis = null;
try {
fis = ServiceProducer.class.getClassLoader().getResourceAsStream("res/raw/keystore.jks");
ks.load(fis, password);
} catch (IOException e)
{
} finally
{
if (fis != null)
{
try
{
fis.close();
} catch (IOException e)
{
}
}
}
return ks;
}
The code that uses the key:
OkHttpClient.Builder builder = new OkHttpClient.Builder();
KeyStore keyStore = readKeyStore();
SSLContext sslContext = SSLContext.getInstance("SSL");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "password".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
builder.sslSocketFactory(sslContext.getSocketFactory());
OkHttpClient client = builder.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://192.168.5.91:9443")
.addConverterFactory(JacksonConverterFactory.create())
.client(client)
.build();
However, accessing the service throws the following exception:
java.security.cert.CertPathValidationException: Trust anchor for certification path not found.
Have we done the certificate installation correctly? Or are we facing a different kind of problem?