📄 sslhandler.java
字号:
/** * 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(); // By RFC 2616, we can "fire and forget" our close_notify // message, so that's what we'll do here. outNetBuffer.clear(); SSLEngineResult result = sslEngine.wrap(hsBB, outNetBuffer); 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() throws SSLException { if (!initialHandshakeComplete) { throw new IllegalStateException(); } if (appBuffer.hasRemaining()) { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " Error: appBuffer not empty!"); } //still app data in buffer!? throw new IllegalStateException(); } unwrap(); } /** * @param status * @throws SSLException */ private SSLEngineResult.Status checkStatus(SSLEngineResult.Status status) throws SSLException { 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); } return status; } /** * Perform any handshaking processing. */ public void handshake(NextFilter nextFilter) throws SSLException { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " doHandshake()"); } while (!initialHandshakeComplete) { if (initialHandshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED) { session.setAttribute(SSLFilter.SSL_SESSION, sslEngine .getSession()); if (SessionLog.isDebugEnabled(session)) { SSLSession sslSession = sslEngine.getSession(); SessionLog.debug(session, " initialHandshakeStatus=FINISHED"); SessionLog.debug(session, " sslSession CipherSuite used " + sslSession.getCipherSuite()); } initialHandshakeComplete = true; if (session.containsAttribute(SSLFilter.USE_NOTIFICATION)) { scheduleMessageReceived(nextFilter, SSLFilter.SESSION_SECURED); } break; } else if (initialHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " initialHandshakeStatus=NEED_TASK"); } initialHandshakeStatus = doTasks(); } else if (initialHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) { // we need more data read if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " initialHandshakeStatus=NEED_UNWRAP"); } SSLEngineResult.Status status = unwrapHandshake(); if ((initialHandshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED && status == SSLEngineResult.Status.BUFFER_UNDERFLOW) || isInboundDone()) { // We need more data or the session is closed break; } } else if (initialHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP) { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " initialHandshakeStatus=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.hasRemaining()) { if (SessionLog.isDebugEnabled(session)) { SessionLog .debug(session, " Still data in out buffer!"); } break; } outNetBuffer.clear(); SSLEngineResult result = sslEngine.wrap(hsBB, outNetBuffer); if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " Wrap res:" + result); } outNetBuffer.flip(); initialHandshakeStatus = result.getHandshakeStatus(); writeNetBuffer(nextFilter); } else { throw new IllegalStateException("Invalid Handshaking State" + initialHandshakeStatus); } } } public WriteFuture writeNetBuffer(NextFilter nextFilter) throws SSLException { // Check if any net data needed to be writen if (!getOutNetBuffer().hasRemaining()) { // no; bail out return DefaultWriteFuture.newNotWrittenFuture(session); } // set flag that we are writing encrypted data // (used in SSLFilter.filterWrite()) writingEncryptedData = true; // write net data WriteFuture writeFuture = null; try { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " write outNetBuffer: " + getOutNetBuffer()); } org.apache.mina.common.ByteBuffer writeBuffer = copy(getOutNetBuffer()); if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " session write: " + writeBuffer); } //debug("outNetBuffer (after copy): {0}", sslHandler.getOutNetBuffer()); writeFuture = new DefaultWriteFuture(session); parent.filterWrite(nextFilter, session, new WriteRequest( writeBuffer, writeFuture)); // loop while more writes required to complete handshake while (needToCompleteInitialHandshake()) { try { handshake(nextFilter); } catch (SSLException ssle) { SSLException newSSLE = new SSLHandshakeException( "Initial SSL handshake failed."); newSSLE.initCause(ssle); throw newSSLE; } if (getOutNetBuffer().hasRemaining()) { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " write outNetBuffer2: " + getOutNetBuffer()); } org.apache.mina.common.ByteBuffer writeBuffer2 = copy(getOutNetBuffer()); writeFuture = new DefaultWriteFuture(session); parent.filterWrite(nextFilter, session, new WriteRequest( writeBuffer2, writeFuture)); } } } finally { writingEncryptedData = false; } return writeFuture; } private SSLEngineResult.Status unwrap() throws SSLException { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " unwrap()"); } // Prepare the application buffer to receive decrypted data appBuffer.clear(); // Prepare the net data for reading. inNetBuffer.flip(); SSLEngineResult res; do { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " inNetBuffer: " + inNetBuffer); SessionLog.debug(session, " appBuffer: " + appBuffer); } res = sslEngine.unwrap(inNetBuffer, appBuffer); if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " Unwrap res:" + res); } } while (res.getStatus() == SSLEngineResult.Status.OK); // prepare to be written again inNetBuffer.compact(); // prepare app data to be read appBuffer.flip(); /* * 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. */ return checkStatus(res.getStatus()); } private SSLEngineResult.Status unwrapHandshake() throws SSLException { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " unwrapHandshake()"); } // Prepare the application buffer to receive decrypted data appBuffer.clear(); // Prepare the net data for reading. inNetBuffer.flip(); SSLEngineResult res; do { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " inNetBuffer: " + inNetBuffer); SessionLog.debug(session, " appBuffer: " + appBuffer); } res = sslEngine.unwrap(inNetBuffer, appBuffer); if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " Unwrap res:" + res); } } while (res.getStatus() == SSLEngineResult.Status.OK && res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP); initialHandshakeStatus = res.getHandshakeStatus(); // If handshake finished, no data was produced, and the status is still ok, // try to unwrap more if (initialHandshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED && appBuffer.position() == 0 && res.getStatus() == SSLEngineResult.Status.OK && inNetBuffer.hasRemaining()) { do { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " extra handshake unwrap"); SessionLog.debug(session, " inNetBuffer: " + inNetBuffer); SessionLog.debug(session, " appBuffer: " + appBuffer); } res = sslEngine.unwrap(inNetBuffer, appBuffer); if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " Unwrap res:" + res); } } while (res.getStatus() == SSLEngineResult.Status.OK); } // prepare to be written again inNetBuffer.compact(); // prepare app data to be read appBuffer.flip(); /* * 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. */ //initialHandshakeStatus = res.getHandshakeStatus(); return checkStatus(res.getStatus()); } /** * Do all the outstanding handshake tasks in the current Thread. */ private SSLEngineResult.HandshakeStatus doTasks() { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " 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) { if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " doTask: " + runnable); } runnable.run(); } if (SessionLog.isDebugEnabled(session)) { SessionLog.debug(session, " doTasks(): " + sslEngine.getHandshakeStatus()); } return sslEngine.getHandshakeStatus(); } /** * Creates a new Mina byte 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 org.apache.mina.common.ByteBuffer copy(java.nio.ByteBuffer src) { org.apache.mina.common.ByteBuffer copy = org.apache.mina.common.ByteBuffer .allocate(src.remaining()); copy.put(src); copy.flip(); return copy; } private static class EventType { public static final EventType RECEIVED = new EventType("RECEIVED"); public static final EventType FILTER_WRITE = new EventType( "FILTER_WRITE"); private final String value; private EventType(String value) { this.value = value; } public String toString() { return value; } } private static class Event { private final EventType type; private final NextFilter nextFilter; private final Object data; Event(EventType type, NextFilter nextFilter, Object data) { this.type = type; this.nextFilter = nextFilter; this.data = data; } public Object getData() { return data; } public NextFilter getNextFilter() { return nextFilter; } public EventType getType() { return type; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -