Example #1
0
 private SSLEngineResult unwrap(
     SSLEngine engine, ByteBuf in, int readerIndex, int len, ByteBuf out) throws SSLException {
   int nioBufferCount = in.nioBufferCount();
   int writerIndex = out.writerIndex();
   final SSLEngineResult result;
   if (engine instanceof OpenSslEngine && nioBufferCount > 1) {
     /**
      * If {@link OpenSslEngine} is in use, we can use a special {@link
      * OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method that accepts multiple {@link
      * ByteBuffer}s without additional memory copies.
      */
     OpenSslEngine opensslEngine = (OpenSslEngine) engine;
     try {
       singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes());
       result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), singleBuffer);
       out.writerIndex(writerIndex + result.bytesProduced());
     } finally {
       singleBuffer[0] = null;
     }
   } else {
     result =
         engine.unwrap(
             toByteBuffer(in, readerIndex, len),
             toByteBuffer(out, writerIndex, out.writableBytes()));
   }
   out.writerIndex(writerIndex + result.bytesProduced());
   return result;
 }
Example #2
0
  protected boolean handleSSLHandshake2() throws IOException {
    // We need to make sure the handshake process finished as a whole
    //		boolean proceed = false;
    SSLEngineResult engineResult = null;
    isHanshakeDone = false;
    while (true) {
      switch (engine.getHandshakeStatus()) {
        case NOT_HANDSHAKING:
        case FINISHED:
          isHanshakeDone = true;
          return true;
        case NEED_TASK:
          Executor exec = Executors.newSingleThreadExecutor();
          Runnable task;
          while ((task = engine.getDelegatedTask()) != null) {
            exec.execute(task);
          }
          continue;
        case NEED_WRAP:
          // We need to call a wrap on the engine
          appSendBuffer.flip();
          engineResult = engine.wrap(appSendBuffer, netSendBuffer);
          appSendBuffer.compact();
          if (engineResult.getStatus() == Status.BUFFER_OVERFLOW
              || engineResult.getStatus()
                  == Status
                      .OK) { // The enigne sys we need to flush the current buffer into the network
            // So just set the selector to the write mode
            channel.register(selector, SelectionKey.OP_WRITE);
            selector.wakeup();
            // System.out.println("Handshake wants to do a write ");
            return false;
          } else if (engineResult.getStatus() == Status.CLOSED) {
            throw new IOException("Connection closed");
          } else {
            continue;
          }

        case NEED_UNWRAP:
          // We need to call unwarap method of the engine
          netRecvBuffer.flip();
          engineResult = engine.unwrap(netRecvBuffer, appRecvBuffer);
          netRecvBuffer.compact();
          // System.out.println(engine.isInboundDone());
          if (engineResult.getStatus() == Status.BUFFER_UNDERFLOW) {
            if (!engine.isInboundDone()) {
              channel.register(selector, SelectionKey.OP_READ);
              selector.wakeup();
              // System.out.println("Handshake wants to do a read ");
              return false;
            } else continue;
          } else if (engineResult.getStatus() == Status.CLOSED) {
            throw new IOException("Connection closed");
          } else {
            continue;
          }
      }
    }
  }
Example #3
0
  private int read() throws IOException {
    //		System.out.println("Doing a read ");
    int count = 0;
    while ((count = channel.read(netRecvBuffer)) > 0) ;
    if (count == -1) throw new IOException("Connection closed");

    if (!isHanshakeDone) {
      if (!handleSSLHandshake2()) return 0;
      else {
        if (appSendBuffer.hasRemaining()) {
          channel.register(selector, SelectionKey.OP_WRITE);
          selector.wakeup();
          return 0;
        }
      }
    }

    int retval = 0;
    boolean loop = true;
    while (loop) {
      netRecvBuffer.flip();
      SSLEngineResult engineResult = engine.unwrap(netRecvBuffer, appRecvBuffer);
      netRecvBuffer.compact();

      switch (engineResult.getStatus()) {
        case BUFFER_UNDERFLOW: // There is not enough data read from the network buffer to do the
                               // handshaking
          // Setting the selector to be read again and pass 0 to the caller saying there is nothing
          // to read
          // System.out.println("Read buffer underflow");
          channel.register(selector, SelectionKey.OP_READ);
          selector.wakeup();
          loop = false;
          break;
        case BUFFER_OVERFLOW: // The appbuffer is full the caller really needs to read the current
                              // buffer.
          // Please not this not a problem in the our current implementation as we make sure we are
          // writing the data to the stream
          // System.out.println("Read buffer overflow");
          retval = appRecvBuffer.position();
          loop = false;
          break;
        case CLOSED:
          throw new IOException("Connection closed");
        case OK:
          retval = appRecvBuffer.position();
          break;
        default:
          break;
      }
      if (!handleSSLHandshake2()) {
        loop = false;
        retval = 0;
      }
    }
    return retval;
  }
Example #4
0
  /*
   * Read the channel for more information, then unwrap the
   * (hopefully application) data we get.
   * <P>
   * If we run out of data, we'll return to our caller (possibly using
   * a Selector) to get notification that more is available.
   * <P>
   * Each call to this method will perform at most one underlying read().
   */
  int read() throws IOException {
    SSLEngineResult result;

    if (!initialHSComplete) {
      throw new IllegalStateException();
    }

    int pos = requestBB.position();

    if (sc.read(inNetBB) == -1) {
      sslEngine.closeInbound(); // probably throws exception
      return -1;
    }

    do {
      resizeRequestBB(); // expected room for unwrap
      inNetBB.flip();
      result = sslEngine.unwrap(inNetBB, requestBB);
      inNetBB.compact();

      /*
       * Could check here for a renegotation, but we're only
       * doing a simple read/write, and won't have enough state
       * transitions to do a complete handshake, so ignore that
       * possibility.
       */
      switch (result.getStatus()) {
        case BUFFER_OVERFLOW:
          // Reset the application buffer size.
          appBBSize = sslEngine.getSession().getApplicationBufferSize();
          break;

        case BUFFER_UNDERFLOW:
          // Resize buffer if needed.
          netBBSize = sslEngine.getSession().getPacketBufferSize();
          if (netBBSize > inNetBB.capacity()) {
            resizeResponseBB();

            break; // break, next read will support larger buffer.
          }
        case OK:
          if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
            doTasks();
          }
          break;

        default:
          throw new IOException("sslEngine error during data read: " + result.getStatus());
      }
    } while ((inNetBB.position() != 0) && result.getStatus() != Status.BUFFER_UNDERFLOW);

    return (requestBB.position() - pos);
  }
  /**
   * Method description
   *
   * @param net
   * @param app
   * @return
   * @throws SSLException
   */
  public ByteBuffer unwrap(ByteBuffer net, ByteBuffer app) throws SSLException {
    ByteBuffer out = app;

    out.order(app.order());
    tlsEngineResult = tlsEngine.unwrap(net, out);

    if (log.isLoggable(Level.FINEST)) {
      log.log(
          Level.FINEST,
          "{0}, unwrap() tlsEngineRsult.getStatus() = {1}, "
              + "tlsEngineRsult.getHandshakeStatus() = {2}",
          new Object[] {
            debugId, tlsEngineResult.getStatus(), tlsEngineResult.getHandshakeStatus()
          });
    }

    if (tlsEngineResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) {
      if (eventHandler != null) {
        eventHandler.handshakeCompleted(this);
      }
    }

    if (tlsEngineResult.getStatus() == Status.BUFFER_OVERFLOW) {
      out = resizeApplicationBuffer(net, out);
      tlsEngineResult = tlsEngine.unwrap(net, out);
    }

    if (tlsEngineResult.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
      doTasks();

      if (log.isLoggable(Level.FINEST)) {
        log.log(
            Level.FINEST,
            "unwrap() doTasks(), handshake: {0}, {1}",
            new Object[] {tlsEngine.getHandshakeStatus(), debugId});
      }
    }

    return out;
  }
Example #6
0
  @Test
  public void testAbruptCloseDuringHandshake() throws Exception {
    InetSocketAddress address = startServer(version, null);
    SslContextFactory sslContextFactory = newSslContextFactory();
    sslContextFactory.start();
    SSLEngine sslEngine = sslContextFactory.newSSLEngine(address);
    sslEngine.setUseClientMode(true);
    NextProtoNego.put(
        sslEngine,
        new NextProtoNego.ClientProvider() {
          @Override
          public boolean supports() {
            return true;
          }

          @Override
          public void unsupported() {}

          @Override
          public String selectProtocol(List<String> protocols) {
            return null;
          }
        });
    sslEngine.beginHandshake();

    ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
    sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
    encrypted.flip();

    try (SocketChannel channel = SocketChannel.open(address)) {
      // Send ClientHello, immediately followed by FIN (no TLS Close Alert)
      channel.write(encrypted);
      channel.shutdownOutput();

      // Read ServerHello from server
      encrypted.clear();
      int read = channel.read(encrypted);
      encrypted.flip();
      Assert.assertTrue(read > 0);
      ByteBuffer decrypted = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize());
      sslEngine.unwrap(encrypted, decrypted);

      // Now if we read more, we should either read the TLS Close Alert, or directly -1
      encrypted.clear();
      read = channel.read(encrypted);
      // Since we have close the connection abruptly, the server also does so
      Assert.assertTrue(read < 0);
    }
  }
