From 6cb363ffc6c515d1b9df760d31ee489b3877c4d5 Mon Sep 17 00:00:00 2001 From: Jonathan Keljo Date: Sun, 9 Mar 2014 17:30:02 -0400 Subject: [PATCH 1/2] Fix issue #853 DefaultSslContextFactory would ignore enabledCipherSuites unless you also specified enabledProtocols, due to a copy-paste error. --- .../src/org/restlet/engine/ssl/DefaultSslContextFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/org.restlet/src/org/restlet/engine/ssl/DefaultSslContextFactory.java b/modules/org.restlet/src/org/restlet/engine/ssl/DefaultSslContextFactory.java index ee444ce008..d1b7addff2 100644 --- a/modules/org.restlet/src/org/restlet/engine/ssl/DefaultSslContextFactory.java +++ b/modules/org.restlet/src/org/restlet/engine/ssl/DefaultSslContextFactory.java @@ -686,7 +686,7 @@ public void init(Series helperParameters) { enabledProtocols.toArray(enabledProtocolsArray); setEnabledProtocols(enabledProtocolsArray); } else { - setEnabledCipherSuites(null); + setEnabledProtocols(null); } setKeyManagerAlgorithm(helperParameters.getFirstValue( From e704f93c16da127780722bc1abba214a680a1dd9 Mon Sep 17 00:00:00 2001 From: Jonathan Keljo Date: Sun, 9 Mar 2014 18:03:28 -0400 Subject: [PATCH 2/2] Fix issues #852 and #862. - Issue #852: Android NIO server SSL handshake was hanging due to SSLEngine behaving differently on Android than on J2SE - Issue #862: Android and J2SE SSL server was hanging on close-notify due to SSLEngine going directly from NEED_WRAP to NOT_HANDSHAKING --- .../internal/channel/WritableSslChannel.java | 18 ++++++++++++-- .../internal/connection/SslConnection.java | 24 ++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/modules/org.restlet.ext.nio/src/org/restlet/ext/nio/internal/channel/WritableSslChannel.java b/modules/org.restlet.ext.nio/src/org/restlet/ext/nio/internal/channel/WritableSslChannel.java index b150145422..ce682308cd 100644 --- a/modules/org.restlet.ext.nio/src/org/restlet/ext/nio/internal/channel/WritableSslChannel.java +++ b/modules/org.restlet.ext.nio/src/org/restlet/ext/nio/internal/channel/WritableSslChannel.java @@ -113,8 +113,22 @@ public void onCompleted() { public int onFill(Buffer buffer, Object... args) throws IOException { int srcSize = buffer.remaining(); ByteBuffer applicationBuffer = (ByteBuffer) args[0]; - SSLEngineResult sslResult = getConnection().getSslEngine().wrap( - applicationBuffer, buffer.getBytes()); + + HandshakeStatus handshakeStatus = getConnection().getSslHandshakeStatus(); + SSLEngineResult sslResult; + + // Empty buffers should generally only be passed to SSLEngine during the handshaking process, + // when SSLEngine will be generating handshake packets itself. The behavior of SSLEngine when + // an empty buffer is passed during normal operation varies across platforms. To avoid problems + // due to this inconsistency, we avoid calling SSLEngine with empty buffers when not handshaking, + // and return what J2SE's SSLEngine would have in that case. See the following issue for more details: + // https://github.com/restlet/restlet-framework-java/issues/852 + if (applicationBuffer.hasRemaining() || handshakeStatus != HandshakeStatus.NOT_HANDSHAKING) { + sslResult = getConnection().getSslEngine().wrap(applicationBuffer, buffer.getBytes()); + } else { + sslResult = new SSLEngineResult(Status.BUFFER_OVERFLOW, handshakeStatus, 0, 0); + } + getConnection().setSslResult(sslResult); return srcSize - buffer.remaining(); } diff --git a/modules/org.restlet.ext.nio/src/org/restlet/ext/nio/internal/connection/SslConnection.java b/modules/org.restlet.ext.nio/src/org/restlet/ext/nio/internal/connection/SslConnection.java index f7adadbd48..8541c1c959 100644 --- a/modules/org.restlet.ext.nio/src/org/restlet/ext/nio/internal/connection/SslConnection.java +++ b/modules/org.restlet.ext.nio/src/org/restlet/ext/nio/internal/connection/SslConnection.java @@ -78,6 +78,9 @@ public class SslConnection extends Connection { /** The engine result. */ private volatile SSLEngineResult sslEngineResult; + /** Whether a handshake is in progress. */ + private volatile boolean isHandshaking; + /** * Constructor. * @@ -275,8 +278,25 @@ private void handleSslHandshake() throws IOException { getLogger().log(Level.FINER, "Handling SSL handshake: " + hs); } + if (isHandshaking && hs == HandshakeStatus.NOT_HANDSHAKING) { + // In some cases, on some platforms, the engine can go directly from a handshaking state to NOT_HANDSHAKING. + // We handle this situation as if it had returned FINISHED. See the following issues: + // https://github.com/restlet/restlet-framework-java/issues/852 + // and + // https://github.com/restlet/restlet-framework-java/issues/862 + hs = HandshakeStatus.FINISHED; + + if (getLogger().isLoggable(Level.FINER)) { + getLogger().log(Level.FINER, "SSLEngine went directly from handshaking to NOT_HANDSHAKING, " + + "treating as FINISHED."); + } + + } + if (hs != HandshakeStatus.NOT_HANDSHAKING) { - switch (getSslHandshakeStatus()) { + isHandshaking = true; + + switch (hs) { case FINISHED: onFinished(); break; @@ -371,6 +391,8 @@ public boolean isSslHandshaking() { * exchanged. */ private void onFinished() { + isHandshaking = false; + if (isClientSide()) { getInboundWay().setIoState(IoState.IDLE); getOutboundWay().setIoState(IoState.INTEREST);