下面列出了怎么用javax.net.ssl.SSLEngineResult.HandshakeStatus的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* read data thru the engine into the given ByteBuffer. If the
* given buffer was not large enough, a new one is allocated
* and returned. This call handles handshaking automatically.
* Caller should check if engine has been closed.
*/
WrapperResult recvData (ByteBuffer dst) throws IOException {
/* we wait until some user data arrives */
int mark = dst.position();
WrapperResult r = null;
int pos = dst.position();
while (dst.position() == pos) {
r = wrapper.recvAndUnwrap (dst);
dst = (r.buf != dst) ? r.buf: dst;
Status status = r.result.getStatus();
if (status == Status.CLOSED) {
doClosure ();
return r;
}
HandshakeStatus hs_status = r.result.getHandshakeStatus();
if (hs_status != HandshakeStatus.FINISHED &&
hs_status != HandshakeStatus.NOT_HANDSHAKING)
{
doHandshake (hs_status);
}
}
Utils.flipToMark(dst, mark);
return r;
}
private static void runDelegatedTasks(SSLEngineResult result,
SSLEngine engine) throws Exception {
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable;
while ((runnable = engine.getDelegatedTask()) != null) {
log("\trunning delegated task...");
runnable.run();
}
HandshakeStatus hsStatus = engine.getHandshakeStatus();
if (hsStatus == HandshakeStatus.NEED_TASK) {
throw new Exception("handshake shouldn't need additional tasks");
}
log("\tnew HandshakeStatus: " + hsStatus);
}
}
/**
* Perform handshake unwrap
* @return the result
* @throws IOException An IO error occurred
*/
protected SSLEngineResult handshakeUnwrap() throws IOException {
SSLEngineResult result;
boolean cont = false;
//loop while we can perform pure SSLEngine data
do {
//prepare the buffer with the incoming data
netInBuffer.flip();
//call unwrap
getBufHandler().configureReadBufferForWrite();
result = sslEngine.unwrap(netInBuffer, getBufHandler().getReadBuffer());
//compact the buffer, this is an optional method, wonder what would happen if we didn't
netInBuffer.compact();
//read in the status
handshakeStatus = result.getHandshakeStatus();
if (result.getStatus() == SSLEngineResult.Status.OK &&
result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
//execute tasks if we need to
handshakeStatus = tasks();
}
//perform another unwrap?
cont = result.getStatus() == SSLEngineResult.Status.OK &&
handshakeStatus == HandshakeStatus.NEED_UNWRAP;
} while (cont);
return result;
}
/**
* performs the unwrap operation by unwrapping from {@link #inCrypt} to {@link #inData}
**/
private synchronized ByteBuffer unwrap() throws SSLException {
int rem;
//There are some ssl test suites, which get around the selector.select() call, which
// cause an infinite unwrap and 100% cpu usage (see #459 and #458)
if (readEngineResult.getStatus() == Status.CLOSED
&& sslEngine.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
try {
close();
} catch (IOException e) {
//Not really interesting
}
}
do {
rem = inData.remaining();
readEngineResult = sslEngine.unwrap(inCrypt, inData);
} while (readEngineResult.getStatus() == Status.OK && (rem != inData.remaining()
|| sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP));
inData.flip();
return inData;
}
private void log(String str, SSLEngineResult result) {
if (!logging) {
return;
}
if (resultOnce) {
resultOnce = false;
Log.info("The format of the SSLEngineResult is: \n"
+ "\t\"getStatus() / getHandshakeStatus()\" +\n"
+ "\t\"bytesConsumed() / bytesProduced()\"\n");
}
HandshakeStatus hsStatus = result.getHandshakeStatus();
Log.info(str + result.getStatus() + "/" + hsStatus + ", " + result.bytesConsumed() + "/"
+ result.bytesProduced() + " bytes");
if (hsStatus == HandshakeStatus.FINISHED) {
Log.info("\t...ready for application data");
}
}
synchronized void writeRecord(EngineOutputRecord outputRecord,
Authenticator authenticator,
CipherBox writeCipher) throws IOException {
/*
* Only output if we're still open.
*/
if (outboundClosed) {
throw new IOException("writer side was already closed.");
}
outputRecord.write(authenticator, writeCipher);
/*
* Did our handshakers notify that we just sent the
* Finished message?
*
* Add an "I'm finished" message to the queue.
*/
if (outputRecord.isFinishedMsg()) {
outboundList.addLast(HandshakeStatus.FINISHED);
}
}
private HandshakeStatus tryToFinishHandshake(byte contentType) {
HandshakeStatus hsStatus = null;
if ((contentType == ContentType.HANDSHAKE.id) &&
conContext.outputRecord.isEmpty()) {
if (conContext.handshakeContext == null) {
hsStatus = HandshakeStatus.FINISHED;
} else if (conContext.isPostHandshakeContext()) {
// unlikely, but just in case.
hsStatus = conContext.finishPostHandshake();
} else if (conContext.handshakeContext.handshakeFinished) {
hsStatus = conContext.finishHandshake();
}
} // Otherwise, the followed call to getHSStatus() will help.
return hsStatus;
}
synchronized void writeRecord(EngineOutputRecord outputRecord,
Authenticator authenticator,
CipherBox writeCipher) throws IOException {
/*
* Only output if we're still open.
*/
if (outboundClosed) {
throw new IOException("writer side was already closed.");
}
outputRecord.write(authenticator, writeCipher);
/*
* Did our handshakers notify that we just sent the
* Finished message?
*
* Add an "I'm finished" message to the queue.
*/
if (outputRecord.isFinishedMsg()) {
outboundList.addLast(HandshakeStatus.FINISHED);
}
}
/**
* performs the unwrap operation by unwrapping from {@link #inCrypt} to {@link #inData}
**/
private synchronized ByteBuffer unwrap() throws SSLException {
int rem;
//There are some ssl test suites, which get around the selector.select() call, which cause an infinite unwrap and 100% cpu usage (see #459 and #458)
if(readEngineResult.getStatus() == SSLEngineResult.Status.CLOSED && sslEngine.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING){
try {
close();
} catch (IOException e) {
//Not really interesting
}
}
do {
rem = inData.remaining();
readEngineResult = sslEngine.unwrap( inCrypt, inData );
} while ( readEngineResult.getStatus() == SSLEngineResult.Status.OK && ( rem != inData.remaining() || sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP ) );
inData.flip();
return inData;
}
/**
* 处理握手 Warp;
*
* @return
* @throws IOException
* @throws Exception
*/
private synchronized HandshakeStatus doHandShakeWarp() throws IOException {
if(!session.isConnected()){
return null;
}
try {
clearBuffer();
appData.flip();
if (warpData(appData) == null) {
return null;
}
//如果有 HandShake Task 则执行
HandshakeStatus handshakeStatus = runDelegatedTasks();
return handshakeStatus;
} catch (SSLException e) {
Logger.error("HandShakeWarp error:", e);
return null;
}
}
private HandshakeStatus tryNewSessionTicket(
HandshakeStatus currentHandshakeStatus) throws IOException {
// Don't bother to kickstart if handshaking is in progress, or if the
// connection is not duplex-open.
if ((conContext.handshakeContext == null) &&
conContext.protocolVersion.useTLS13PlusSpec() &&
!conContext.isOutboundClosed() &&
!conContext.isInboundClosed() &&
!conContext.isBroken) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
SSLLogger.finest("trigger NST");
}
conContext.conSession.updateNST = false;
NewSessionTicket.kickstartProducer.produce(
new PostHandshakeContext(conContext));
return conContext.getHandshakeStatus();
}
return currentHandshakeStatus;
}
synchronized void writeRecord(EngineOutputRecord outputRecord,
Authenticator authenticator,
CipherBox writeCipher) throws IOException {
/*
* Only output if we're still open.
*/
if (outboundClosed) {
throw new IOException("writer side was already closed.");
}
outputRecord.write(authenticator, writeCipher);
/*
* Did our handshakers notify that we just sent the
* Finished message?
*
* Add an "I'm finished" message to the queue.
*/
if (outputRecord.isFinishedMsg()) {
outboundList.addLast(HandshakeStatus.FINISHED);
}
}
synchronized void writeRecord(EngineOutputRecord outputRecord,
Authenticator authenticator,
CipherBox writeCipher) throws IOException {
/*
* Only output if we're still open.
*/
if (outboundClosed) {
throw new IOException("writer side was already closed.");
}
outputRecord.write(authenticator, writeCipher);
/*
* Did our handshakers notify that we just sent the
* Finished message?
*
* Add an "I'm finished" message to the queue.
*/
if (outputRecord.isFinishedMsg()) {
outboundList.addLast(HandshakeStatus.FINISHED);
}
}
private static void log(String str, SSLEngineResult result) {
if (!logging) {
return;
}
if (resultOnce) {
resultOnce = false;
Logger.simple("The format of the SSLEngineResult is: \n"
+ "\t\"getStatus() / getHandshakeStatus()\" +\n"
+ "\t\"bytesConsumed() / bytesProduced()\"\n");
}
HandshakeStatus hsStatus = result.getHandshakeStatus();
log(str + result.getStatus() + "/" + hsStatus + ", "
+ result.bytesConsumed() + "/" + result.bytesProduced()
+ " bytes");
if (hsStatus == HandshakeStatus.FINISHED) {
log("\t...ready for application data");
}
}
synchronized void writeRecord(EngineOutputRecord outputRecord,
Authenticator authenticator,
CipherBox writeCipher) throws IOException {
/*
* Only output if we're still open.
*/
if (outboundClosed) {
throw new IOException("writer side was already closed.");
}
outputRecord.write(authenticator, writeCipher);
/*
* Did our handshakers notify that we just sent the
* Finished message?
*
* Add an "I'm finished" message to the queue.
*/
if (outputRecord.isFinishedMsg()) {
outboundList.addLast(HandshakeStatus.FINISHED);
}
}
public SSLStreams.WrapperResult sendData(ByteBuffer src) throws IOException {
SSLStreams.WrapperResult r = null;
while(src.remaining() > 0) {
r = this.wrapper.wrapAndSend(src);
Status status = r.result.getStatus();
if (status == Status.CLOSED) {
this.doClosure();
return r;
}
HandshakeStatus hs_status = r.result.getHandshakeStatus();
if (hs_status != HandshakeStatus.FINISHED && hs_status != HandshakeStatus.NOT_HANDSHAKING) {
this.doHandshake(hs_status);
}
}
return r;
}
synchronized void writeRecord(EngineOutputRecord outputRecord,
Authenticator authenticator,
CipherBox writeCipher) throws IOException {
/*
* Only output if we're still open.
*/
if (outboundClosed) {
throw new IOException("writer side was already closed.");
}
outputRecord.write(authenticator, writeCipher);
/*
* Did our handshakers notify that we just sent the
* Finished message?
*
* Add an "I'm finished" message to the queue.
*/
if (outputRecord.isFinishedMsg()) {
outboundList.addLast(HandshakeStatus.FINISHED);
}
}
private void runDelegatedTasks(SSLEngineResult result)
{
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK)
{
Runnable runnable;
while ((runnable = _sslEngine.getDelegatedTask()) != null)
{
runnable.run();
}
HandshakeStatus hsStatus = _sslEngine.getHandshakeStatus();
if (hsStatus == HandshakeStatus.NEED_TASK)
{
throw new RuntimeException("handshake shouldn't need additional tasks");
}
}
}
/**
* Sends a SSL close message, will not physically close the connection here.<br>
* To close the connection, you could do something like
* <pre><code>
* close();
* while (isOpen() && !myTimeoutFunction()) Thread.sleep(25);
* if ( isOpen() ) close(true); //forces a close if you timed out
* </code></pre>
* @throws IOException if an I/O error occurs
* @throws IOException if there is data on the outgoing network buffer and we are unable to flush it
* TODO Implement this java.io.Closeable method
*/
@Override
public void close() throws IOException {
if (closing) return;
closing = true;
sslEngine.closeOutbound();
if (!flush(netOutBuffer)) {
throw new IOException("Remaining data in the network buffer, can't send SSL close message, force a close with close(true) instead");
}
//prep the buffer for the close message
netOutBuffer.clear();
//perform the close, since we called sslEngine.closeOutbound
SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer);
//we should be in a close state
if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) {
throw new IOException("Invalid close state, will not send network data.");
}
//prepare the buffer for writing
netOutBuffer.flip();
//if there is data to be written
flush(netOutBuffer);
//is the channel closed?
closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));
}
/**
* Runs all tasks needed to continue SSL work.
*
* @return Handshake status after running all tasks.
*/
private HandshakeStatus runTasks() {
Runnable runnable;
while ((runnable = sslEngine.getDelegatedTask()) != null) {
if (log.isDebugEnabled())
log.debug("Running SSL engine task: " + runnable + '.');
runnable.run();
}
if (log.isDebugEnabled())
log.debug("Finished running SSL engine tasks. HandshakeStatus: " + sslEngine.getHandshakeStatus());
return sslEngine.getHandshakeStatus();
}
/**
* Perform handshake unwrap
* @param doread boolean
* @return the result
* @throws IOException An IO error occurred
*/
protected SSLEngineResult handshakeUnwrap(boolean doread) throws IOException {
if (netInBuffer.position() == netInBuffer.limit()) {
//clear the buffer if we have emptied it out on data
netInBuffer.clear();
}
if (doread) {
//if we have data to read, read it
int read = sc.read(netInBuffer);
if (read == -1) {
throw new IOException(sm.getString("channel.nio.ssl.eofDuringHandshake"));
}
}
SSLEngineResult result;
boolean cont = false;
//loop while we can perform pure SSLEngine data
do {
//prepare the buffer with the incoming data
netInBuffer.flip();
//call unwrap
getBufHandler().configureReadBufferForWrite();
result = sslEngine.unwrap(netInBuffer, getBufHandler().getReadBuffer());
//compact the buffer, this is an optional method, wonder what would happen if we didn't
netInBuffer.compact();
//read in the status
handshakeStatus = result.getHandshakeStatus();
if ( result.getStatus() == SSLEngineResult.Status.OK &&
result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) {
//execute tasks if we need to
handshakeStatus = tasks();
}
//perform another unwrap?
cont = result.getStatus() == SSLEngineResult.Status.OK &&
handshakeStatus == HandshakeStatus.NEED_UNWRAP;
}while ( cont );
return result;
}
HandshakeStatus getHandshakeStatus() {
if (!outputRecord.isEmpty()) {
// If no handshaking, special case to wrap alters or
// post-handshake messages.
return HandshakeStatus.NEED_WRAP;
} else if (isOutboundClosed() && isInboundClosed()) {
return HandshakeStatus.NOT_HANDSHAKING;
} else if (handshakeContext != null) {
if (!handshakeContext.delegatedActions.isEmpty()) {
return HandshakeStatus.NEED_TASK;
} else if (!isInboundClosed()) {
//JDK8 NEED_UNWRAP returnned for NEED_UNWRAP_AGAIN status
// needUnwrapAgain should be used to determine NEED_UNWRAP_AGAIN
return HandshakeStatus.NEED_UNWRAP;
} else if (!isOutboundClosed()) {
// Special case that the inbound was closed, but outbound open.
return HandshakeStatus.NEED_WRAP;
}
} else if (isOutboundClosed() && !isInboundClosed()) {
// Special case that the outbound was closed, but inbound open.
return HandshakeStatus.NEED_UNWRAP;
} else if (!isOutboundClosed() && isInboundClosed()) {
// Special case that the inbound was closed, but outbound open.
return HandshakeStatus.NEED_WRAP;
}
return HandshakeStatus.NOT_HANDSHAKING;
}
HandshakeStatus finishHandshake() {
if (protocolVersion.useTLS13PlusSpec()) {
outputRecord.tc = this;
inputRecord.tc = this;
cipherSuite = handshakeContext.negotiatedCipherSuite;
inputRecord.readCipher.baseSecret =
handshakeContext.baseReadSecret;
outputRecord.writeCipher.baseSecret =
handshakeContext.baseWriteSecret;
}
handshakeContext = null;
outputRecord.handshakeHash.finish();
inputRecord.finishHandshake();
outputRecord.finishHandshake();
isNegotiated = true;
// Tell folk about handshake completion, but do it in a separate thread.
if (transport instanceof SSLSocket &&
sslConfig.handshakeListeners != null &&
!sslConfig.handshakeListeners.isEmpty()) {
HandshakeCompletedEvent hce =
new HandshakeCompletedEvent((SSLSocket)transport, conSession);
//JDK8
Thread thread = new Thread(
null,
new NotifyHandshake(sslConfig.handshakeListeners, hce),
"HandshakeCompletedNotify-Thread",
0);
thread.start();
}
return HandshakeStatus.FINISHED;
}
private void renegotiateIfNeeded(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();
handshake0();
}
}
private static void dumpResult(String str, SSLEngineResult result) {
System.err.println("The format of the SSLEngineResult is: \n" +
"\t\"getStatus() / getHandshakeStatus()\" +\n" +
"\t\"bytesConsumed() / bytesProduced()\"\n");
HandshakeStatus hsStatus = result.getHandshakeStatus();
System.err.println(str + result.getStatus() + "/" + hsStatus + ", " +
result.bytesConsumed() + "/" + result.bytesProduced() + " bytes");
if (hsStatus == HandshakeStatus.FINISHED) {
System.err.println("\t...ready for application data");
}
}
private static void runDelegatedTasks(SSLEngineResult result,
SSLEngine engine) throws Exception {
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable;
while ((runnable = engine.getDelegatedTask()) != null) {
runnable.run();
}
HandshakeStatus hsStatus = engine.getHandshakeStatus();
if (hsStatus == HandshakeStatus.NEED_TASK) {
throw new Exception(
"handshake shouldn't need additional tasks");
}
}
}
private HandshakeStatus getOutboundData(ByteBuffer dstBB) {
Object msg = outboundList.removeFirst();
assert(msg instanceof ByteBuffer);
ByteBuffer bbIn = (ByteBuffer) msg;
assert(dstBB.remaining() >= bbIn.remaining());
dstBB.put(bbIn);
/*
* If we have more data in the queue, it's either
* a finished message, or an indication that we need
* to call wrap again.
*/
if (hasOutboundDataInternal()) {
msg = outboundList.getFirst();
if (msg == HandshakeStatus.FINISHED) {
outboundList.removeFirst(); // consume the message
return HandshakeStatus.FINISHED;
} else {
return HandshakeStatus.NEED_WRAP;
}
} else {
return null;
}
}
/**
* Attempts to decode SSL/TLS network data into a subsequence of plaintext application data
* buffers. Depending on the state of the TLSWrapper, this method may consume network data
* without producing any application data (for example, it may consume handshake data.)
*
* If this TLSWrapper has not yet started its initial handshake, this method will automatically
* start the handshake.
*
* @param net a ByteBuffer containing inbound network data
* @param app a ByteBuffer to hold inbound application data
* @return a ByteBuffer containing inbound application data
* @throws SSLException A problem was encountered while processing the data that caused the
* TLSHandler to abort.
*/
public ByteBuffer unwrap(ByteBuffer net, ByteBuffer app) throws SSLException {
ByteBuffer out = app;
out = resizeApplicationBuffer(out);// guarantees enough room for unwrap
// Record a hex dump of the buffer, but only when logging on level 'debug'.
// Create the dump before the buffer is being passed to tlsEngine, to ensure
// that the original content of the buffer is logged.
String hexDump = null;
if ( Log.isDebugEnabled() )
{
final ByteBuffer bb = net.duplicate();
final byte[] data = Arrays.copyOf( bb.array(), bb.limit() );
hexDump = StringUtils.encodeHex( data );
}
try {
tlsEngineResult = tlsEngine.unwrap( net, out );
} catch ( SSLException e ) {
if ( e.getMessage().startsWith( "Unsupported record version Unknown-" ) ) {
Log.debug( "Buffer that wasn't TLS: {}", hexDump );
throw new SSLException( "We appear to have received plain text data where we expected encrypted data. A common cause for this is a peer sending us a plain-text error message when it shouldn't send a message, but close the socket instead).", e );
}
else {
throw e;
}
}
log("server unwrap: ", tlsEngineResult);
if (tlsEngineResult.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
// If the result indicates that we have outstanding tasks to do, go
// ahead and run them in this thread.
doTasks();
}
return out;
}
private static void runDelegatedTasks(SSLEngineResult result,
SSLEngine engine) throws Exception {
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable;
while ((runnable = engine.getDelegatedTask()) != null) {
runnable.run();
}
HandshakeStatus hsStatus = engine.getHandshakeStatus();
if (hsStatus == HandshakeStatus.NEED_TASK) {
throw new Exception(
"handshake shouldn't need additional tasks");
}
}
}
void doHandshake(HandshakeStatus hs_status) throws IOException {
try {
this.handshaking.lock();
SSLStreams.WrapperResult r;
for(ByteBuffer tmp = this.allocate(SSLStreams.BufType.APPLICATION); hs_status != HandshakeStatus.FINISHED && hs_status != HandshakeStatus.NOT_HANDSHAKING; hs_status = r.result.getHandshakeStatus()) {
r = null;
Runnable task;
switch(hs_status) {
case NEED_TASK:
while((task = this.engine.getDelegatedTask()) != null) {
task.run();
}
case NEED_WRAP:
break;
case NEED_UNWRAP:
tmp.clear();
r = this.wrapper.recvAndUnwrap(tmp);
if (r.buf != tmp) {
tmp = r.buf;
}
assert tmp.position() == 0;
default:
continue;
}
tmp.clear();
tmp.flip();
r = this.wrapper.wrapAndSend(tmp);
}
} finally {
this.handshaking.unlock();
}
}