Example #7
0
 private static SSLEngineResult unwrap(SSLEngine engine, ByteBuf in, ByteBuf out)
     throws SSLException {
   ByteBuffer in0 = in.nioBuffer();
   for (; ; ) {
     ByteBuffer out0 = out.nioBuffer(out.writerIndex(), out.writableBytes());
     SSLEngineResult result = engine.unwrap(in0, out0);
     in.skipBytes(result.bytesConsumed());
     out.writerIndex(out.writerIndex() + result.bytesProduced());
     switch (result.getStatus()) {
       case BUFFER_OVERFLOW:
         out.ensureWritableBytes(engine.getSession().getApplicationBufferSize());
         break;
       default:
         return result;
     }
   }
 }
Example #8
0
  /**
   * Unwraps data with the specified engine.
   *
   * @param engine - SSLEngine that unwraps data.
   * @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for logging only.
   * @param net - Buffer with data to unwrap.
   * @param wantedStatus - Specifies expected result status of wrapping.
   * @param result - Array which first element will be used to output wrap result object.
   * @return - Buffer with unwrapped data.
   * @throws SSLException - thrown on engine errors.
   */
  public static ByteBuffer doUnWrap(
      SSLEngine engine,
      String unwrapper,
      ByteBuffer net,
      SSLEngineResult.Status wantedStatus,
      SSLEngineResult[] result)
      throws SSLException {

    ByteBuffer app = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize());
    int length = net.remaining();
    System.out.println(unwrapper + " unwrapping " + length + " bytes...");
    SSLEngineResult r = engine.unwrap(net, app);
    app.flip();
    System.out.println(unwrapper + " handshake status is " + engine.getHandshakeStatus());
    checkResult(r, wantedStatus);
    if (result != null && result.length > 0) {
      result[0] = r;
    }
    return app;
  }
  private boolean unwrap() {
    SSLEngineResult unwrapResult;

    try {
      unwrapSrc.flip();
      unwrapResult = engine.unwrap(unwrapSrc, unwrapDst);
      unwrapSrc.compact();
    } catch (SSLException exc) {
      this.onHandshakeFailure(exc);
      return false;
    }

    switch (unwrapResult.getStatus()) {
      case OK:
        if (unwrapDst.position() > 0) {
          unwrapDst.flip();
          this.onInboundData(unwrapDst);
          unwrapDst.compact();
        }
        break;

      case CLOSED:
        this.onClosed();
        return false;

      case BUFFER_OVERFLOW:
        throw new IllegalStateException("failed to unwrap");

      case BUFFER_UNDERFLOW:
        return false;
    }

    switch (unwrapResult.getHandshakeStatus()) {
      case FINISHED:
        this.onHandshakeSuccess();
        return false;
    }

    return true;
  }
Example #10
0
  /**
   * Attempts to decode SSL/TLS network data into a plaintext application data buffer.
   *
   * @param src a ByteBuffer containing inbound network data.
   * @param dst a ByteBuffer to hold inbound application data.
   * @return the number of bytes produced
   * @throws Exception
   */
  private int unwrap(ByteBuffer src, ByteBuffer dst) throws Exception {
    SSLEngineResult result;
    int read = 0;
    do {
      // prepare the input buffer
      src.flip();
      // unwrap the data
      result = sslEngine.unwrap(src, dst);
      // compact the buffer
      src.compact();

      if (result.getStatus() == Status.OK || result.getStatus() == Status.BUFFER_UNDERFLOW) {
        // we did receive some data, add it to our total
        read += result.bytesProduced();

        handshakeStatus = result.getHandshakeStatus();
        // perform any tasks if needed
        tryTasks();
        // if we need more network data, then bail out for now.
        if (result.getStatus() == Status.BUFFER_UNDERFLOW) {
          break;
        }
      } else if (result.getStatus() == Status.BUFFER_OVERFLOW && read > 0) {
        // buffer overflow can happen, if we have read data, then
        // empty out the destination buffer before we do another read
        break;
      } else if (result.getStatus() == Status.CLOSED) {
        return -1;
      } else {
        // here we should trap BUFFER_OVERFLOW and call expand on the
        // buffer for now, throw an exception, as we initialized the
        // buffers in the constructor
        throw new IOException(MESSAGES.errorUnwrappingData(result.getStatus().toString()));
      }
      // continue to unwrapping as long as the input buffer has stuff
    } while (src.position() != 0);

    return read;
  }
 private ByteBuffer unwrap(ByteBuffer b) throws SSLException {
   in.clear();
   while (b.hasRemaining()) {
     sslEngineResult = sslEngine.unwrap(b, in);
     if (sslEngineResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
       if (DEBUG) {
         log("Handshake NEED TASK");
       }
       Runnable task;
       while ((task = sslEngine.getDelegatedTask()) != null) {
         if (DEBUG) {
           log("Running task: " + task);
         }
         task.run();
       }
     } else if (sslEngineResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED
         || sslEngineResult.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
       return in;
     }
   }
   return in;
 }
