aboutsummaryrefslogtreecommitdiffstats
path: root/AndroidAsync
diff options
context:
space:
mode:
authorKoushik Dutta <koushd@gmail.com>2014-07-13 18:06:22 -0700
committerKoushik Dutta <koushd@gmail.com>2014-07-13 18:06:22 -0700
commitd8a5060ca43c7efc5ff7b2b253791805cb928114 (patch)
tree2c347298ef8c7cf54ebeef20568e526dd4467367 /AndroidAsync
parenteb633ea9125ec9ddfbe99d04301b61cbbac3a507 (diff)
downloadAndroidAsync-d8a5060ca43c7efc5ff7b2b253791805cb928114.tar.gz
AndroidAsync-d8a5060ca43c7efc5ff7b2b253791805cb928114.tar.bz2
AndroidAsync-d8a5060ca43c7efc5ff7b2b253791805cb928114.zip
AsyncSSLSocketWrapper: Perform handshake before allowing read/write.
Diffstat (limited to 'AndroidAsync')
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java207
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/AsyncSSLSocketMiddleware.java22
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java14
3 files changed, 85 insertions, 158 deletions
diff --git a/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java b/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java
index 93c2865..bb6a167 100644
--- a/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java
+++ b/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java
@@ -28,129 +28,28 @@ import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket {
+ public interface HandshakeCallback {
+ public void onHandshakeCompleted(Exception e, AsyncSSLSocket socket);
+ }
+
static SSLContext defaultSSLContext;
AsyncSocket mSocket;
BufferedDataEmitter mEmitter;
BufferedDataSink mSink;
- boolean mUnwrapping = false;
+ boolean mUnwrapping;
+ SSLEngine engine;
+ boolean finishedHandshake;
+ private int mPort;
+ private String mHost;
+ private boolean mWrapping;
HostnameVerifier hostnameVerifier;
-
- /*
- private static void initTLS_1_2() {
- try {
- defaultSSLContext = SSLContext.getInstance("TLSv1.2");
- }
- catch (NoSuchAlgorithmException e) {
- }
- }
-
- private static void initTLS_1_1() {
- try {
- defaultSSLContext = SSLContext.getInstance("TLSv1.1");
- }
- catch (NoSuchAlgorithmException e) {
- }
- }
-
- private static void initTLS() {
- try {
- defaultSSLContext = SSLContext.getInstance("TLS");
- }
- catch (NoSuchAlgorithmException e) {
- }
- }
-
- static {
- try {
- initTLS_1_2();
- if (defaultSSLContext == null)
- initTLS_1_1();
- if (defaultSSLContext == null)
- initTLS();
- if (defaultSSLContext == null)
- defaultSSLContext = SSLContext.getInstance("SSL");
- // critical extension 2.5.29.15 is implemented improperly prior to 4.0.3.
- // https://code.google.com/p/android/issues/detail?id=9307
- // https://groups.google.com/forum/?fromgroups=#!topic/netty/UCfqPPk5O4s
- // certs that use this extension will throw in Cipher.java.
- // fallback is to use a custom SSLContext, and hack around the x509 extension.
- TrustManager[] trustManagers = null;
- if (Build.VERSION.SDK_INT <= 15) {
- trustManagers = new TrustManager[] { new X509TrustManager() {
- public java.security.cert.X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
-
- public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
- }
-
- public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
- for (X509Certificate cert : certs) {
- if (cert != null && cert.getCriticalExtensionOIDs() != null)
- cert.getCriticalExtensionOIDs().remove("2.5.29.15");
- }
- }
- } };
- }
- defaultSSLContext.init(null, trustManagers, null);
- }
- catch (Exception ex) {
- ex.printStackTrace();
- }
- }
-
- // android SSL cipher suites were downgraded (!!) for some derpy reason.
- // Paranoid people would be wise to enable the original/secure suites.
- // http://op-co.de/blog/posts/android_ssl_downgrade/
- public static final String RECOMMENDED_CIPHERS[] = {
- "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
- "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
- "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
- "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
- "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
- "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
- "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
- "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
- "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
- "TLS_RSA_WITH_AES_128_CBC_SHA",
- "TLS_RSA_WITH_AES_256_CBC_SHA",
- "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
- "SSL_RSA_WITH_RC4_128_SHA",
- "SSL_RSA_WITH_RC4_128_MD5",
- "TLS_RSA_WITH_AES_256_CBC_SHA256",
- };
-
- public static final String RECOMMENDED_PROTOCOLS[] = {
- "TLSv1"
- };
-
- public static void setupRecommendedEngineSecurity(SSLEngine engine) {
- LinkedHashSet<String> ciphers = new LinkedHashSet<String>(Arrays.asList(engine.getSupportedCipherSuites()));
- ciphers.addAll(Arrays.asList(engine.getSupportedCipherSuites()));
- LinkedHashSet<String> protocols = new LinkedHashSet<String>();
- protocols.addAll(Arrays.asList(engine.getSupportedProtocols()));
-
- ArrayList<String> enabledCiphers = new ArrayList<String>();
- for (String cipher: RECOMMENDED_CIPHERS) {
- if (ciphers.contains(cipher))
- enabledCiphers.add(cipher);
- }
-
- ArrayList<String> enabledProtocols = new ArrayList<String>();
- for (String protocol: RECOMMENDED_PROTOCOLS) {
- if (protocols.contains(protocol))
- enabledProtocols.add(protocol);
- }
-
- enabledCiphers.addAll(Arrays.asList(engine.getEnabledCipherSuites()));
- enabledProtocols.addAll(Arrays.asList(engine.getEnabledProtocols()));
-// engine.setEnabledCipherSuites(enabledCiphers.toArray(new String[enabledCiphers.size()]));
-// engine.setEnabledProtocols(enabledProtocols.toArray(new String[enabledProtocols.size()]));
-// engine.setEnabledCipherSuites(RECOMMENDED_CIPHERS);
- engine.setEnabledProtocols(new String[] {"SSL"});
- }
- */
+ HandshakeCallback handshakeCallback;
+ X509Certificate[] peerCertificates;
+ WritableCallback mWriteableCallback;
+ DataCallback mDataCallback;
+ TrustManager[] trustManagers;
+ boolean clientMode;
static {
// following is the "trust the system" certs setup
@@ -195,19 +94,25 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket
return defaultSSLContext.createSSLEngine();
}
- @Override
- public void end() {
- mSocket.end();
- }
-
- public AsyncSSLSocketWrapper(AsyncSocket socket, String host, int port) {
- this(socket, host, port, createDefaultSSLEngine(), null, null, true);
+ public static void handshake(AsyncSocket socket,
+ String host, int port,
+ SSLEngine sslEngine,
+ TrustManager[] trustManagers, HostnameVerifier verifier, boolean clientMode,
+ HandshakeCallback callback) {
+ AsyncSSLSocketWrapper wrapper = new AsyncSSLSocketWrapper(socket, host, port, sslEngine, trustManagers, verifier, clientMode);
+ wrapper.handshakeCallback = callback;
+ try {
+ wrapper.engine.beginHandshake();
+ wrapper.handleHandshakeStatus(wrapper.engine.getHandshakeStatus());
+ } catch (SSLException e) {
+ wrapper.report(e);
+ }
}
- TrustManager[] trustManagers;
- boolean clientMode;
-
- public AsyncSSLSocketWrapper(AsyncSocket socket, String host, int port, SSLEngine sslEngine, TrustManager[] trustManagers, HostnameVerifier verifier, boolean clientMode) {
+ private AsyncSSLSocketWrapper(AsyncSocket socket,
+ String host, int port,
+ SSLEngine sslEngine,
+ TrustManager[] trustManagers, HostnameVerifier verifier, boolean clientMode) {
mSocket = socket;
hostnameVerifier = verifier;
this.clientMode = clientMode;
@@ -277,7 +182,7 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket
bb.addFirst(b);
b = ByteBufferList.EMPTY_BYTEBUFFER;
}
- handleResult(res);
+ handleHandshakeStatus(res.getHandshakeStatus());
if (b.remaining() == remaining && before == transformed.remaining()) {
bb.addFirst(b);
break;
@@ -308,32 +213,30 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket
}
- SSLEngine engine;
- boolean finishedHandshake = false;
-
- private String mHost;
+ @Override
+ public void end() {
+ mSocket.end();
+ }
public String getHost() {
return mHost;
}
- private int mPort;
-
public int getPort() {
return mPort;
}
- private void handleResult(SSLEngineResult res) {
- if (res.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+ private void handleHandshakeStatus(HandshakeStatus status) {
+ if (status == HandshakeStatus.NEED_TASK) {
final Runnable task = engine.getDelegatedTask();
task.run();
}
- if (res.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
+ if (status == HandshakeStatus.NEED_WRAP) {
write(ByteBufferList.EMPTY_BYTEBUFFER);
}
- if (res.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP) {
+ if (status == HandshakeStatus.NEED_UNWRAP) {
mEmitter.onDataAvailable();
}
@@ -380,6 +283,11 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket
throw e;
}
}
+ else {
+ finishedHandshake = true;
+ }
+ handshakeCallback.onHandshakeCompleted(null, this);
+ handshakeCallback = null;
if (mWriteableCallback != null)
mWriteableCallback.onWriteable();
mEmitter.onDataAvailable();
@@ -403,7 +311,6 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket
assert !mWriteTmp.hasRemaining();
}
- private boolean mWrapping = false;
int calculateAlloc(int remaining) {
// alloc 50% more than we need for writing
@@ -445,7 +352,7 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket
else {
mWriteTmp = ByteBufferList.obtain(calculateAlloc(bb.remaining()));
}
- handleResult(res);
+ handleHandshakeStatus(res.getHandshakeStatus());
}
catch (SSLException e) {
report(e);
@@ -489,7 +396,7 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket
}
else {
mWriteTmp = ByteBufferList.obtain(calculateAlloc(bb.remaining()));
- handleResult(res);
+ handleHandshakeStatus(res.getHandshakeStatus());
}
}
catch (SSLException e) {
@@ -501,8 +408,6 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket
mWrapping = false;
}
- WritableCallback mWriteableCallback;
-
@Override
public void setWriteableCallback(WritableCallback handler) {
mWriteableCallback = handler;
@@ -514,13 +419,21 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket
}
private void report(Exception e) {
+ final HandshakeCallback hs = handshakeCallback;
+ if (hs != null) {
+ handshakeCallback = null;
+ mSocket.setDataCallback(new NullDataCallback());
+ mSocket.end();
+ mSocket.close();
+ hs.onHandshakeCompleted(e, null);
+ return;
+ }
+
CompletedCallback cb = getEndCallback();
if (cb != null)
cb.onCompleted(e);
}
- DataCallback mDataCallback;
-
@Override
public void setDataCallback(DataCallback callback) {
mDataCallback = callback;
@@ -596,8 +509,6 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket
return mSocket;
}
- X509Certificate[] peerCertificates;
-
@Override
public X509Certificate[] getPeerCertificates() {
return peerCertificates;
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncSSLSocketMiddleware.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncSSLSocketMiddleware.java
index 4f3fff7..868afc6 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncSSLSocketMiddleware.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncSSLSocketMiddleware.java
@@ -4,6 +4,7 @@ import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
+import com.koushikdutta.async.AsyncSSLSocket;
import com.koushikdutta.async.AsyncSSLSocketWrapper;
import com.koushikdutta.async.AsyncSocket;
import com.koushikdutta.async.LineEmitter;
@@ -70,6 +71,17 @@ public class AsyncSSLSocketMiddleware extends AsyncSocketMiddleware {
return sslEngine;
}
+ protected void tryHandshake(final ConnectCallback callback, AsyncSocket socket, final Uri uri, final int port) {
+ AsyncSSLSocketWrapper.handshake(socket, uri.getHost(), port,
+ createConfiguredSSLEngine(uri.getHost(), port),
+ trustManagers, hostnameVerifier, true, new AsyncSSLSocketWrapper.HandshakeCallback() {
+ @Override
+ public void onHandshakeCompleted(Exception e, AsyncSSLSocket socket) {
+ callback.onConnectCompleted(e, socket);
+ }
+ });
+ }
+
@Override
protected ConnectCallback wrapCallback(final ConnectCallback callback, final Uri uri, final int port, final boolean proxied) {
return new ConnectCallback() {
@@ -77,10 +89,7 @@ public class AsyncSSLSocketMiddleware extends AsyncSocketMiddleware {
public void onConnectCompleted(Exception ex, final AsyncSocket socket) {
if (ex == null) {
if (!proxied) {
- callback.onConnectCompleted(null,
- new AsyncSSLSocketWrapper(socket, uri.getHost(), port,
- createConfiguredSSLEngine(uri.getHost(), port),
- trustManagers, hostnameVerifier, true));
+ tryHandshake(callback, socket, uri, port);
}
else {
// this SSL connection is proxied, must issue a CONNECT request to the proxy server
@@ -112,10 +121,7 @@ public class AsyncSSLSocketMiddleware extends AsyncSocketMiddleware {
socket.setDataCallback(null);
socket.setEndCallback(null);
if (TextUtils.isEmpty(s.trim())) {
- callback.onConnectCompleted(null,
- new AsyncSSLSocketWrapper(socket, uri.getHost(), port,
- createConfiguredSSLEngine(uri.getHost(), port),
- trustManagers, hostnameVerifier, true));
+ tryHandshake(callback, socket, uri, port);
}
else {
callback.onConnectCompleted(new IOException("unknown second status line"), socket);
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java
index 8d139ef..b1b393d 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java
@@ -1,9 +1,12 @@
package com.koushikdutta.async.http.server;
+import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.AssetManager;
+import android.os.Build;
import android.text.TextUtils;
+import com.koushikdutta.async.AsyncSSLSocket;
import com.koushikdutta.async.AsyncSSLSocketWrapper;
import com.koushikdutta.async.AsyncServer;
import com.koushikdutta.async.AsyncServerSocket;
@@ -39,6 +42,7 @@ import java.util.regex.Pattern;
import javax.net.ssl.SSLContext;
+@TargetApi(Build.VERSION_CODES.ECLAIR)
public class AsyncHttpServer {
ArrayList<AsyncServerSocket> mListeners = new ArrayList<AsyncServerSocket>();
public void stop() {
@@ -223,8 +227,14 @@ public class AsyncHttpServer {
AsyncServer.getDefault().listen(null, port, new ListenCallback() {
@Override
public void onAccepted(AsyncSocket socket) {
- AsyncSSLSocketWrapper sslSocket = new AsyncSSLSocketWrapper(socket, null, port, sslContext.createSSLEngine(), null, null, false);
- mListenCallback.onAccepted(sslSocket);
+ AsyncSSLSocketWrapper.handshake(socket, null, port, sslContext.createSSLEngine(), null, null, false,
+ new AsyncSSLSocketWrapper.HandshakeCallback() {
+ @Override
+ public void onHandshakeCompleted(Exception e, AsyncSSLSocket socket) {
+ if (socket != null)
+ mListenCallback.onAccepted(socket);
+ }
+ });
}
@Override