From 938081f1259b5c979b49cfd2e157db97f8572845 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 21 Jan 2018 03:16:35 +0100 Subject: [PATCH] hack to make PskKeyManager work on newer Android --- .../network/KeyTransferInteractor.java | 50 +----------- .../keychain/network/TlsPskCompat.java | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+), 49 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/TlsPskCompat.java diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferInteractor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferInteractor.java index c7f565970..1fb9e387d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferInteractor.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/KeyTransferInteractor.java @@ -31,8 +31,6 @@ import java.net.NoRouteToHostException; import java.net.Socket; import java.net.SocketTimeoutException; import java.net.URISyntaxException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; import java.util.Collections; @@ -40,22 +38,16 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import android.net.PskKeyManager; import android.os.Build.VERSION_CODES; import android.os.Handler; import android.os.Looper; import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLSocket; -import javax.net.ssl.TrustManager; import timber.log.Timber; @@ -159,7 +151,7 @@ public class KeyTransferInteractor { @Override public void run() { - SSLContext sslContext = createTlsPskSslContext(presharedKey); + SSLContext sslContext = TlsPskCompat.createTlsPskSslContext(presharedKey); Socket socket = null; try { @@ -225,18 +217,6 @@ public class KeyTransferInteractor { return socket; } - private static SSLContext createTlsPskSslContext(byte[] presharedKey) { - try { - PresharedKeyManager pskKeyManager = new PresharedKeyManager(presharedKey); - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(new KeyManager[] { pskKeyManager }, new TrustManager[0], null); - - return sslContext; - } catch (KeyManagementException | NoSuchAlgorithmException e) { - throw new IllegalStateException(e); - } - } - private void handleOpenConnection(Socket socket) throws IOException { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); OutputStream outputStream = new BufferedOutputStream(socket.getOutputStream()); @@ -443,34 +423,6 @@ public class KeyTransferInteractor { return ""; } - private static class PresharedKeyManager extends PskKeyManager implements KeyManager { - byte[] presharedKey; - - private PresharedKeyManager(byte[] presharedKey) { - this.presharedKey = presharedKey; - } - - @Override - public String chooseClientKeyIdentity(String identityHint, Socket socket) { - return identityHint; - } - - @Override - public String chooseClientKeyIdentity(String identityHint, SSLEngine engine) { - return identityHint; - } - - @Override - public SecretKey getKey(String identityHint, String identity, Socket socket) { - return new SecretKeySpec(presharedKey, "AES"); - } - - @Override - public SecretKey getKey(String identityHint, String identity, SSLEngine engine) { - return new SecretKeySpec(presharedKey, "AES"); - } - } - private static void closeQuietly(Closeable closeable) { try { if (closeable != null) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/TlsPskCompat.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/TlsPskCompat.java new file mode 100644 index 000000000..7a83eac34 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/TlsPskCompat.java @@ -0,0 +1,77 @@ +package org.sufficientlysecure.keychain.network; + + +import java.net.Socket; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; + +import android.os.Build.VERSION_CODES; +import android.support.annotation.RequiresApi; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManager; + + +@RequiresApi(api = VERSION_CODES.LOLLIPOP) +class TlsPskCompat { + + static SSLContext createTlsPskSslContext(byte[] presharedKey) { + try { + PresharedKeyManager pskKeyManager = new PresharedKeyManager(presharedKey); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(new KeyManager[] { pskKeyManager }, new TrustManager[0], null); + + return sslContext; + } catch (KeyManagementException | NoSuchAlgorithmException e) { + throw new IllegalStateException(e); + } + } + + @SuppressWarnings("unused") + /* This class is a KeyManager that is compatible to TlsPskManager. + * + * Due to the way conscrypt works internally, this class will be internally duck typed to + * PSKKeyManager. This is quite a hack, and relies on conscrypt internals to work - but it + * works. + * + * see also: + * https://github.com/google/conscrypt/blob/b23e9353ed4e3256379d660cb09491a69b21affb/common/src/main/java/org/conscrypt/SSLParametersImpl.java#L494 + * https://github.com/google/conscrypt/blob/29916ef38dc9cb4e4c6e3fdb87d4e921546d3ef4/common/src/main/java/org/conscrypt/DuckTypedPSKKeyManager.java#L51 + * + */ + private static class PresharedKeyManager implements KeyManager { + byte[] presharedKey; + + private PresharedKeyManager(byte[] presharedKey) { + this.presharedKey = presharedKey; + } + + public String chooseServerKeyIdentityHint(Socket socket) { + return null; + } + + public String chooseServerKeyIdentityHint(SSLEngine engine) { + return null; + } + + public String chooseClientKeyIdentity(String identityHint, Socket socket) { + return identityHint; + } + + public String chooseClientKeyIdentity(String identityHint, SSLEngine engine) { + return identityHint; + } + + public SecretKey getKey(String identityHint, String identity, Socket socket) { + return new SecretKeySpec(presharedKey, "AES"); + } + + public SecretKey getKey(String identityHint, String identity, SSLEngine engine) { + return new SecretKeySpec(presharedKey, "AES"); + } + } +}