Example #12
0
 private static SSLEngineResult unwrap(SSLEngine engine, ByteBuffer in, ByteBuf out)
     throws SSLException {
   int overflows = 0;
   for (; ; ) {
     ByteBuffer out0 = out.nioBuffer(out.writerIndex(), out.writableBytes());
     SSLEngineResult result = engine.unwrap(in, out0);
     out.writerIndex(out.writerIndex() + result.bytesProduced());
     switch (result.getStatus()) {
       case BUFFER_OVERFLOW:
         int max = engine.getSession().getApplicationBufferSize();
         switch (overflows++) {
           case 0:
             out.ensureWritable(Math.min(max, in.remaining()));
             break;
           default:
             out.ensureWritable(max);
         }
         break;
       default:
         return result;
     }
   }
 }
Example #13
0
 private boolean unwrap() throws IOException {
   while (true) {
     SSLEngineResult result = engine.unwrap(inToken, data);
     switch (result.getStatus()) {
       case BUFFER_UNDERFLOW:
         return false;
       case BUFFER_OVERFLOW:
         ByteBuffer buffer =
             ByteBuffer.allocate(
                 outToken.capacity() + engine.getSession().getApplicationBufferSize());
         data.flip();
         buffer.put(data);
         data = buffer;
         break;
       case OK:
         if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) {
           subject = createSubject();
         }
         return true;
       case CLOSED:
         throw new EOFException();
     }
   }
 }
  @Test
  public void checkSslEngineBehaviour() throws Exception {
    SSLEngine server = __sslCtxFactory.newSSLEngine();
    SSLEngine client = __sslCtxFactory.newSSLEngine();

    ByteBuffer netC2S = ByteBuffer.allocate(server.getSession().getPacketBufferSize());
    ByteBuffer netS2C = ByteBuffer.allocate(server.getSession().getPacketBufferSize());
    ByteBuffer serverIn = ByteBuffer.allocate(server.getSession().getApplicationBufferSize());
    ByteBuffer serverOut = ByteBuffer.allocate(server.getSession().getApplicationBufferSize());
    ByteBuffer clientIn = ByteBuffer.allocate(client.getSession().getApplicationBufferSize());

    SSLEngineResult result;

    // start the client
    client.setUseClientMode(true);
    client.beginHandshake();
    Assert.assertEquals(HandshakeStatus.NEED_WRAP, client.getHandshakeStatus());

    // what if we try an unwrap?
    netS2C.flip();
    result = client.unwrap(netS2C, clientIn);
    // unwrap is a noop
    assertEquals(SSLEngineResult.Status.OK, result.getStatus());
    assertEquals(0, result.bytesConsumed());
    assertEquals(0, result.bytesProduced());
    assertEquals(HandshakeStatus.NEED_WRAP, result.getHandshakeStatus());
    netS2C.clear();

    // do the needed WRAP of empty buffer
    result = client.wrap(BufferUtil.EMPTY_BUFFER, netC2S);
    // unwrap is a noop
    assertEquals(SSLEngineResult.Status.OK, result.getStatus());
    assertEquals(0, result.bytesConsumed());
    assertThat(result.bytesProduced(), greaterThan(0));
    assertEquals(HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus());
    netC2S.flip();
    assertEquals(netC2S.remaining(), result.bytesProduced());

    // start the server
    server.setUseClientMode(false);
    server.beginHandshake();
    Assert.assertEquals(HandshakeStatus.NEED_UNWRAP, server.getHandshakeStatus());

    // what if we try a needless wrap?
    serverOut.put(BufferUtil.toBuffer("Hello World"));
    serverOut.flip();
    result = server.wrap(serverOut, netS2C);
    // wrap is a noop
    assertEquals(SSLEngineResult.Status.OK, result.getStatus());
    assertEquals(0, result.bytesConsumed());
    assertEquals(0, result.bytesProduced());
    assertEquals(HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus());

    // Do the needed unwrap, to an empty buffer
    result = server.unwrap(netC2S, BufferUtil.EMPTY_BUFFER);
    assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
    assertEquals(0, result.bytesConsumed());
    assertEquals(0, result.bytesProduced());
    assertEquals(HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus());

    // Do the needed unwrap, to a full buffer
    serverIn.position(serverIn.limit());
    result = server.unwrap(netC2S, serverIn);
    assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
    assertEquals(0, result.bytesConsumed());
    assertEquals(0, result.bytesProduced());
    assertEquals(HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus());

    // Do the needed unwrap, to an empty buffer
    serverIn.clear();
    result = server.unwrap(netC2S, serverIn);
    assertEquals(SSLEngineResult.Status.OK, result.getStatus());
    assertThat(result.bytesConsumed(), greaterThan(0));
    assertEquals(0, result.bytesProduced());
    assertEquals(HandshakeStatus.NEED_TASK, result.getHandshakeStatus());

    server.getDelegatedTask().run();

    assertEquals(HandshakeStatus.NEED_WRAP, server.getHandshakeStatus());
  }
