📄 sslhandler.java
字号:
// Loop until there is no more data in src while (src.hasRemaining()) { SSLEngineResult result = sslEngine.wrap(src, outNetBuffer.buf()); if (result.getStatus() == SSLEngineResult.Status.OK) { if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) { doTasks(); } } else if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) { outNetBuffer.capacity(outNetBuffer.capacity() << 1); outNetBuffer.limit(outNetBuffer.capacity()); } else { throw new SSLException("SSLEngine error during encrypt: " + result.getStatus() + " src: " + src + "outNetBuffer: " + outNetBuffer); } } outNetBuffer.flip(); } /** * Start SSL shutdown process. * * @return <tt>true</tt> if shutdown process is started. * <tt>false</tt> if shutdown process is already finished. * @throws SSLException on errors */ public boolean closeOutbound() throws SSLException { if (sslEngine == null || sslEngine.isOutboundDone()) { return false; } sslEngine.closeOutbound(); createOutNetBuffer(0); SSLEngineResult result; for (;;) { result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf()); if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) { outNetBuffer.capacity(outNetBuffer.capacity() << 1); outNetBuffer.limit(outNetBuffer.capacity()); } else { break; } } if (result.getStatus() != SSLEngineResult.Status.CLOSED) { throw new SSLException("Improper close state: " + result); } outNetBuffer.flip(); return true; } /** * Decrypt in net buffer. Result is stored in app buffer. * * @throws SSLException */ private void decrypt(NextFilter nextFilter) throws SSLException { if (!handshakeComplete) { throw new IllegalStateException(); } unwrap(nextFilter); } /** * @param res * @throws SSLException */ private void checkStatus(SSLEngineResult res) throws SSLException { SSLEngineResult.Status status = res.getStatus(); /* * The status may be: * OK - Normal operation * OVERFLOW - Should never happen since the application buffer is * sized to hold the maximum packet size. * UNDERFLOW - Need to read more data from the socket. It's normal. * CLOSED - The other peer closed the socket. Also normal. */ if (status != SSLEngineResult.Status.OK && status != SSLEngineResult.Status.CLOSED && status != SSLEngineResult.Status.BUFFER_UNDERFLOW) { throw new SSLException("SSLEngine error during decrypt: " + status + " inNetBuffer: " + inNetBuffer + "appBuffer: " + appBuffer); } } /** * Perform any handshaking processing. */ public void handshake(NextFilter nextFilter) throws SSLException { for (;;) { switch (handshakeStatus) { case FINISHED : session.setAttribute( SslFilter.SSL_SESSION, sslEngine.getSession()); handshakeComplete = true; if (!initialHandshakeComplete && session.containsAttribute(SslFilter.USE_NOTIFICATION)) { // SESSION_SECURED is fired only when it's the first handshake. // (i.e. renegotiation shouldn't trigger SESSION_SECURED.) initialHandshakeComplete = true; scheduleMessageReceived(nextFilter, SslFilter.SESSION_SECURED); } return; case NEED_TASK : handshakeStatus = doTasks(); break; case NEED_UNWRAP : // we need more data read SSLEngineResult.Status status = unwrapHandshake(nextFilter); if (status == SSLEngineResult.Status.BUFFER_UNDERFLOW && handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED || isInboundDone()) { // We need more data or the session is closed return; } break; case NEED_WRAP : // First make sure that the out buffer is completely empty. Since we // cannot call wrap with data left on the buffer if (outNetBuffer != null && outNetBuffer.hasRemaining()) { return; } SSLEngineResult result; createOutNetBuffer(0); for (;;) { result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf()); if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) { outNetBuffer.capacity(outNetBuffer.capacity() << 1); outNetBuffer.limit(outNetBuffer.capacity()); } else { break; } } outNetBuffer.flip(); handshakeStatus = result.getHandshakeStatus(); writeNetBuffer(nextFilter); break; default : throw new IllegalStateException("Invalid Handshaking State" + handshakeStatus); } } } private void createOutNetBuffer(int expectedRemaining) { // SSLEngine requires us to allocate unnecessarily big buffer // even for small data. *Shrug* int capacity = Math.max( expectedRemaining, sslEngine.getSession().getPacketBufferSize()); if (outNetBuffer != null) { outNetBuffer.capacity(capacity); } else { outNetBuffer = IoBuffer.allocate(capacity).minimumCapacity(0); } } public WriteFuture writeNetBuffer(NextFilter nextFilter) throws SSLException { // Check if any net data needed to be writen if (outNetBuffer == null || !outNetBuffer.hasRemaining()) { // no; bail out return null; } // set flag that we are writing encrypted data // (used in SSLFilter.filterWrite()) writingEncryptedData = true; // write net data WriteFuture writeFuture = null; try { IoBuffer writeBuffer = fetchOutNetBuffer(); writeFuture = new DefaultWriteFuture(session); parent.filterWrite(nextFilter, session, new DefaultWriteRequest( writeBuffer, writeFuture)); // loop while more writes required to complete handshake while (needToCompleteHandshake()) { try { handshake(nextFilter); } catch (SSLException ssle) { SSLException newSsle = new SSLHandshakeException( "SSL handshake failed."); newSsle.initCause(ssle); throw newSsle; } IoBuffer outNetBuffer = fetchOutNetBuffer(); if (outNetBuffer != null && outNetBuffer.hasRemaining()) { writeFuture = new DefaultWriteFuture(session); parent.filterWrite(nextFilter, session, new DefaultWriteRequest(outNetBuffer, writeFuture)); } } } finally { writingEncryptedData = false; } return writeFuture; } private void unwrap(NextFilter nextFilter) throws SSLException { // Prepare the net data for reading. if (inNetBuffer != null) { inNetBuffer.flip(); } if (inNetBuffer == null || !inNetBuffer.hasRemaining()) { return; } SSLEngineResult res = unwrap0(); // prepare to be written again if (inNetBuffer.hasRemaining()) { inNetBuffer.compact(); } else { inNetBuffer = null; } checkStatus(res); renegotiateIfNeeded(nextFilter, res); } private SSLEngineResult.Status unwrapHandshake(NextFilter nextFilter) throws SSLException { // Prepare the net data for reading. if (inNetBuffer != null) { inNetBuffer.flip(); } if (inNetBuffer == null || !inNetBuffer.hasRemaining()) { // Need more data. return SSLEngineResult.Status.BUFFER_UNDERFLOW; } SSLEngineResult res = unwrap0(); handshakeStatus = res.getHandshakeStatus(); checkStatus(res); // If handshake finished, no data was produced, and the status is still ok, // try to unwrap more if (handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED && res.getStatus() == SSLEngineResult.Status.OK && inNetBuffer.hasRemaining()) { res = unwrap0(); // prepare to be written again if (inNetBuffer.hasRemaining()) { inNetBuffer.compact(); } else { inNetBuffer = null; } renegotiateIfNeeded(nextFilter, res); } else { // prepare to be written again if (inNetBuffer.hasRemaining()) { inNetBuffer.compact(); } else { inNetBuffer = null; } } return res.getStatus(); } private void renegotiateIfNeeded(NextFilter nextFilter, SSLEngineResult res) throws SSLException { if (res.getStatus() != SSLEngineResult.Status.CLOSED && res.getStatus() != SSLEngineResult.Status.BUFFER_UNDERFLOW && res.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { // Renegotiation required. handshakeComplete = false; handshakeStatus = res.getHandshakeStatus(); handshake(nextFilter); } } private SSLEngineResult unwrap0() throws SSLException { if (appBuffer == null) { appBuffer = IoBuffer.allocate(inNetBuffer.remaining()); } else { appBuffer.expand(inNetBuffer.remaining()); } SSLEngineResult res; do { res = sslEngine.unwrap(inNetBuffer.buf(), appBuffer.buf()); if (res.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) { appBuffer.capacity(appBuffer.capacity() << 1); appBuffer.limit(appBuffer.capacity()); continue; } } while ((res.getStatus() == SSLEngineResult.Status.OK || res.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) && (handshakeComplete && res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING || res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)); return res; } /** * Do all the outstanding handshake tasks in the current Thread. */ private SSLEngineResult.HandshakeStatus doTasks() { /* * We could run this in a separate thread, but I don't see the need * for this when used from SSLFilter. Use thread filters in MINA instead? */ Runnable runnable; while ((runnable = sslEngine.getDelegatedTask()) != null) { // TODO : we may have to use a thread pool here to improve the performances runnable.run(); } return sslEngine.getHandshakeStatus(); } /** * Creates a new MINA buffer that is a deep copy of the remaining bytes * in the given buffer (between index buf.position() and buf.limit()) * * @param src the buffer to copy * @return the new buffer, ready to read from */ public static IoBuffer copy(ByteBuffer src) { IoBuffer copy = IoBuffer.allocate(src.remaining()); copy.put(src); copy.flip(); return copy; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -