From 8b8e1bc71d1d452998f7d92f3e1ec34e5439c880 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 10 Feb 2012 11:11:56 +0000
Subject: [PATCH] Preparation work for OPENDJ-420: Rare SSLExceptions while handling LDAPS connections and big LDAP searches

---
 opends/src/server/org/opends/server/extensions/TLSByteChannel.java |  416 ++++++++++------------------------------------------------
 1 files changed, 74 insertions(+), 342 deletions(-)

diff --git a/opends/src/server/org/opends/server/extensions/TLSByteChannel.java b/opends/src/server/org/opends/server/extensions/TLSByteChannel.java
index ad2b96e..53741c8 100644
--- a/opends/src/server/org/opends/server/extensions/TLSByteChannel.java
+++ b/opends/src/server/org/opends/server/extensions/TLSByteChannel.java
@@ -53,49 +53,86 @@
 /**
  * A class that provides a TLS byte channel implementation.
  */
-public class TLSByteChannel implements ByteChannel, ConnectionSecurityProvider
+public class TLSByteChannel implements ConnectionSecurityProvider
 {
+  /**
+   * Private implementation.
+   */
+  private final class ByteChannelImpl implements ByteChannel
+  {
+
+    /**
+     * {@inheritDoc}
+     */
+    public int read(ByteBuffer dst) throws IOException
+    {
+      // TODO Auto-generated method stub
+      return 0;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isOpen()
+    {
+      // TODO Auto-generated method stub
+      return false;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException
+    {
+      // TODO Auto-generated method stub
+
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int write(ByteBuffer src) throws IOException
+    {
+      // TODO Auto-generated method stub
+      return 0;
+    }
+
+  }
+
+
+
   private static final DebugTracer TRACER = getTracer();
-
   private final ByteChannel socketChannel;
-
   private final SSLEngine sslEngine;
+  private final ByteChannelImpl pimpl = new ByteChannelImpl();
 
-  // read copy to buffer
-  private final ByteBuffer appData;
-
-  // read encrypted
-  private final ByteBuffer appNetData;
-
-  // Write encrypted
-  private final ByteBuffer netData;
-  private final ByteBuffer tempData;
-
-  private final int sslBufferSize;
-  private final int appBufSize;
-
-  private boolean reading = false;
 
   // Map of cipher phrases to effective key size (bits). Taken from the
   // following RFCs: 5289, 4346, 3268,4132 and 4162.
-  private static final Map<String, Integer> cipherMap;
+  private static final Map<String, Integer> CIPHER_MAP;
   static
   {
-    cipherMap = new LinkedHashMap<String, Integer>();
-    cipherMap.put("_WITH_AES_256_CBC_", new Integer(256));
-    cipherMap.put("_WITH_CAMELLIA_256_CBC_", new Integer(256));
-    cipherMap.put("_WITH_AES_256_GCM_", new Integer(256));
-    cipherMap.put("_WITH_3DES_EDE_CBC_", new Integer(112));
-    cipherMap.put("_WITH_AES_128_GCM_", new Integer(128));
-    cipherMap.put("_WITH_SEED_CBC_", new Integer(128));
-    cipherMap.put("_WITH_CAMELLIA_128_CBC_", new Integer(128));
-    cipherMap.put("_WITH_AES_128_CBC_", new Integer(128));
-    cipherMap.put("_WITH_IDEA_CBC_", new Integer(128));
-    cipherMap.put("_WITH_DES_CBC_", new Integer(56));
-    cipherMap.put("_WITH_RC2_CBC_40_", new Integer(40));
-    cipherMap.put("_WITH_RC4_40_", new Integer(40));
-    cipherMap.put("_WITH_DES40_CBC_", new Integer(40));
-    cipherMap.put("_WITH_NULL_", new Integer(0));
+    CIPHER_MAP = new LinkedHashMap<String, Integer>();
+    CIPHER_MAP.put("_WITH_AES_256_CBC_", new Integer(256));
+    CIPHER_MAP.put("_WITH_CAMELLIA_256_CBC_", new Integer(256));
+    CIPHER_MAP.put("_WITH_AES_256_GCM_", new Integer(256));
+    CIPHER_MAP.put("_WITH_3DES_EDE_CBC_", new Integer(112));
+    CIPHER_MAP.put("_WITH_AES_128_GCM_", new Integer(128));
+    CIPHER_MAP.put("_WITH_SEED_CBC_", new Integer(128));
+    CIPHER_MAP.put("_WITH_CAMELLIA_128_CBC_", new Integer(128));
+    CIPHER_MAP.put("_WITH_AES_128_CBC_", new Integer(128));
+    CIPHER_MAP.put("_WITH_IDEA_CBC_", new Integer(128));
+    CIPHER_MAP.put("_WITH_DES_CBC_", new Integer(56));
+    CIPHER_MAP.put("_WITH_RC2_CBC_40_", new Integer(40));
+    CIPHER_MAP.put("_WITH_RC4_40_", new Integer(40));
+    CIPHER_MAP.put("_WITH_DES40_CBC_", new Integer(40));
+    CIPHER_MAP.put("_WITH_NULL_", new Integer(0));
   };
 
 
@@ -137,9 +174,11 @@
     // avoid blocking new connections. Just remove for now to prevent
     // potential DoS attacks. SSL sessions will not be reused and some
     // cipher suites (such as Kerberos) will not work.
+
     // String hostName = socketChannel.socket().getInetAddress().getHostName();
     // int port = socketChannel.socket().getPort();
     // sslEngine = sslContext.createSSLEngine(hostName, port);
+
     sslEngine = sslContext.createSSLEngine();
     sslEngine.setUseClientMode(false);
     final Set<String> protocols = config.getSSLProtocol();
@@ -170,44 +209,6 @@
       sslEngine.setWantClientAuth(true);
       break;
     }
-
-    final SSLSession sslSession = sslEngine.getSession();
-    sslBufferSize = sslSession.getPacketBufferSize();
-    appBufSize = sslSession.getApplicationBufferSize();
-
-    appNetData = ByteBuffer.allocate(sslBufferSize);
-    netData = ByteBuffer.allocate(sslBufferSize);
-
-    appData = ByteBuffer.allocate(sslSession.getApplicationBufferSize());
-    tempData = ByteBuffer.allocate(sslSession.getApplicationBufferSize());
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public synchronized void close() throws IOException
-  {
-    sslEngine.closeInbound();
-    sslEngine.closeOutbound();
-    final SSLEngineResult.HandshakeStatus hsStatus = sslEngine
-        .getHandshakeStatus();
-    if (hsStatus != SSLEngineResult.HandshakeStatus.FINISHED
-        && hsStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
-    {
-      doHandshakeWrite(hsStatus);
-    }
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public int getAppBufSize()
-  {
-    return appBufSize;
   }
 
 
@@ -250,7 +251,7 @@
   {
     int cipherKeySSF = 0;
     final String cipherString = sslEngine.getSession().getCipherSuite();
-    for (final Map.Entry<String, Integer> mapEntry : cipherMap.entrySet())
+    for (final Map.Entry<String, Integer> mapEntry : CIPHER_MAP.entrySet())
     {
       if (cipherString.indexOf(mapEntry.getKey()) >= 0)
       {
@@ -266,20 +267,6 @@
   /**
    * {@inheritDoc}
    */
-  public boolean isOpen()
-  {
-    if (sslEngine.isInboundDone() || sslEngine.isOutboundDone())
-    {
-      return false;
-    }
-    return true;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
   public boolean isSecure()
   {
     return true;
@@ -290,264 +277,9 @@
   /**
    * {@inheritDoc}
    */
-  public synchronized int read(final ByteBuffer clearBuffer) throws IOException
-  {
-    SSLEngineResult.HandshakeStatus hsStatus;
-    if (!reading)
-    {
-      appNetData.clear();
-    }
-    else
-    {
-      reading = false;
-    }
-
-    if (!socketChannel.isOpen())
-    {
-      return -1;
-    }
-
-    if (sslEngine.isInboundDone())
-    {
-      return -1;
-    }
-
-    do
-    {
-      final int wrappedBytes = socketChannel.read(appNetData);
-      appNetData.flip();
-
-      if (wrappedBytes == -1)
-      {
-        return -1;
-      }
-
-      hsStatus = sslEngine.getHandshakeStatus();
-
-      if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK
-          || hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP)
-      {
-        doHandshakeRead(hsStatus);
-      }
-
-      if (wrappedBytes == 0)
-      {
-        return 0;
-      }
-
-      while (appNetData.hasRemaining())
-      {
-        appData.clear();
-        final SSLEngineResult res = sslEngine.unwrap(appNetData, appData);
-        appData.flip();
-
-        if (res.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW)
-        {
-          appNetData.compact();
-          reading = true;
-          break;
-        }
-        else if (res.getStatus() != SSLEngineResult.Status.OK)
-        {
-          return -1;
-        }
-
-        hsStatus = sslEngine.getHandshakeStatus();
-        if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK
-            || hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP)
-        {
-          doHandshakeOp(hsStatus);
-        }
-        clearBuffer.put(appData);
-      }
-      hsStatus = sslEngine.getHandshakeStatus();
-    }
-    while (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK
-        || hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP);
-
-    return clearBuffer.position();
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
   public ByteChannel wrapChannel(final ByteChannel channel)
   {
-    return this;
+    return pimpl;
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public synchronized int write(final ByteBuffer clearData) throws IOException
-  {
-    if (!socketChannel.isOpen() || sslEngine.isOutboundDone())
-    {
-      throw new ClosedChannelException();
-    }
-
-    final int originalPosition = clearData.position();
-    final int originalLimit = clearData.limit();
-    final int length = originalLimit - originalPosition;
-
-    if (length > sslBufferSize)
-    {
-      int pos = originalPosition;
-      int lim = originalPosition + sslBufferSize;
-      while (pos < originalLimit)
-      {
-        clearData.position(pos);
-        clearData.limit(lim);
-        writeInternal(clearData);
-        pos = lim;
-        lim = Math.min(originalLimit, pos + sslBufferSize);
-      }
-      return length;
-    }
-    else
-    {
-      return writeInternal(clearData);
-    }
-  }
-
-
-
-  private void doHandshakeOp(SSLEngineResult.HandshakeStatus hsStatus)
-      throws IOException
-  {
-    SSLEngineResult res;
-    switch (hsStatus)
-    {
-    case NEED_TASK:
-      hsStatus = doTasks();
-      break;
-    case NEED_WRAP:
-      tempData.clear();
-      netData.clear();
-      res = sslEngine.wrap(tempData, netData);
-      hsStatus = res.getHandshakeStatus();
-      netData.flip();
-      while (netData.hasRemaining())
-      {
-        socketChannel.write(netData);
-      }
-      hsStatus = sslEngine.getHandshakeStatus();
-      return;
-    default:
-      return;
-    }
-  }
-
-
-
-  private void doHandshakeRead(SSLEngineResult.HandshakeStatus hsStatus)
-      throws IOException
-  {
-    do
-    {
-      doHandshakeOp(hsStatus);
-      hsStatus = sslEngine.getHandshakeStatus();
-    }
-    while (hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP
-        || hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK);
-  }
-
-
-
-  private void doHandshakeUnwrap() throws IOException
-  {
-    netData.clear();
-    tempData.clear();
-    final int bytesRead = socketChannel.read(netData);
-
-    if (bytesRead <= 0)
-    {
-      throw new ClosedChannelException();
-    }
-    else
-    {
-      sslEngine.unwrap(netData, tempData);
-    }
-  }
-
-
-
-  private void doHandshakeWrite(SSLEngineResult.HandshakeStatus hsStatus)
-      throws IOException
-  {
-    do
-    {
-      if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)
-      {
-        doHandshakeUnwrap();
-      }
-      else
-      {
-        doHandshakeOp(hsStatus);
-      }
-      hsStatus = sslEngine.getHandshakeStatus();
-    }
-    while (hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP
-        || hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK
-        || hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP);
-  }
-
-
-
-  private SSLEngineResult.HandshakeStatus doTasks()
-  {
-    Runnable task;
-    while ((task = sslEngine.getDelegatedTask()) != null)
-    {
-      task.run();
-    }
-    return sslEngine.getHandshakeStatus();
-  }
-
-
-
-  private int writeInternal(final ByteBuffer clearData) throws IOException
-  {
-    int totBytesSent = 0;
-    SSLEngineResult.HandshakeStatus hsStatus;
-    hsStatus = sslEngine.getHandshakeStatus();
-
-    if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK
-        || hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP
-        || hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)
-    {
-      doHandshakeWrite(hsStatus);
-    }
-
-    while (clearData.hasRemaining())
-    {
-      netData.clear();
-      final SSLEngineResult res = sslEngine.wrap(clearData, netData);
-      netData.flip();
-      if (netData.remaining() == 0)
-      {
-        // wrap didn't produce any data from our clear buffer.
-        // Throw exception to prevent looping.
-        throw new SSLException("SSLEngine.wrap produced 0 bytes");
-      }
-
-      if (res.getStatus() != SSLEngineResult.Status.OK)
-      {
-        throw new ClosedChannelException();
-      }
-
-      if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK
-          || hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP
-          || hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)
-      {
-        doHandshakeWrite(hsStatus);
-      }
-      totBytesSent += socketChannel.write(netData);
-    }
-    return totBytesSent;
-  }
 }

--
Gitblit v1.10.0