Example #15
0
  /**
   * Execute a handshake with the client socket channel
   *
   * @throws Exception
   */
  private void doHandshake() throws Exception {

    SSLSession session = getSSLSession();
    int packetBufferSize = Math.max(session.getPacketBufferSize(), MIN_BUFFER_SIZE);
    // Create byte buffers to use for holding application data
    initBuffers(packetBufferSize);

    ByteBuffer clientNetData = ByteBuffer.allocateDirect(packetBufferSize);
    ByteBuffer clientAppData = ByteBuffer.allocateDirect(packetBufferSize);

    // Begin handshake
    sslEngine.beginHandshake();
    handshakeStatus = sslEngine.getHandshakeStatus();
    int i = 1;
    boolean read = true;
    // Process handshaking message
    while (!handshakeComplete) {

      switch (handshakeStatus) {
        case NEED_UNWRAP:
          int nBytes = 0;
          if (read) {
            clientAppData.clear();
            nBytes = this.channel.read(this.netInBuffer).get();
          }
          if (nBytes < 0) {
            throw new IOException(MESSAGES.errorUnwrappingHandshake());
          } else {
            boolean cont = false;
            // Loop while we can perform pure SSLEngine data
            do {
              // Prepare the buffer with the incoming data
              this.netInBuffer.flip();
              // Call unwrap
              SSLEngineResult res = sslEngine.unwrap(this.netInBuffer, clientAppData);
              // Compact the buffer, this is an optional method,
              // wonder what would happen if we didn't
              this.netInBuffer.compact();
              // Read in the status
              handshakeStatus = res.getHandshakeStatus();
              if (res.getStatus() == SSLEngineResult.Status.OK) {
                // Execute tasks if we need to
                tryTasks();
                read = true;
              } else if (res.getStatus() == Status.BUFFER_UNDERFLOW) {
                read = true;
              } else if (res.getStatus() == Status.BUFFER_OVERFLOW) {
                ByteBuffer tmp = ByteBuffer.allocateDirect(packetBufferSize * (++i));

                if (clientAppData.position() > 0) {
                  clientAppData.flip();
                }
                tmp.put(clientAppData);
                clientAppData = tmp;
                read = false;
              }
              // Perform another unwrap?
              cont =
                  res.getStatus() == SSLEngineResult.Status.OK
                      && handshakeStatus == HandshakeStatus.NEED_UNWRAP;
            } while (cont);
          }

          break;
        case NEED_WRAP:
          clientNetData.compact();
          this.netOutBuffer.clear();
          SSLEngineResult res = sslEngine.wrap(clientNetData, this.netOutBuffer);
          handshakeStatus = res.getHandshakeStatus();
          this.netOutBuffer.flip();

          if (res.getStatus() == Status.OK) {
            // Execute tasks if we need to
            tryTasks();
            // Send the handshaking data to client
            while (this.netOutBuffer.hasRemaining()) {
              if (this.channel.write(this.netOutBuffer).get() < 0) {
                // Handle closed channel
                throw new IOException(MESSAGES.errorWrappingHandshake());
              }
            }
          } else {
            // Wrap should always work with our buffers
            throw new IOException(
                MESSAGES.errorWrappingHandshakeStatus(res.getStatus().toString()));
          }

          break;
        case NEED_TASK:
          handshakeStatus = tasks();

          break;
        case NOT_HANDSHAKING:
          throw new SSLHandshakeException(MESSAGES.notHandshaking());
        case FINISHED:
          handshakeComplete = true;
          break;
      }
    }

    this.handshakeComplete = (handshakeStatus == HandshakeStatus.FINISHED);
  }
Example #16
0
  private ChannelBuffer unwrap(
      ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, int offset, int length)
      throws SSLException {
    ByteBuffer inNetBuf = buffer.toByteBuffer(offset, length);
    ByteBuffer outAppBuf = bufferPool.acquire();

    try {
      boolean needsWrap = false;
      loop:
      for (; ; ) {
        SSLEngineResult result;
        synchronized (handshakeLock) {
          if (!handshaken
              && !handshaking
              && !engine.getUseClientMode()
              && !engine.isInboundDone()
              && !engine.isOutboundDone()) {
            handshake();
          }

          try {
            result = engine.unwrap(inNetBuf, outAppBuf);
          } catch (SSLException e) {
            throw e;
          }

          final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
          handleRenegotiation(handshakeStatus);
          switch (handshakeStatus) {
            case NEED_UNWRAP:
              if (inNetBuf.hasRemaining() && !engine.isInboundDone()) {
                break;
              } else {
                break loop;
              }
            case NEED_WRAP:
              wrapNonAppData(ctx, channel);
              break;
            case NEED_TASK:
              runDelegatedTasks();
              break;
            case FINISHED:
              setHandshakeSuccess(channel);
              needsWrap = true;
              break loop;
            case NOT_HANDSHAKING:
              needsWrap = true;
              break loop;
            default:
              throw new IllegalStateException("Unknown handshake status: " + handshakeStatus);
          }
        }
      }

      if (needsWrap) {
        // wrap() acquires pendingUnencryptedWrites first and then
        // handshakeLock.  If handshakeLock is already hold by the
        // current thread, calling wrap() will lead to a dead lock
        // i.e. pendingUnencryptedWrites -> handshakeLock vs.
        //      handshakeLock -> pendingUnencryptedLock -> handshakeLock
        //
        // There is also a same issue between pendingEncryptedWrites
        // and pendingUnencryptedWrites.
        if (!Thread.holdsLock(handshakeLock)
            && !pendingEncryptedWritesLock.isHeldByCurrentThread()) {
          wrap(ctx, channel);
        }
      }

      outAppBuf.flip();

      if (outAppBuf.hasRemaining()) {
        ChannelBuffer frame = ChannelBuffers.buffer(outAppBuf.remaining());
        frame.writeBytes(outAppBuf.array(), 0, frame.capacity());
        return frame;
      } else {
        return null;
      }
    } catch (SSLException e) {
      setHandshakeFailure(channel, e);
      throw e;
    } finally {
      bufferPool.release(outAppBuf);
    }
  }
