下面列出了javax.net.ssl.SSLEngineResult#HandshakeStatus ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Test for <code>getStatus()</code> method
*/
public void test_getStatus() {
int[] pos = { 0, 1, 1000, Integer.MAX_VALUE, (Integer.MAX_VALUE - 1) };
SSLEngineResult.Status [] enS =
SSLEngineResult.Status.values();
SSLEngineResult.HandshakeStatus [] enHS =
SSLEngineResult.HandshakeStatus.values();
for (int i = 0; i < enS.length; i++) {
for (int j = 0; j < enHS.length; j++) {
for (int n = 0; n < pos.length; n++) {
for (int l = 0; l < pos.length; ++l) {
SSLEngineResult res = new SSLEngineResult(enS[i],
enHS[j], pos[n], pos[l]);
assertEquals("Incorrect Status", enS[i],
res.getStatus());
}
}
}
}
}
/**
* Test for <code>getHandshakeStatus()</code> method
*/
public void test_getHandshakeStatus() {
int[] pos = { 0, 1, 1000, Integer.MAX_VALUE, (Integer.MAX_VALUE - 1) };
SSLEngineResult.Status [] enS =
SSLEngineResult.Status.values();
SSLEngineResult.HandshakeStatus [] enHS =
SSLEngineResult.HandshakeStatus.values();
for (int i = 0; i < enS.length; i++) {
for (int j = 0; j < enHS.length; j++) {
for (int n = 0; n < pos.length; n++) {
for (int l = 0; l < pos.length; ++l) {
SSLEngineResult res = new SSLEngineResult(enS[i],
enHS[j], pos[n], pos[l]);
assertEquals("Incorrect HandshakeStatus", enHS[j],
res.getHandshakeStatus());
}
}
}
}
}
/**
* Executes all the tasks needed on the same thread.
* @return the status
*/
protected SSLEngineResult.HandshakeStatus tasks() {
Runnable r = null;
while ((r = sslEngine.getDelegatedTask()) != null) {
r.run();
}
return sslEngine.getHandshakeStatus();
}
/**
* Executes all the tasks needed on the same thread.
* @return the status
*/
protected SSLEngineResult.HandshakeStatus tasks() {
Runnable r = null;
while ( (r = sslEngine.getDelegatedTask()) != null) {
r.run();
}
return sslEngine.getHandshakeStatus();
}
void didConnect() throws SSLException {
do {
final int oldStatus = this.status;
if ((oldStatus & (CONNECTING | CONNECTED | HANDSHAKING)) != (CONNECTED | HANDSHAKING)) {
final int newStatus = oldStatus & ~CONNECTING | (CONNECTED | HANDSHAKING);
if (STATUS.compareAndSet(this, oldStatus, newStatus)) {
if ((oldStatus & CONNECTED) != (newStatus & CONNECTED)) {
this.socket.didConnect();
}
if ((oldStatus & HANDSHAKING) != (newStatus & HANDSHAKING)) {
this.socket.willSecure();
}
this.sslEngine.beginHandshake();
final SSLEngineResult.HandshakeStatus handshakeStatus = this.sslEngine.getHandshakeStatus();
switch (handshakeStatus) {
case NEED_UNWRAP:
this.context.flowControl(FlowModifier.ENABLE_READ);
break;
case NEED_WRAP:
this.context.flowControl(FlowModifier.ENABLE_READ_WRITE);
break;
default:
throw new AssertionError(handshakeStatus); // unreachable
}
break;
}
} else {
break;
}
} while (true);
}
private SSLEngineResult.HandshakeStatus doTasks() {
Runnable runnable;
/*
* We could run this in a separate thread, but do in the current for now.
*/
while ((runnable = tlsEngine.getDelegatedTask()) != null) {
runnable.run();
}
return tlsEngine.getHandshakeStatus();
}
@Override
public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
if (accepted == 0 || destroyed != 0) {
return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
}
initSsl();
// Check if we are in the initial handshake phase
if (!handshakeFinished) {
// There is pending data in the network BIO -- call wrap
if (SSL.getInstance().pendingWrittenBytesInBIO(networkBIO) != 0) {
return SSLEngineResult.HandshakeStatus.NEED_WRAP;
}
// No pending data to be sent to the peer
// Check to see if we have finished handshaking
if (SSL.getInstance().isInInit(ssl) == 0) {
handshakeFinished();
return SSLEngineResult.HandshakeStatus.FINISHED;
}
// No pending data and still handshaking
// Must be waiting on the peer to send more data
return SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
}
// Check if we are in the shutdown phase
if (engineClosed) {
// Waiting to send the close_notify message
if (SSL.getInstance().pendingWrittenBytesInBIO(networkBIO) != 0) {
return SSLEngineResult.HandshakeStatus.NEED_WRAP;
}
// Must be waiting to receive the close_notify message
return SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
}
return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
}
/**
* Do all the outstanding handshake tasks in the current Thread.
*/
private SSLEngineResult.HandshakeStatus doTasks() {
Runnable runnable;
/*
* We could run this in a separate thread, but
* do in the current for now.
*/
while ((runnable = sslEngine.getDelegatedTask()) != null) {
runnable.run();
}
return sslEngine.getHandshakeStatus();
}
/**
* 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();
}
/**
* Executes all the tasks needed on the same thread.
* @return HandshakeStatus
*/
protected SSLEngineResult.HandshakeStatus tasks() {
Runnable r = null;
while ( (r = sslEngine.getDelegatedTask()) != null) {
r.run();
}
return sslEngine.getHandshakeStatus();
}
void handshake(SSLEngine engine, ByteBuffer input, CodecCallback callback)
throws IOException {
if (!mHandshakeStarted) {
engine.beginHandshake();
mHandshakeStarted = true;
}
SSLEngineResult.HandshakeStatus status = engine.getHandshakeStatus();
while (!mHandshakeFinished) {
if (mEngineClosed) {
throw new IOException("Handshake failed: Engine is closed.");
}
if (status == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
// Should never happen
throw new IOException("Handshake failed: Invalid handshake status: " + status);
} else if (status == SSLEngineResult.HandshakeStatus.FINISHED) {
mHandshakeFinished = true;
NetBareLog.i("SSL handshake finished!");
if (input.hasRemaining()) {
decode(engine, input, callback);
}
} else if (status == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
status = handshakeWrap(engine, callback).getHandshakeStatus();
} else if (status == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
// Wait next encrypted buffer.
if (!input.hasRemaining()) {
break;
}
status = handshakeUnwrap(engine, input, callback).getHandshakeStatus();
} else if (status == SSLEngineResult.HandshakeStatus.NEED_TASK) {
runDelegatedTasks(engine);
}
}
}
@Override
public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
if (accepted == 0 || destroyed != 0) {
return NOT_HANDSHAKING;
}
// Check if we are in the initial handshake phase
if (!handshakeFinished) {
// There is pending data in the network BIO -- call wrap
if (SSL.pendingWrittenBytesInBIO(networkBIO) != 0) {
return NEED_WRAP;
}
// No pending data to be sent to the peer
// Check to see if we have finished handshaking
if (SSL.isInInit(ssl) == 0) {
handshakeFinished = true;
return FINISHED;
}
// No pending data and still handshaking
// Must be waiting on the peer to send more data
return NEED_UNWRAP;
}
// Check if we are in the shutdown phase
if (engineClosed) {
// Waiting to send the close_notify message
if (SSL.pendingWrittenBytesInBIO(networkBIO) != 0) {
return NEED_WRAP;
}
// Must be waiting to receive the close_notify message
return NEED_UNWRAP;
}
return NOT_HANDSHAKING;
}
@Override
public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
if (accepted == Accepted.NOT || destroyed) {
return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
}
// Check if we are in the initial handshake phase
if (!handshakeFinished) {
// There is pending data in the network BIO -- call wrap
if (sendHandshakeError || SSL.pendingWrittenBytesInBIO(networkBIO) != 0) {
if (sendHandshakeError) {
// After a last wrap, consider it is going to be done
sendHandshakeError = false;
currentHandshake++;
}
return SSLEngineResult.HandshakeStatus.NEED_WRAP;
}
/*
* Tomcat Native stores a count of the completed handshakes in the
* SSL instance and increments it every time a handshake is
* completed. Comparing the handshake count when the handshake
* started to the current handshake count enables this code to
* detect when the handshake has completed.
*
* Obtaining client certificates after the connection has been
* established requires additional checks. We need to trigger
* additional reads until the certificates have been read but we
* don't know how many reads we will need as it depends on both
* client and network behaviour.
*
* The additional reads are triggered by returning NEED_UNWRAP
* rather than FINISHED. This allows the standard I/O code to be
* used.
*
* For TLSv1.2 and below, the handshake completes before the
* renegotiation. We therefore use SSL.renegotiatePending() to
* check on the current status of the renegotiation and return
* NEED_UNWRAP until it completes which means the client
* certificates will have been read from the client.
*
* For TLSv1.3, Tomcat Native sets a flag when post handshake
* authentication is started and updates it once the client
* certificate has been received. We therefore use
* SSL.getPostHandshakeAuthInProgress() to check the current status
* and return NEED_UNWRAP until that methods indicates that PHA is
* no longer in progress.
*/
// No pending data to be sent to the peer
// Check to see if we have finished handshaking
int handshakeCount = SSL.getHandshakeCount(ssl);
if (handshakeCount != currentHandshake && SSL.renegotiatePending(ssl) == 0 &&
(SSL.getPostHandshakeAuthInProgress(ssl) == 0)) {
if (alpn) {
selectedProtocol = SSL.getAlpnSelected(ssl);
if (selectedProtocol == null) {
selectedProtocol = SSL.getNextProtoNegotiated(ssl);
}
}
session.lastAccessedTime = System.currentTimeMillis();
version = SSL.getVersion(ssl);
handshakeFinished = true;
return SSLEngineResult.HandshakeStatus.FINISHED;
}
// No pending data
// Still handshaking / renegotiation / post-handshake auth pending
// Must be waiting on the peer to send more data
return SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
}
// Check if we are in the shutdown phase
if (engineClosed) {
// Waiting to send the close_notify message
if (SSL.pendingWrittenBytesInBIO(networkBIO) != 0) {
return SSLEngineResult.HandshakeStatus.NEED_WRAP;
}
// Must be waiting to receive the close_notify message
return SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
}
return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
}
@Override
public OutputResult output(ByteBuffer outputData, boolean isFinalDataOfElement, boolean destinationAddressChanged,
boolean moreDataAvailable) throws SSLException {
if (outputData != null) {
pendingOutputData.add(outputData);
pendingOutputBytes += outputData.remaining();
if (moreDataAvailable && pendingOutputBytes < MAX_PENDING_OUTPUT_BYTES) {
return OutputResult.NO_OUTPUT;
}
}
ByteBuffer[] outputDataArray = pendingOutputData.toArray(new ByteBuffer[pendingOutputData.size()]);
myNetData.clear();
while (true) {
SSLEngineResult result;
try {
result = engine.wrap(outputDataArray, myNetData);
} catch (SSLException e) {
handleSslException(e);
throw e;
}
debugLogSslEngineResult("wrap", result);
SSLEngineResult.Status engineResultStatus = result.getStatus();
pendingOutputBytes -= result.bytesConsumed();
if (engineResultStatus == SSLEngineResult.Status.OK) {
wrapInBytes += result.bytesConsumed();
wrapOutBytes += result.bytesProduced();
SSLEngineResult.HandshakeStatus handshakeStatus = handleHandshakeStatus(result);
switch (handshakeStatus) {
case NEED_UNWRAP:
// NEED_UNWRAP means that we need to receive something in order to continue the handshake. The
// standard channelSelectedCallback logic will take care of this, as there is eventually always
// a interest to read from the socket.
break;
case NEED_WRAP:
// Same as need task: Cycle the reactor.
case NEED_TASK:
// Note that we also set pendingOutputFilterData in the OutputResult in the NEED_TASK case, as
// we also want to retry the wrap() operation above in this case.
return new OutputResult(true, myNetData);
default:
break;
}
}
switch (engineResultStatus) {
case OK:
// No need to outputData.compact() here, since we do not reuse the buffer.
// Clean up the pending output data.
pruneBufferList(pendingOutputData);
return new OutputResult(!pendingOutputData.isEmpty(), myNetData);
case CLOSED:
pendingOutputData.clear();
return OutputResult.NO_OUTPUT;
case BUFFER_OVERFLOW:
LOGGER.warning("SSLEngine status BUFFER_OVERFLOW, this is hopefully uncommon");
int outputDataRemaining = outputData != null ? outputData.remaining() : 0;
int newCapacity = (int) (1.3 * outputDataRemaining);
// If newCapacity would not increase myNetData, then double it.
if (newCapacity <= myNetData.capacity()) {
newCapacity = 2 * myNetData.capacity();
}
ByteBuffer newMyNetData = ByteBuffer.allocateDirect(newCapacity);
myNetData.flip();
newMyNetData.put(myNetData);
myNetData = newMyNetData;
continue;
case BUFFER_UNDERFLOW:
throw new IllegalStateException(
"Buffer underflow as result of SSLEngine.wrap() should never happen");
}
}
}
void handshake(SSLContextValidatorEngine peerEngine) throws SSLException {
SSLEngineResult.HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus();
while (true) {
switch (handshakeStatus) {
case NEED_WRAP:
handshakeResult = sslEngine.wrap(EMPTY_BUF, netBuffer);
switch (handshakeResult.getStatus()) {
case OK: break;
case BUFFER_OVERFLOW:
netBuffer.compact();
netBuffer = ensureCapacity(netBuffer, sslEngine.getSession().getPacketBufferSize());
netBuffer.flip();
break;
case BUFFER_UNDERFLOW:
case CLOSED:
default:
throw new SSLException("Unexpected handshake status: " + handshakeResult.getStatus());
}
return;
case NEED_UNWRAP:
if (peerEngine.netBuffer.position() == 0) {
return;
}
peerEngine.netBuffer.flip(); // unwrap the data from peer
handshakeResult = sslEngine.unwrap(peerEngine.netBuffer, appBuffer);
peerEngine.netBuffer.compact();
handshakeStatus = handshakeResult.getHandshakeStatus();
switch (handshakeResult.getStatus()) {
case OK: break;
case BUFFER_OVERFLOW:
appBuffer = ensureCapacity(appBuffer, sslEngine.getSession().getApplicationBufferSize());
break;
case BUFFER_UNDERFLOW:
netBuffer = ensureCapacity(netBuffer, sslEngine.getSession().getPacketBufferSize());
break;
case CLOSED:
default:
throw new SSLException("Unexpected handshake status: " + handshakeResult.getStatus());
}
break;
case NEED_TASK:
sslEngine.getDelegatedTask().run();
handshakeStatus = sslEngine.getHandshakeStatus();
break;
case FINISHED:
return;
case NOT_HANDSHAKING:
if (handshakeResult.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.FINISHED) {
throw new SSLException("Did not finish handshake");
}
return;
default:
throw new IllegalStateException("Unexpected handshake status " + handshakeStatus);
}
}
}
@Override
public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
// Check if we are in the initial handshake phase or shutdown phase
return needPendingStatus() ? pendingStatus(SSL.bioLengthNonApplication(networkBIO)) : NOT_HANDSHAKING;
}
private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) {
// Check if we are in the initial handshake phase or shutdown phase
return needPendingStatus() ? pendingStatus(pending) : NOT_HANDSHAKING;
}
public void performHandshake() throws IOException {
if (sslEngine == null) {
return;
}
sslEngine.beginHandshake();
final ByteBuffer emptyMessage = ByteBuffer.allocate(0);
ByteBuffer unwrapBuffer = ByteBuffer.allocate(0);
while (true) {
final SSLEngineResult.HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus();
switch (handshakeStatus) {
case FINISHED:
case NOT_HANDSHAKING:
streamBuffer.clear();
destinationBuffer.clear();
logger.debug("Completed SSL Handshake with Peer {}", peerDescription);
return;
case NEED_TASK:
logger.debug("SSL Handshake with Peer {} Needs Task", peerDescription);
Runnable runnable;
while ((runnable = sslEngine.getDelegatedTask()) != null) {
runnable.run();
}
break;
case NEED_WRAP:
logger.trace("SSL Handshake with Peer {} Needs Wrap", peerDescription);
encrypt(emptyMessage);
final int bytesWritten = write(destinationBuffer);
logger.debug("Wrote {} bytes for NEED_WRAP portion of Handshake", bytesWritten);
break;
case NEED_UNWRAP:
logger.trace("SSL Handshake with Peer {} Needs Unwrap", peerDescription);
while (sslEngine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
final boolean decrypted = decrypt(unwrapBuffer);
if (decrypted) {
logger.trace("Decryption was successful for NEED_UNWRAP portion of Handshake");
break;
}
if (unwrapBuffer.capacity() - unwrapBuffer.position() < 1) {
logger.trace("Enlarging size of Buffer for NEED_UNWRAP portion of Handshake");
// destinationBuffer is not large enough. Need to increase the size.
final ByteBuffer tempBuffer = ByteBuffer.allocate(unwrapBuffer.capacity() + sslEngine.getSession().getApplicationBufferSize());
tempBuffer.put(unwrapBuffer);
unwrapBuffer = tempBuffer;
unwrapBuffer.flip();
continue;
}
logger.trace("Need to read more bytes for NEED_UNWRAP portion of Handshake");
// Need to read more data.
unwrapBuffer.compact();
final int bytesRead = socketChannel.read(unwrapBuffer);
unwrapBuffer.flip();
logger.debug("Read {} bytes for NEED_UNWRAP portion of Handshake", bytesRead);
}
break;
}
}
}
/**
* DTLS produce handshake packets
*/
boolean dtls_produceHandshakePackets(SSLEngine engine, /*SocketAddress socketAddr,*/ String peer_realm,
String side, List<DatagramOverDiameterPacket> packets) throws Exception {
long _t = System.currentTimeMillis();
long _end = _t + DTLS_MAX_HANDSHAKE_DURATION*1000;
boolean endLoops = false;
int loops = DTLS_MAX_HANDSHAKE_LOOPS / 2;
while (!endLoops && System.currentTimeMillis() < _end/*&&
(dtls_serverException == null) && (dtls_clientException == null)*/) {
if (--loops < 0) {
throw new RuntimeException(
"Too much loops to produce handshake packets");
}
ByteBuffer oNet = ByteBuffer.allocate(DTLS_BUFFER_SIZE);
ByteBuffer oApp = ByteBuffer.allocate(0);
SSLEngineResult r = engine.wrap(oApp, oNet);
oNet.flip();
SSLEngineResult.Status rs = r.getStatus();
SSLEngineResult.HandshakeStatus hs = r.getHandshakeStatus();
logger.debug("DTLS " + side + ": " + "----produce handshake packet(" +
loops + ", " + rs + ", " + hs + ")----");
if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
// the client maximum fragment size config does not work?
throw new Exception("Buffer overflow: " +
"incorrect server maximum fragment size");
} else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
logger.debug("DTLS " + side + ": " +
"Produce handshake packets: BUFFER_UNDERFLOW occured");
logger.debug("DTLS " + side + ": " +
"Produce handshake packets: Handshake status: " + hs);
// bad packet, or the client maximum fragment size
// config does not work?
if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
throw new Exception("Buffer underflow: " +
"incorrect server maximum fragment size");
} // otherwise, ignore this packet
} else if (rs == SSLEngineResult.Status.CLOSED) {
throw new Exception("SSLEngine has closed");
} else if (rs == SSLEngineResult.Status.OK) {
// OK
} else {
throw new Exception("Can't reach here, result is " + rs);
}
// SSLEngineResult.Status.OK:
if (oNet.hasRemaining()) {
byte[] ba = new byte[oNet.remaining()];
oNet.get(ba);
DatagramOverDiameterPacket packet = createHandshakePacket(ba, peer_realm);
packets.add(packet);
}
if (hs == SSLEngineResult.HandshakeStatus.FINISHED) {
logger.debug("DTLS " + side + ": " + "Produce handshake packets: "
+ "Handshake status is FINISHED, finish the loop");
return true;
}
boolean endInnerLoop = false;
SSLEngineResult.HandshakeStatus nhs = hs;
while (!endInnerLoop) {
if (nhs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
dtls_runDelegatedTasks(engine);
} else if (nhs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ||
nhs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN ||
nhs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
endInnerLoop = true;
endLoops = true;
} else if (nhs == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
endInnerLoop = true;
} else if (nhs == SSLEngineResult.HandshakeStatus.FINISHED) {
throw new Exception(
"Unexpected status, SSLEngine.getHandshakeStatus() "
+ "shouldn't return FINISHED");
} else {
throw new Exception("Can't reach here, handshake status is "
+ nhs);
}
nhs = engine.getHandshakeStatus();
}
}
return false;
}
SSLEngineResult.HandshakeStatus getHandshakeStatus() {
return _engine.getHandshakeStatus();
}