Skip to content

Commit

Permalink
Fix bug that made an2linux unusable on kitkat
Browse files Browse the repository at this point in the history
Was trying to use unsupported ciphers for android kitkat users

Also needed to change a little in the implementation for SSLEngine,
apparantly it works differently on api 19

For example with api 19 it needs to do multiple unwrap but on api 23
one unwrap was necessary
  • Loading branch information
rootkiwi committed Jan 7, 2017
1 parent c0ddfc6 commit d7ca076
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 21 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ android {
applicationId "kiwi.root.an2linuxclient"
minSdkVersion 19
targetSdkVersion 25
versionCode 1
versionName "0.1"
versionCode 2
versionName "0.1.1"
}
buildTypes {
release {
Expand Down
71 changes: 60 additions & 11 deletions app/src/main/java/kiwi/root/an2linuxclient/crypto/TlsHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.util.Base64;
import android.util.Log;

Expand Down Expand Up @@ -52,14 +53,22 @@

public class TlsHelper {

// TLSv1.2 -> API_16+ but with SSLEngine it's API_20+
public static final String[] TLS_VERSIONS = new String[]{"TLSv1.2"};

// TLSv1 -> API_1+ used with SSLEngine on Android 4.4 (API_19)
public static final String[] TLS_VERSIONS_COMPAT_BT = new String[]{"TLSv1"};

// TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 -> API_20+
// TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA -> API_11+
public static final String[] TLS_CIPHERS = new String[]{"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"};
public static final String[] TLS_CIPHERS = new String[]{"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"};

static void initialiseCertificate(SharedPreferences deviceKeyPref, KeyPair keyPair){
// TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA -> API_11+ but with SSLEngine it's API_20+
public static final String[] TLS_CIPHERS_COMPAT = new String[]{"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"};

// TLS_DHE_RSA_WITH_AES_256_CBC_SHA -> API_9+ used with SSLEngine on Android 4.4 (API_19)
public static final String[] TLS_CIPHERS_COMPAT_BT = new String[]{"TLS_DHE_RSA_WITH_AES_256_CBC_SHA"};

static void initialiseCertificate(SharedPreferences deviceKeyPref, KeyPair keyPair){
X509Certificate certificate;

Calendar calendar = Calendar.getInstance();
Expand Down Expand Up @@ -98,7 +107,7 @@ static void initialiseCertificate(SharedPreferences deviceKeyPref, KeyPair keyPa

}

public static X509Certificate getCertificate(Context c){
private static X509Certificate getCertificate(Context c){
SharedPreferences deviceKeyPref = c.getSharedPreferences("device_key_and_cert", MODE_PRIVATE);
try {
byte[] certificateBytes = Base64.decode(deviceKeyPref.getString("certificate", ""), Base64.DEFAULT);
Expand Down Expand Up @@ -126,7 +135,7 @@ public static byte[] certificateToBytes(Certificate certificate){
}
}

public static SSLContext getPairingTlsContext(Context c){
public static SSLContext getPairingTlsContext(){
try {
SSLContext tlsContext = SSLContext.getInstance(TLS_VERSIONS[0]);

Expand Down Expand Up @@ -182,7 +191,15 @@ public static SSLEngineResult.HandshakeStatus doHandshake(SSLEngine tlsEngine,
OutputStream out,
InputStream in){
try {
ByteBuffer empty = ByteBuffer.allocate(0);
ByteBuffer empty;
/*Apparently on Android 4.4 (API_19) SSLEngine whines about BUFFER_OVERFLOW for this
buffer even though nothing ever gets written to it*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH){
empty = ByteBuffer.allocate(0);
} else {
empty = ByteBuffer.allocate(tlsEngine.getSession().getApplicationBufferSize());
}

// ClientHello -> netDataBuf
tlsEngine.wrap(empty, netDataBuf);
netDataBuf.flip();
Expand All @@ -197,11 +214,22 @@ public static SSLEngineResult.HandshakeStatus doHandshake(SSLEngine tlsEngine,
netDataBuf.clear();
netDataBuf.put(serverHello);
netDataBuf.flip();
tlsEngine.unwrap(netDataBuf, empty);
SSLEngineResult result = tlsEngine.unwrap(netDataBuf, empty);
while (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP){
result = tlsEngine.unwrap(netDataBuf, empty);
}
Runnable task = tlsEngine.getDelegatedTask();
while (task != null){
task.run();
task = tlsEngine.getDelegatedTask();
}

// [client]Certificate*..ClientKeyExchange..Finished -> netDataBuf
netDataBuf.clear();
tlsEngine.wrap(empty, netDataBuf);
result = tlsEngine.wrap(empty, netDataBuf);
while (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP){
result = tlsEngine.wrap(empty, netDataBuf);
}
netDataBuf.flip();
byte[] clientKeyExchange = new byte[netDataBuf.limit()];
netDataBuf.get(clientKeyExchange);
Expand All @@ -214,7 +242,25 @@ public static SSLEngineResult.HandshakeStatus doHandshake(SSLEngine tlsEngine,
netDataBuf.clear();
netDataBuf.put(serverChangeCipherSpec);
netDataBuf.flip();
return tlsEngine.unwrap(netDataBuf, empty).getHandshakeStatus();
result = tlsEngine.unwrap(netDataBuf, empty);
while (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP){
result = tlsEngine.unwrap(netDataBuf, empty);
}

/*Apparently on Android 4.4 (API_19) with SSLEngine the latest call tlsEngine.unwrap(..)
that finishes the handshake returns NOT_HANDSHAKING instead of FINISHED as the result*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH){
return result.getHandshakeStatus();
} else {
if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING){
return SSLEngineResult.HandshakeStatus.FINISHED;
} else if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) {
// just in case
return result.getHandshakeStatus();
} else {
return null;
}
}
} catch (IOException e){
return null;
}
Expand Down Expand Up @@ -250,7 +296,10 @@ public static byte[] tlsDecrypt(SSLEngine tlsEngine,
netDataBuf.clear();
netDataBuf.put(netData);
netDataBuf.flip();
tlsEngine.unwrap(netDataBuf, appDataBuf);
int consumed = tlsEngine.unwrap(netDataBuf, appDataBuf).bytesConsumed();
while (consumed < netData.length){
consumed += tlsEngine.unwrap(netDataBuf, appDataBuf).bytesConsumed();
}
appDataBuf.flip();
byte[] appData = new byte[appDataBuf.limit()];
appDataBuf.get(appData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.SystemClock;
import android.util.Log;

Expand Down Expand Up @@ -49,8 +50,13 @@ class BluetoothNotificationConnection extends NotificationConnection implements
private void createTlsEngine(){
tlsEngine = TlsHelper.getNotificationTlsContext(c, serverCert).createSSLEngine();
tlsEngine.setUseClientMode(true);
tlsEngine.setEnabledProtocols(TlsHelper.TLS_VERSIONS);
tlsEngine.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH){
tlsEngine.setEnabledProtocols(TlsHelper.TLS_VERSIONS);
tlsEngine.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS);
} else {
tlsEngine.setEnabledProtocols(TlsHelper.TLS_VERSIONS_COMPAT_BT);
tlsEngine.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS_COMPAT_BT);
}
}

private void createBuffers(){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Build;
import android.os.SystemClock;
import android.util.Log;

Expand Down Expand Up @@ -67,10 +68,15 @@ void denyPairing() {
}

private void createTlsEngine(){
tlsEngine = TlsHelper.getPairingTlsContext(c).createSSLEngine();
tlsEngine = TlsHelper.getPairingTlsContext().createSSLEngine();
tlsEngine.setUseClientMode(true);
tlsEngine.setEnabledProtocols(TlsHelper.TLS_VERSIONS);
tlsEngine.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH){
tlsEngine.setEnabledProtocols(TlsHelper.TLS_VERSIONS);
tlsEngine.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS);
} else {
tlsEngine.setEnabledProtocols(TlsHelper.TLS_VERSIONS_COMPAT_BT);
tlsEngine.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS_COMPAT_BT);
}
}

private void createBuffers(){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.util.Log;

import java.io.BufferedInputStream;
Expand Down Expand Up @@ -52,7 +53,11 @@ public void run(){
.createSocket(s, serverAddress, serverPort, true);
tlsSocket.setUseClientMode(true);
tlsSocket.setEnabledProtocols(TlsHelper.TLS_VERSIONS);
tlsSocket.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH){
tlsSocket.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS);
} else {
tlsSocket.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS_COMPAT);
}

try {
tlsSocket.startHandshake();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package kiwi.root.an2linuxclient.network;

import android.content.Context;
import android.os.Build;
import android.util.Log;

import java.io.IOException;
Expand Down Expand Up @@ -87,11 +88,15 @@ public void run() {

mOut.write(INITIATE_PAIRING);

SSLSocket tlsSocket = (SSLSocket) TlsHelper.getPairingTlsContext(c).getSocketFactory()
SSLSocket tlsSocket = (SSLSocket) TlsHelper.getPairingTlsContext().getSocketFactory()
.createSocket(s, serverAddress, serverPort, true);
tlsSocket.setUseClientMode(true);
tlsSocket.setEnabledProtocols(TlsHelper.TLS_VERSIONS);
tlsSocket.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH){
tlsSocket.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS);
} else {
tlsSocket.setEnabledCipherSuites(TlsHelper.TLS_CIPHERS_COMPAT);
}

final byte[] clientCertBytes = TlsHelper.getCertificateBytes(c);
tlsSocket.addHandshakeCompletedListener(new HandshakeCompletedListener() {
Expand Down

0 comments on commit d7ca076

Please sign in to comment.