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();
Related
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.
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 currently developing an Android app (Android Studio 2.0), that will connect to my server (Glassfish 4.1, Netbeans 8.1) through HTTPS (using javax.net.ssl.HttpsURLConnection). This is currently all being run on my local network (smartphone + laptop). The problem I'm getting now is:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
I think because my Android application doesn't trust the server yet. How do I go about so it does indeed trust the server?
In some official documentation (http://developer.android.com/training/articles/security-ssl.html) and other guides, I've seen getting Keystores mentioned, or using .crt files. But where do I get either of those and how do I get them on my mobile device?
Currently my code looks like:
public static HttpsURLConnection setupHttpsConnection(URL url, Context context) {
try {
// Load CAs from an InputStream
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(context.getAssets().open("localhost.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
Log.d(LOG_TAG, "> setupHttpsConnection > ca.getSubjectDN = " + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
/*
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
HostnameVerifier hv =
HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify("192.168.0.121", session);
}
};
*/
// Tell the URLConnection to use a SocketFactory from our SSLContext
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
//urlConnection.setHostnameVerifier(hostnameVerifier);
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
return urlConnection;
} catch (Exception e) {
e.printStackTrace();
Log.d(LOG_TAG, e.toString());
return null;
}
}
Then in another place I call:
urlConnection = Utility.setupHttpsConnection(url, context);
urlConnection.connect(); // <-- Exception thrown here!
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?
I have my own PKI infrastructure for my web server with a CA and an intermediate CA. Then I have a web certificate signed by the intermediate CA and I want my app to communicate with the server. According to the Developer docs the solution is to create my own keystore. So I bundled the root CA certificate with the app and tried to see if that would work. It didnt, and I got the following error:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
So my question is this. Since the SSL certificate is signed by my intermediate CA, is that the certificate I should be importing into the custom key store, or do I need both, or is there something else wrong here?
Ultimately, with a SSL certificate signed by a CA not trusted by Android, is this the right way to go about it?
Thanks!
Here's the code that sets up the keystore manager.
public SSLContext getTrusted() throws Exception{
// Load CAs from an InputStream
CertificateFactory cf = CertificateFactory.getInstance("X.509");
AssetManager assManager = context.getAssets();
InputStream is = null;
try {
is = assManager.open("ca.cert.crt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
InputStream caInput = new BufferedInputStream(is);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
Log.d("TrustMan", "ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
return context;
}
And then I am trying to use it as follows.
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
TrustMan tm = new TrustMan(context);
SSLContext sslContext;
sslContext = tm.getTrusted();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
The code did actually work, but not when I returned the SSLContext from my class. I adjusted the class to return the TrustManagerFactory instead, and using the intermediate CA certificate works fine now!
Thanks!