下面列出了javax.net.ssl.SSLEngineResult#getHandshakeStatus ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* 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;
}
/**
* Does post-handshake logic described <a href="https://tools.ietf.org/html/rfc8446#section-4.6">here</a> if nedded.
*
* @param res Response.
*/
private SSLEngineResult postHandshakeIfNeded(SSLEngineResult res) throws SSLException, IgniteCheckedException {
while (res.getHandshakeStatus() == FINISHED && res.getStatus() == OK) {
if (!inNetBuf.hasRemaining()) {
inNetBuf.clear();
readFromNet();
inNetBuf.flip();
}
res = unwrap0();
handshakeStatus = res.getHandshakeStatus();
if (log.isDebugEnabled())
log.debug("Unrapped post-handshake data [status=" + res.getStatus() + ", handshakeStatus=" +
handshakeStatus + ']');
}
return res;
}
private void testBeginHandshakeCloseOutbound(SSLEngine engine) throws SSLException {
ByteBuffer dst = allocateBuffer(engine.getSession().getPacketBufferSize());
ByteBuffer empty = allocateBuffer(0);
engine.beginHandshake();
engine.closeOutbound();
SSLEngineResult result;
for (;;) {
result = engine.wrap(empty, dst);
dst.flip();
assertEquals(0, result.bytesConsumed());
assertEquals(dst.remaining(), result.bytesProduced());
if (result.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NEED_WRAP) {
break;
}
dst.clear();
}
assertEquals(SSLEngineResult.Status.CLOSED, result.getStatus());
}
private void wrap() throws IOException {
ArrayList<ByteBuffer> wrapped = new ArrayList<>();
while (true) {
// TODO(bgallagher) buffer pooling
ByteBuffer out = ByteBuffer.allocate(engine.getSession().getPacketBufferSize());
SSLEngineResult result = engine.wrap(pending(), out);
if (result.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
throw new SSLException("renegotiation not supported");
}
if (result.bytesProduced() > 0) {
out.flip();
wrapped.add(out);
} else {
break;
}
}
setPending(wrapped.toArray(new ByteBuffer[wrapped.size()]));
}
private int applicationDataWrap(ByteBuffer src) throws IOException {
SSLEngineResult result = sslEngineWrap(src);
if (result.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) throw new SSLException("Renegotiation detected");
switch (result.getStatus()) {
case OK:
return result.bytesConsumed();
case BUFFER_OVERFLOW:
return 0;
default:
throw unexpectedStatusException(result.getStatus());
}
}
@Override
boolean doRead(SocketChannel channel) throws IOException {
ByteBuffer out = getBuffer();
int bytesRead = channel.read(bufferedWrapped);
if (bytesRead < 0) {
fail(new IOException("connection closed"));
return true;
}
bufferedWrapped.flip();
SSLEngineResult.Status status = SSLEngineResult.Status.OK;
while (out.remaining() > 0 && bufferedWrapped.remaining() > 0 && status ==
SSLEngineResult.Status.OK) {
SSLEngineResult result = engine.unwrap(bufferedWrapped, out);
status = result.getStatus();
if (result.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
throw new SSLException("renegotiation not supported");
}
}
bufferedWrapped.compact();
out.flip();
set(out);
return true;
}
public synchronized boolean shutdown() throws IOException
{
shutdown = true;
if (!sslEngine.isOutboundDone())
{
sslEngine.closeOutbound();
}
// Try to "fire-and-forget" the closed notification (RFC2616).
SSLEngineResult result;
if (prepare(outputBuffer, minBufferSize))
{
result = sslEngine.wrap(emptyBuffer, outputBuffer[0]);
if (result.getStatus() != Status.CLOSED)
{
throw new SSLException("Unexpected shutdown status '" + result.getStatus() + '\'');
}
outputBuffer[0].flip();
}
else
{
result = null;
}
flush(outputBuffer[0]);
return !outputBuffer[0].hasRemaining() && (result != null)
&& (result.getHandshakeStatus() != HandshakeStatus.NEED_WRAP);
}
private boolean handleHandshakeResult(SSLEngineResult result) throws IOException {
switch (result.getHandshakeStatus()) {
case NEED_TASK: {
state |= FLAG_IN_HANDSHAKE;
clearReadRequiresWrite();
clearWriteRequiresRead();
runTasks();
return false;
}
case NEED_UNWRAP: {
clearReadRequiresWrite();
state |= FLAG_WRITE_REQUIRES_READ | FLAG_IN_HANDSHAKE;
sink.suspendWrites();
if(anyAreSet(state, FLAG_WRITES_RESUMED)) {
source.resumeReads();
}
return false;
}
case NEED_WRAP: {
clearWriteRequiresRead();
state |= FLAG_READ_REQUIRES_WRITE | FLAG_IN_HANDSHAKE;
source.suspendReads();
if(anyAreSet(state, FLAG_READS_RESUMED)) {
sink.resumeWrites();
}
return false;
}
case FINISHED: {
if(anyAreSet(state, FLAG_IN_HANDSHAKE)) {
state &= ~FLAG_IN_HANDSHAKE;
handshakeCallback.run();
}
}
}
clearReadRequiresWrite();
clearWriteRequiresRead();
return true;
}
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 static void runDelegatedTasks(SSLEngineResult result, SSLEngine engine) {
if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
for (;;) {
Runnable task = engine.getDelegatedTask();
if (task == null) {
break;
}
task.run();
}
}
}
private void wrapHandshake() throws IOException {
ByteBuffer out = ByteBuffer.allocate(engine.getSession().getPacketBufferSize());
SSLEngineResult result;
do {
result = engine.wrap(EMPTY_BUFFER_ARRAY, out);
if (result.bytesProduced() > 0) {
out.flip();
handshakeWriteQueue.add(new WriteFuture(new ByteBuffer[] { out }));
out = ByteBuffer.allocate(engine.getSession().getPacketBufferSize());
}
switch (result.getHandshakeStatus()) {
case FINISHED:
super.finishConnect();
break;
case NEED_TASK:
runDelegatedTasks(engine);
break;
case NEED_UNWRAP:
readAndUnwrapHandshake();
break;
case NEED_WRAP:
case NOT_HANDSHAKING:
break;
}
} while (result.bytesProduced() > 0);
}
private void updateCipherAndProtocolName(SSLEngineResult result)
{
if (result.getHandshakeStatus() == HandshakeStatus.FINISHED)
{
_cipherName = _sslEngine.getCipherSuite();
_protocolName = _sslEngine.getProtocol();
}
}
public static SSLEngineResult.HandshakeStatus doHandshake(SSLEngine tlsEngine,
ByteBuffer netDataBuf,
OutputStream out,
InputStream in){
try {
ByteBuffer empty;
/*Apparently on Android 4.4 (API_19) SSLEngine whines about BUFFER_OVERFLOW for this
buffer even though nothing ever gets written to it*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH){
empty = ByteBuffer.allocate(0);
} else {
empty = ByteBuffer.allocate(tlsEngine.getSession().getApplicationBufferSize());
}
// ClientHello -> netDataBuf
tlsEngine.wrap(empty, netDataBuf);
netDataBuf.flip();
byte[] clientHello = new byte[netDataBuf.limit()];
netDataBuf.get(clientHello);
out.write(ConnectionHelper.intToByteArray(clientHello.length));
out.write(clientHello);
// netDataBuf <- ServerHello..ServerHelloDone
int serverHelloSize = ByteBuffer.wrap(ConnectionHelper.readAll(4, in)).getInt();
byte[] serverHello = ConnectionHelper.readAll(serverHelloSize, in);
netDataBuf.clear();
netDataBuf.put(serverHello);
netDataBuf.flip();
SSLEngineResult result = tlsEngine.unwrap(netDataBuf, empty);
while (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP){
result = tlsEngine.unwrap(netDataBuf, empty);
}
Runnable task = tlsEngine.getDelegatedTask();
while (task != null){
task.run();
task = tlsEngine.getDelegatedTask();
}
// [client]Certificate*..ClientKeyExchange..Finished -> netDataBuf
netDataBuf.clear();
result = tlsEngine.wrap(empty, netDataBuf);
while (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP){
result = tlsEngine.wrap(empty, netDataBuf);
}
netDataBuf.flip();
byte[] clientKeyExchange = new byte[netDataBuf.limit()];
netDataBuf.get(clientKeyExchange);
out.write(ConnectionHelper.intToByteArray(clientKeyExchange.length));
out.write(clientKeyExchange);
// netDataBuf <- ChangeCipherSpec..Finished
int serverChangeCipherSpecSize = ByteBuffer.wrap(ConnectionHelper.readAll(4, in)).getInt();
byte[] serverChangeCipherSpec = ConnectionHelper.readAll(serverChangeCipherSpecSize, in);
netDataBuf.clear();
netDataBuf.put(serverChangeCipherSpec);
netDataBuf.flip();
result = tlsEngine.unwrap(netDataBuf, empty);
while (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP){
result = tlsEngine.unwrap(netDataBuf, empty);
}
/*On Android 8.1 (LineageOS 15.1) on a Xiaomi device (not sure about others) the
SSL_ENGINE may return NEED_WRAP here, so we do that even though no data gets written
by the SSL_ENGINE ???*/
if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
netDataBuf.clear();
result = tlsEngine.wrap(empty, netDataBuf);
// netDataBuf still empty here...
}
/*Apparently on Android 4.4 (API_19) with SSLEngine the latest call tlsEngine.unwrap(..)
that finishes the handshake returns NOT_HANDSHAKING instead of FINISHED as the result*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH){
return result.getHandshakeStatus();
} else {
if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING){
return SSLEngineResult.HandshakeStatus.FINISHED;
} else if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) {
// just in case
return result.getHandshakeStatus();
} else {
return null;
}
}
} catch (IOException e){
return null;
}
}
/**
* Handshake unwrap.
*
* @param ops the current ready operations set.
* @return the interest set to continue or 0 if finished.
* @throws IOException on I/O errors.
*/
private synchronized int unwrap(int ops) throws IOException
{
// Fill the buffer, if applicable.
if ((ops & SelectionKey.OP_READ) != 0)
{
fill(inputBuffer[0]);
}
// Unwrap the buffer.
SSLEngineResult result;
Status status;
do
{
// Prepare the input cache, although no app
// data should be produced during handshake.
prepare(inputCache, minCacheSize);
inputBuffer[0].flip();
try
{
result = sslEngine.unwrap(inputBuffer[0], inputCache[0]);
}
finally
{
inputBuffer[0].compact();
inputCache[0].flip();
}
handshake = result.getHandshakeStatus();
status = result.getStatus();
if (status == Status.OK)
{
if (handshake == HandshakeStatus.NEED_TASK)
{
handshake = runTasks();
}
}
else if (status == Status.BUFFER_UNDERFLOW)
{
return SelectionKey.OP_READ;
}
else
{
// BUFFER_OVERFLOW/CLOSED
throw new IOException("Handshake failed '" + status + '\'');
}
} while (handshake == HandshakeStatus.NEED_UNWRAP);
return 0;
}
/**
* Perform the handshaking step of the TLS connection. We use the `sslEngine' along with the `channel' to exchange messages with the server to setup an
* encrypted channel.
*
* @param sslEngine
* {@link SSLEngine}
* @param channel
* {@link AsynchronousSocketChannel}
* @throws SSLException
* in case of handshake error
*/
private static void performTlsHandshake(SSLEngine sslEngine, AsynchronousSocketChannel channel) throws SSLException {
sslEngine.beginHandshake();
HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus();
// Create byte buffers to use for holding application data
int packetBufferSize = sslEngine.getSession().getPacketBufferSize();
ByteBuffer myNetData = ByteBuffer.allocate(packetBufferSize);
ByteBuffer peerNetData = ByteBuffer.allocate(packetBufferSize);
int appBufferSize = sslEngine.getSession().getApplicationBufferSize();
ByteBuffer myAppData = ByteBuffer.allocate(appBufferSize);
ByteBuffer peerAppData = ByteBuffer.allocate(appBufferSize);
SSLEngineResult res = null;
while (handshakeStatus != HandshakeStatus.FINISHED && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING) {
switch (handshakeStatus) {
case NEED_WRAP:
myNetData.clear();
res = sslEngine.wrap(myAppData, myNetData);
handshakeStatus = res.getHandshakeStatus();
switch (res.getStatus()) {
case OK:
myNetData.flip();
write(channel, myNetData);
break;
case BUFFER_OVERFLOW:
case BUFFER_UNDERFLOW:
case CLOSED:
throw new CJCommunicationsException("Unacceptable SSLEngine result: " + res);
}
break;
case NEED_UNWRAP:
peerNetData.flip(); // Process incoming handshaking data
res = sslEngine.unwrap(peerNetData, peerAppData);
handshakeStatus = res.getHandshakeStatus();
switch (res.getStatus()) {
case OK:
peerNetData.compact();
break;
case BUFFER_OVERFLOW:
// Check if we need to enlarge the peer application data buffer.
final int newPeerAppDataSize = sslEngine.getSession().getApplicationBufferSize();
if (newPeerAppDataSize > peerAppData.capacity()) {
// enlarge the peer application data buffer
ByteBuffer newPeerAppData = ByteBuffer.allocate(newPeerAppDataSize);
newPeerAppData.put(peerAppData);
newPeerAppData.flip();
peerAppData = newPeerAppData;
} else {
peerAppData.compact();
}
break;
case BUFFER_UNDERFLOW:
// Check if we need to enlarge the peer network packet buffer
final int newPeerNetDataSize = sslEngine.getSession().getPacketBufferSize();
if (newPeerNetDataSize > peerNetData.capacity()) {
// enlarge the peer network packet buffer
ByteBuffer newPeerNetData = ByteBuffer.allocate(newPeerNetDataSize);
newPeerNetData.put(peerNetData);
newPeerNetData.flip();
peerNetData = newPeerNetData;
} else {
peerNetData.compact();
}
// obtain more inbound network data and then retry the operation
if (read(channel, peerNetData) < 0) {
throw new CJCommunicationsException("Server does not provide enough data to proceed with SSL handshake.");
}
break;
case CLOSED:
throw new CJCommunicationsException("Unacceptable SSLEngine result: " + res);
}
break;
case NEED_TASK:
sslEngine.getDelegatedTask().run();
handshakeStatus = sslEngine.getHandshakeStatus();
break;
case FINISHED:
case NOT_HANDSHAKING:
break;
}
}
}
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 = unwrap();
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 = unwrap();
// 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();
}
@SuppressLint("TrulyRandom")
private synchronized boolean wrap(final Buffer buffer) throws IOException
{
ByteBuffer bbuf=extractByteBuffer(buffer);
final SSLEngineResult result;
int encrypted_produced = 0;
int decrypted_consumed = 0;
synchronized(bbuf)
{
_outbound.compact();
ByteBuffer out_buffer=_outbound.getByteBuffer();
synchronized(out_buffer)
{
try
{
bbuf.position(buffer.getIndex());
bbuf.limit(buffer.putIndex());
int decrypted_position = bbuf.position();
out_buffer.position(_outbound.putIndex());
out_buffer.limit(out_buffer.capacity());
int encrypted_position = out_buffer.position();
result=_engine.wrap(bbuf,out_buffer);
if (_logger.isDebugEnabled())
_logger.debug("{} wrap {} {} consumed={} produced={}",
_session,
result.getStatus(),
result.getHandshakeStatus(),
result.bytesConsumed(),
result.bytesProduced());
decrypted_consumed = bbuf.position() - decrypted_position;
buffer.skip(decrypted_consumed);
encrypted_produced = out_buffer.position() - encrypted_position;
_outbound.setPutIndex(_outbound.putIndex() + encrypted_produced);
}
catch(SSLException e)
{
_logger.debug(String.valueOf(_endp), e);
_endp.close();
throw e;
}
catch (Exception x)
{
throw new IOException(x);
}
finally
{
out_buffer.position(0);
out_buffer.limit(out_buffer.capacity());
bbuf.position(0);
bbuf.limit(bbuf.capacity());
}
}
}
switch(result.getStatus())
{
case BUFFER_UNDERFLOW:
throw new IllegalStateException();
case BUFFER_OVERFLOW:
break;
case OK:
if (result.getHandshakeStatus()==HandshakeStatus.FINISHED)
_handshook=true;
break;
case CLOSED:
_logger.debug("wrap CLOSE {} {}",this,result);
if (result.getHandshakeStatus()==HandshakeStatus.FINISHED)
_endp.close();
break;
default:
_logger.debug("{} wrap default {}",_session,result);
throw new IOException(result.toString());
}
return decrypted_consumed > 0 || encrypted_produced > 0;
}
/**
* Handshake wrap.
*
* @param ops the current ready operations set.
* @return the interest set to continue or 0 if finished.
* @throws IOException on I/O errors.
*/
private synchronized int wrap(int ops) throws IOException
{
// Prepare the buffer.
if (prepare(outputBuffer, minBufferSize))
{
// Wrap the buffer.
SSLEngineResult result;
Status status;
try
{
result = sslEngine.wrap(emptyBuffer, outputBuffer[0]);
}
finally
{
outputBuffer[0].flip();
}
handshake = result.getHandshakeStatus();
status = result.getStatus();
if (status == Status.OK)
{
if (handshake == HandshakeStatus.NEED_TASK)
{
handshake = runTasks();
}
}
else
{
// BUFFER_OVERFLOW/BUFFER_UNDERFLOW/CLOSED
throw new IOException("Handshake failed '" + status + '\'');
}
}
// Flush the buffer, if applicable.
if ((ops & SelectionKey.OP_WRITE) != 0)
{
flush(outputBuffer[0]);
}
return outputBuffer[0].hasRemaining() ? SelectionKey.OP_WRITE : 0;
}
/**
* Perform any handshaking processing.
*/
void handshake(NextFilter nextFilter) throws Exception {
for (;;) {
switch (handshakeStatus) {
case FINISHED:
// LOGGER.debug("{} processing the FINISHED state", SslFilter.getSessionInfo(session));
handshakeComplete = true;
// Send the SECURE message only if it's the first SSL handshake
if (firstSSLNegociation) {
firstSSLNegociation = false;
if (session.containsAttribute(SslFilter.USE_NOTIFICATION))
scheduleMessageReceived(nextFilter, SslFilter.SESSION_SECURED);
}
// if (!isOutboundDone()) {
// LOGGER.debug("{} is now secured", SslFilter.getSessionInfo(session));
// } else {
// LOGGER.debug("{} is not secured yet", SslFilter.getSessionInfo(session));
// }
return;
case NEED_TASK:
// LOGGER.debug("{} processing the NEED_TASK state", SslFilter.getSessionInfo(session));
handshakeStatus = doTasks();
break;
case NEED_UNWRAP:
// LOGGER.debug("{} processing the NEED_UNWRAP state", SslFilter.getSessionInfo(session));
// we need more data read
if (unwrapHandshake(nextFilter) == Status.BUFFER_UNDERFLOW && handshakeStatus != HandshakeStatus.FINISHED || isInboundDone())
return; // We need more data or the session is closed
break;
case NEED_WRAP:
case NOT_HANDSHAKING:
// LOGGER.debug("{} processing the NEED_WRAP state", SslFilter.getSessionInfo(session));
// 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;
createOutNetBuffer(0);
for (;;) { //NOSONAR
SSLEngineResult result = sslEngine.wrap(SimpleBufferAllocator.emptyBuffer.buf(), outNetBuffer.buf());
if (result.getStatus() != Status.BUFFER_OVERFLOW) {
handshakeStatus = result.getHandshakeStatus();
break;
}
outNetBuffer = IoBuffer.reallocate(outNetBuffer, outNetBuffer.capacity() << 1);
outNetBuffer.limit(outNetBuffer.capacity());
}
outNetBuffer.flip();
writeNetBuffer(nextFilter, false);
break;
default:
String msg = "invalid handshaking state" + handshakeStatus + " while processing the handshake for session " + session.getId();
ExceptionMonitor.getInstance().error(msg);
throw new IllegalStateException(msg);
}
}
}
void handleEnOfSession(final SSLEngineResult result)
{
if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
_sessionClosedListener.onSessionClosed();
}
}