diff --git a/src/main/java/tlschannel/impl/TlsChannelImpl.java b/src/main/java/tlschannel/impl/TlsChannelImpl.java index 82bbfcde..d47b96c9 100644 --- a/src/main/java/tlschannel/impl/TlsChannelImpl.java +++ b/src/main/java/tlschannel/impl/TlsChannelImpl.java @@ -103,7 +103,9 @@ public TlsChannelImpl( private final Lock readLock = new ReentrantLock(); private final Lock writeLock = new ReentrantLock(); - private volatile boolean negotiated = false; + private boolean handshakeStarted = false; + + private volatile boolean handshakeCompleted = false; /** * Whether a IOException was received from the underlying channel or from the {@link SSLEngine}. @@ -489,7 +491,7 @@ public void handshake() throws IOException { } private void doHandshake(boolean force) throws IOException, EofException { - if (!force && negotiated) { + if (!force && handshakeCompleted) { return; } initLock.lock(); @@ -497,15 +499,26 @@ private void doHandshake(boolean force) throws IOException, EofException { if (invalid || shutdownSent) { throw new ClosedChannelException(); } - if (force || !negotiated) { - logger.log(Level.FINEST, "Calling SSLEngine.beginHandshake()"); - engine.beginHandshake(); + if (force || !handshakeCompleted) { + + if (!handshakeStarted) { + logger.log(Level.FINEST, "Calling SSLEngine.beginHandshake()"); + engine.beginHandshake(); + + // Some engines that do not support renegotiations may be sensitive to calling + // SSLEngine.beginHandshake() more than once. This guard prevents that. + // See: https://github.com/marianobarrios/tls-channel/issues/197 + handshakeStarted = true; + } + writeAndHandshake(); if (engine.getSession().getProtocol().startsWith("DTLS")) { throw new IllegalArgumentException("DTLS not supported"); } + handshakeCompleted = true; + // call client code try { initSessionCallback.accept(engine.getSession()); @@ -513,7 +526,6 @@ private void doHandshake(boolean force) throws IOException, EofException { logger.log(Level.FINEST, "client code threw exception in session initialization callback", e); throw new TlsChannelCallbackException("session initialization callback failed", e); } - negotiated = true; } } finally { initLock.unlock();