Example #17
0
  /*
   * Run the test.
   *
   * Sit in a tight loop, both engines calling wrap/unwrap regardless
   * of whether data is available or not.  We do this until both engines
   * report back they are closed.
   *
   * The main loop handles all of the I/O phases of the SSLEngine's
   * lifetime:
   *
   *     initial handshaking
   *     application data transfer
   *     engine closing
   *
   * One could easily separate these phases into separate
   * sections of code.
   */
  private SSLSession runTest() throws Exception {
    boolean dataDone = false;

    createSSLEngines();
    createBuffers();

    SSLEngineResult clientResult; // results from client's last operation
    SSLEngineResult serverResult; // results from server's last operation

    /*
     * Examining the SSLEngineResults could be much more involved,
     * and may alter the overall flow of the application.
     *
     * For example, if we received a BUFFER_OVERFLOW when trying
     * to write to the output pipe, we could reallocate a larger
     * pipe, but instead we wait for the peer to drain it.
     */
    while (!isEngineClosed(clientEngine) || !isEngineClosed(serverEngine)) {

      log("================");

      clientResult = clientEngine.wrap(clientOut, cTOs);
      log("client wrap: ", clientResult);
      runDelegatedTasks(clientResult, clientEngine);

      serverResult = serverEngine.wrap(serverOut, sTOc);
      log("server wrap: ", serverResult);
      runDelegatedTasks(serverResult, serverEngine);

      cTOs.flip();
      sTOc.flip();

      log("----");

      clientResult = clientEngine.unwrap(sTOc, clientIn);
      log("client unwrap: ", clientResult);
      runDelegatedTasks(clientResult, clientEngine);

      serverResult = serverEngine.unwrap(cTOs, serverIn);
      log("server unwrap: ", serverResult);
      runDelegatedTasks(serverResult, serverEngine);

      cTOs.compact();
      sTOc.compact();

      /*
       * After we've transfered all application data between the client
       * and server, we close the clientEngine's outbound stream.
       * This generates a close_notify handshake message, which the
       * server engine receives and responds by closing itself.
       */
      if (!dataDone
          && (clientOut.limit() == serverIn.position())
          && (serverOut.limit() == clientIn.position())) {

        /*
         * A sanity check to ensure we got what was sent.
         */
        checkTransfer(serverOut, clientIn);
        checkTransfer(clientOut, serverIn);

        log("\tClosing clientEngine's *OUTBOUND*...");
        clientEngine.closeOutbound();
        dataDone = true;
      }
    }

    return clientEngine.getSession();
  }
Example #18
0
  private SSLSession runRehandshake() throws Exception {

    log("\n\n==============================================");
    log("Staring actual test.");

    createSSLEngines();
    createBuffers();
    SSLEngineResult result;

    log("Client's ClientHello");
    checkResult(
        clientEngine, clientEngine.wrap(clientOut, cTOs), HandshakeStatus.NEED_UNWRAP, false, true);
    cTOs.flip();
    checkResult(
        serverEngine, serverEngine.unwrap(cTOs, serverIn), HandshakeStatus.NEED_WRAP, true, false);
    cTOs.compact();

    log("Server's ServerHello/ServerHelloDone");
    checkResult(
        serverEngine, serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_WRAP, false, true);
    sTOc.flip();
    checkResult(
        clientEngine,
        clientEngine.unwrap(sTOc, clientIn),
        HandshakeStatus.NEED_UNWRAP,
        true,
        false);
    sTOc.compact();

    log("Server's CCS");
    checkResult(
        serverEngine, serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_WRAP, false, true);
    sTOc.flip();
    checkResult(
        clientEngine,
        clientEngine.unwrap(sTOc, clientIn),
        HandshakeStatus.NEED_UNWRAP,
        true,
        false);
    sTOc.compact();

    log("Server's FINISHED");
    checkResult(
        serverEngine, serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_UNWRAP, false, true);
    sTOc.flip();
    checkResult(
        clientEngine, clientEngine.unwrap(sTOc, clientIn), HandshakeStatus.NEED_WRAP, true, false);
    sTOc.compact();

    log("Client's CCS");
    checkResult(
        clientEngine, clientEngine.wrap(clientOut, cTOs), HandshakeStatus.NEED_WRAP, false, true);
    cTOs.flip();
    checkResult(
        serverEngine,
        serverEngine.unwrap(cTOs, serverIn),
        HandshakeStatus.NEED_UNWRAP,
        true,
        false);
    cTOs.compact();

    log("Client's FINISHED should trigger FINISHED messages all around.");
    checkResult(
        clientEngine, clientEngine.wrap(clientOut, cTOs), HandshakeStatus.FINISHED, false, true);
    cTOs.flip();
    checkResult(
        serverEngine, serverEngine.unwrap(cTOs, serverIn), HandshakeStatus.FINISHED, true, false);
    cTOs.compact();

    return clientEngine.getSession();
  }
