I'm working on an app that connects two Android devices via Wifi so they can exchange files/data using TCP. Since Android Oreo (API level 26) there's finally an official API for this: WifiManager.startLocalOnlyHotspot(). This creates a Wifi hotspot/network without internet access. The documentation says:
Applications should also be aware that this network will be shared with other applications. Applications are responsible for protecting their data on this network (e.g., TLS).
I have no experience in using TLS when it comes to connecting two devices via TCP, so I searched around and found some approaches mentioning self-signed certificates. I'm not sure wether this is a good practice; I can't get it working anyway. Any help is appreciated!
What I did so far:
- I created a self-signed certificate using OpenSSL as described in this answer: - openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 10
- I created a new keystore with the latest (March 2018) Bouncy Castle provider .jar file and added - cert.pemto it. The following snippet is derived from this great blog article, more specifically from the sample app it features.- ALIAS=`openssl x509 -inform PEM -subject_hash -noout -in cert.pem` keytool -import -v -trustcacerts \ -alias $ALIAS \ -file cert.pem \ -keystore keystore_output_file \ -storetype BKS \ -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \ -providerpath bcprov-jdk15on-159.jar \ -storepass my_keystore_password
- I've added - keystore_output_fileto the- src/res/raw/folder of my app and initialized a- SSLContext. Then my app creates a- SSLServerSocketwhen acting as server or a- SSLSocketwhen acting as client. Originally I found this approach here.- // Exception handling omitted KeyStore keyStore = KeyStore.getInstance("BKS"); InputStream certStore = context.getResources().openRawResource(R.raw.keystore_output_file); keyStore.load(certStore, "my_keystore_password".toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, "my_key_password".toCharArray()); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());- ...continuing as server: - SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory(); SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(port); SSLSocket sslClientSocket = (SSLSocket) sslServerSocket.accept();- ...continuing as client: - SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(ipAddress, port); sslSocket.startHandshake();
The Problem:
The connection fails. There are different error messages depending on what version of Android the server device is running, but both are mentioning problems with ciphers. The Android versions of my testing devices are 4.3 and 7.1.1. The stacktraces are:
Server: Android 7.1.1
javax.net.ssl.SSLHandshakeException: Handshake failed                                                                                 
    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:429)                                         
    at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:682)                                       
    at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:644)                                         
    at com.candor.tlstcptest.ServerWorkerThread.run(ServerWorkerThread.java:46)                                  
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x8b0f8a40: Failure in SSL library, usually a protocol error
error:100000b8:SSL routines:OPENSSL_internal:NO_SHARED_CIPHER (external/boringssl/src/ssl/s3_srvr.c:1059 0x99b4286a:0x00000000)       
    at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)                                                         
    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357)      
Server: Android 4.3
javax.net.ssl.SSLException: Could not find any key store entries to support the enabled cipher suites.
    at org.apache.harmony.xnet.provider.jsse.OpenSSLServerSocketImpl.checkEnabledCipherSuites(OpenSSLServerSocketImpl.java:232)
    at org.apache.harmony.xnet.provider.jsse.OpenSSLServerSocketImpl.accept(OpenSSLServerSocketImpl.java:177)
    at com.candor.tlstcptest.ServerThread.run(ServerThread.java:71)
Now I'm stuck, I don't even know how to start to resolve this problem and I haven't yet found helpful information online. I wonder if there is really no offical documentation on this topic... As I said, any help is appreciated! Thanks
 
    