I have a HTTPS MEDIA server with self signed certificate from which I want to stream audio in my Android app. As per this link from developer.android.com, to allow self signed certificate, I have generated a certificate by reading the .crt file, created a keystore with this certificate and initialized this keyStore to a TrustManagerFactory.
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(getResources().openRawResource(R.raw.certificate));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
Log.d(TAG, "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);
The link describes an example to use this custom SSLContext with an HttpsURLConnection object.
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
But in my app for HTTP, I'm using MediaPlayer class by setting the audio link as below.
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(address); //address is a String variable like http://example.com/audio.aac
The question is, how do i use the above SSLContext's socketFactory object with the MediaPlayer, so that the MediaPlayer could use HTTPS audio source.
To use this custom SSLContext connection, we have to set the socketFactory object to the HttpsURLConnection before providing the source to the media player.
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
This allows the MediaPlayer to use the connection with our self signed certificate.
Other than this, I also had to provide a custom HostnameVerifier implementation to verify the subjectAlternateNames manually.
final HostnameVerifier hv =
HttpsURLConnection.getDefaultHostnameVerifier();
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return hv.verify("www.youdomainname.com", session);
}
};
And this custom HostnameVerifier could be linked to the MediaPlayer by the below code.
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
Related
I want to set a custom SSL certificate for my UrlTileProvider from the Google Maps Android API.
In my subclassed UrlTileProvider I'm setting the URL to the WMS of my Geoserver by https.
Can you tell me how to set the SSLContext by UrlTileProvider in order to use my SSL certificate?
I found the solution!
if I do not set the SocketFactory directly to a specific connection - I can define my socket factory as the DefaultSSLSocketFactory for HttpsURLConnections in general.
See:
Instead of applying this function:
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
I can add the Socket Factory per Default:
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = mContext.get().getAssets().
open("mycert.crt");
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("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);
sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
I have developed an android app where I am accessing one server url to access one xml file.In that server we have deployed one SelfSigned SSL Server Certificate.
I tried this code
// My Code:
My Code is here as follows
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = this.getResources().openRawResource(R.raw.server2); //server2 is the server2.crt Certificate file
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("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);
// Tell the URLConnection to use a SocketFactory from our SSLContext
HttpsURLConnection urlConnection =
(HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
But I am getting "javax.net.ssl.SSLHandshakeException: Handshake failed" Error.PLease help me how to access that URL?
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!
Hi I am working on android application where I am using https protocol in all the web service. so to communicate with https enabled server from android app do we need to add any certificate in my raw folder of android ?
If yes then what is the process of it. I checked many answers but people are simply ignoring the https procotol just accepting all certificates or by pass.
Thanks in advance.
Create BouncyCastle KeyStore, put your certificate in it (you can use openssl), later put created KeyStore into res/raw folder.
In app:
Load your keystore file into java KeyStore
Feed your HttpClient with your KeyStore
Example:
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("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);
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection =
(HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);
source:
https://developer.android.com/training/articles/security-ssl.html
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!