Example #19
0
 private SSLEngineResult doUnwrap() throws SSLException {
   ByteBuffer cipherText = _buffers.get(BufferType.IN_CIPHER);
   ByteBuffer plainText = _buffers.get(BufferType.IN_PLAIN);
   return _engine.unwrap(cipherText, plainText);
 }
Example #20
0
  /*
   * Perform any handshaking processing.
   * <P>
   * If a SelectionKey is passed, register for selectable
   * operations.
   * <P>
   * In the blocking case, our caller will keep calling us until
   * we finish the handshake.  Our reads/writes will block as expected.
   * <P>
   * In the non-blocking case, we just received the selection notification
   * that this channel is ready for whatever the operation is, so give
   * it a try.
   * <P>
   * return:
   *		true when handshake is done.
   *		false while handshake is in progress
   */
  boolean doHandshake(SelectionKey sk) throws IOException {

    SSLEngineResult result;

    if (initialHSComplete) {
      return initialHSComplete;
    }

    /*
     * Flush out the outgoing buffer, if there's anything left in
     * it.
     */
    if (outNetBB.hasRemaining()) {

      if (!tryFlush(outNetBB)) {
        return false;
      }

      // See if we need to switch from write to read mode.

      switch (initialHSStatus) {

          /*
           * Is this the last buffer?
           */
        case FINISHED:
          initialHSComplete = true;
          // Fall-through to reregister need for a Read.

        case NEED_UNWRAP:
          if (sk != null) {
            sk.interestOps(SelectionKey.OP_READ);
          }
          break;
      }

      return initialHSComplete;
    }

    switch (initialHSStatus) {
      case NEED_UNWRAP:
        if (sc.read(inNetBB) == -1) {
          sslEngine.closeInbound();
          return initialHSComplete;
        }

        needIO:
        while (initialHSStatus == HandshakeStatus.NEED_UNWRAP) {
          resizeRequestBB(); // expected room for unwrap
          inNetBB.flip();
          result = sslEngine.unwrap(inNetBB, requestBB);
          inNetBB.compact();

          initialHSStatus = result.getHandshakeStatus();

          switch (result.getStatus()) {
            case OK:
              switch (initialHSStatus) {
                case NOT_HANDSHAKING:
                  throw new IOException("Not handshaking during initial handshake");

                case NEED_TASK:
                  initialHSStatus = doTasks();
                  break;

                case FINISHED:
                  initialHSComplete = true;
                  break needIO;
              }

              break;

            case BUFFER_UNDERFLOW:
              // Resize buffer if needed.
              netBBSize = sslEngine.getSession().getPacketBufferSize();
              if (netBBSize > inNetBB.capacity()) {
                resizeResponseBB();
              }

              /*
               * Need to go reread the Channel for more data.
               */
              if (sk != null) {
                sk.interestOps(SelectionKey.OP_READ);
              }
              break needIO;

            case BUFFER_OVERFLOW:
              // Reset the application buffer size.
              appBBSize = sslEngine.getSession().getApplicationBufferSize();
              break;

            default: // CLOSED:
              throw new IOException("Received" + result.getStatus() + "during initial handshaking");
          }
        } // "needIO" block.

        /*
         * Just transitioned from read to write.
         */
        if (initialHSStatus != HandshakeStatus.NEED_WRAP) {
          break;
        }

        // Fall through and fill the write buffers.

      case NEED_WRAP:
        /*
         * The flush above guarantees the out buffer to be empty
         */
        outNetBB.clear();
        result = sslEngine.wrap(hsBB, outNetBB);
        outNetBB.flip();

        initialHSStatus = result.getHandshakeStatus();

        switch (result.getStatus()) {
          case OK:
            if (initialHSStatus == HandshakeStatus.NEED_TASK) {
              initialHSStatus = doTasks();
            }

            if (sk != null) {
              sk.interestOps(SelectionKey.OP_WRITE);
            }

            break;

          default: // BUFFER_OVERFLOW/BUFFER_UNDERFLOW/CLOSED:
            throw new IOException("Received" + result.getStatus() + "during initial handshaking");
        }
        break;

      default: // NOT_HANDSHAKING/NEED_TASK/FINISHED
        throw new RuntimeException("Invalid Handshaking State" + initialHSStatus);
    } // switch

    return initialHSComplete;
  }
  @Test
  public void testTcpClose() throws Exception {
    // This test replaces SSLSocket() with a very manual SSL client
    // so we can close TCP underneath SSL.

    SocketChannel client = SocketChannel.open(_connector.socket().getLocalSocketAddress());
    client.socket().setSoTimeout(500);

    SocketChannel server = _connector.accept();
    server.configureBlocking(false);
    _manager.accept(server);

    SSLEngine engine = __sslCtxFactory.newSSLEngine();
    engine.setUseClientMode(true);
    engine.beginHandshake();

    ByteBuffer appOut = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize());
    ByteBuffer sslOut = ByteBuffer.allocate(engine.getSession().getPacketBufferSize() * 2);
    ByteBuffer appIn = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize());
    ByteBuffer sslIn = ByteBuffer.allocate(engine.getSession().getPacketBufferSize() * 2);

    boolean debug = false;

    if (debug) System.err.println(engine.getHandshakeStatus());
    int loop = 20;
    while (engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) {
      if (--loop == 0) throw new IllegalStateException();

      if (engine.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
        if (debug)
          System.err.printf(
              "sslOut %d-%d-%d%n", sslOut.position(), sslOut.limit(), sslOut.capacity());
        if (debug)
          System.err.printf(
              "appOut %d-%d-%d%n", appOut.position(), appOut.limit(), appOut.capacity());
        SSLEngineResult result = engine.wrap(appOut, sslOut);
        if (debug) System.err.println(result);
        sslOut.flip();
        int flushed = client.write(sslOut);
        if (debug) System.err.println("out=" + flushed);
        sslOut.clear();
      }

      if (engine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP) {
        if (debug)
          System.err.printf("sslIn %d-%d-%d%n", sslIn.position(), sslIn.limit(), sslIn.capacity());
        if (sslIn.position() == 0) {
          int filled = client.read(sslIn);
          if (debug) System.err.println("in=" + filled);
        }
        sslIn.flip();
        if (debug)
          System.err.printf("sslIn %d-%d-%d%n", sslIn.position(), sslIn.limit(), sslIn.capacity());
        SSLEngineResult result = engine.unwrap(sslIn, appIn);
        if (debug) System.err.println(result);
        if (debug)
          System.err.printf("sslIn %d-%d-%d%n", sslIn.position(), sslIn.limit(), sslIn.capacity());
        if (sslIn.hasRemaining()) sslIn.compact();
        else sslIn.clear();
        if (debug)
          System.err.printf("sslIn %d-%d-%d%n", sslIn.position(), sslIn.limit(), sslIn.capacity());
      }

      if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
        Runnable task;
        while ((task = engine.getDelegatedTask()) != null) task.run();
        if (debug) System.err.println(engine.getHandshakeStatus());
      }
    }

    if (debug) System.err.println("\nSay Hello");

    // write a message
    appOut.put("HelloWorld".getBytes(StandardCharsets.UTF_8));
    appOut.flip();
    SSLEngineResult result = engine.wrap(appOut, sslOut);
    if (debug) System.err.println(result);
    sslOut.flip();
    int flushed = client.write(sslOut);
    if (debug) System.err.println("out=" + flushed);
    sslOut.clear();
    appOut.clear();

    // read the response
    int filled = client.read(sslIn);
    if (debug) System.err.println("in=" + filled);
    sslIn.flip();
    result = engine.unwrap(sslIn, appIn);
    if (debug) System.err.println(result);
    if (sslIn.hasRemaining()) sslIn.compact();
    else sslIn.clear();

    appIn.flip();
    String reply = new String(appIn.array(), appIn.arrayOffset(), appIn.remaining());
    appIn.clear();

    Assert.assertEquals("HelloWorld", reply);

    if (debug) System.err.println("Shutting down output");
    client.socket().shutdownOutput();

    filled = client.read(sslIn);
    if (debug) System.err.println("in=" + filled);

    if (filled >= 0) {
      // this is the old behaviour.
      sslIn.flip();
      try {
        // Since the client closed abruptly, the server is sending a close alert with a failure
        engine.unwrap(sslIn, appIn);
        Assert.fail();
      } catch (SSLException x) {
        // Expected
      }
    }

    sslIn.clear();
    filled = client.read(sslIn);
    Assert.assertEquals(-1, filled);

    Assert.assertFalse(server.isOpen());
  }