I'm new on Android platform, coming from .NET world. I need to write a TCP/SSL client class in my app, which send/recieve text messages with some Java server. I also need to use server public certificate (.cer file) in that communication. In C# I have SSLStream class that do all the job, and a lot of examples for it. However for Android (Lolipop) I cannot find any good examples on this subject, especially without http protocol on top. Any hint would be appreciated.
-
Welcome to SO:SE. See How to Ask to understand how the site works and improve your post. Two comments... It seems you are asking without previous research on your side, and there are many tutorial on this basic topic online.mins– mins2015-04-26 08:43:51 +00:00Commented Apr 26, 2015 at 8:43
2 Answers
Below is basially steps to create ssl connection in android :
Step 1 : Get public key of ur server (.cert file), which you already have.
Step 2: Create keystore via bouncycastle jar
Below is commands :
keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/myKeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Verify if the certificates were imported correctly into the keystore:
keytool -list -keystore "res/raw/myKeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Should output the whole chain:
RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
Now you can copy the keystore as a raw resource in your android app under res/raw/
Step 3:
Create HttpsClient like below and query you service with this client only :
public class HttpsClient extends DefaultHttpClient {
final Context context;
public HttpsClient(Context context) {
this.context = context;
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
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 = context.getResources().openRawResource(
R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted
// certificates
// Also provide the password of the keystore
trusted.load(in, "mysecret".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is
// responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
The Above Case holds true for connection over http , if you need to have connection without http , the keystore procedure remains the same and you need to use sockets to open and close the connection :
String keyStorePath = "absolute path to your JKS keystore file";
String keyStorePass = "keystore password";
System.setProperty("javax.net.ssl.keyStore", keyStorePath);
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePass);
SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket serverSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(port_number);
while (true) {
new ClientThread((SSLSocket) serverSocket.accept()).start();
}
4 Comments
the KOTIOS answer Works!
For SSL sockets (not http)
use this code:
Socket socket = null;
SSLContext context = null;
char[] passphrase = "mysecret".toCharArray();
try{
KeyStore keystore = KeyStore.getInstance("BKS");
keystore.load(this.getApplication().getResources().openRawResource(R.raw.mykeystore), passphrase);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
tmf.init(keystore);
context = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = tmf.getTrustManagers();
context.init(null, trustManagers, null);
}catch (Exception e){
e.printStackTrace();
}
SSLSocketFactory sf = context.getSocketFactory();
socket = (SSLSocket) sf.createSocket(InetAddress.getByName(IP), DEFAULT_PORT);
and use this socket like a normal socket.