use of javax.net.ssl.SSLEngineResult.Status in project baseio by generallycloud.
the class SslHandler method wrap.
public ByteBuf wrap(SocketChannel channel, ByteBuf src) throws IOException {
SSLEngine engine = channel.getSSLEngine();
ByteBuf dst = getTempDst(engine);
ByteBuf out = null;
try {
for (; ; ) {
dst.clear();
SSLEngineResult result = engine.wrap(src.nioBuffer(), dst.nioBuffer());
Status status = result.getStatus();
HandshakeStatus handshakeStatus = result.getHandshakeStatus();
synchByteBuf(result, src, dst);
if (status == Status.CLOSED) {
return gc(channel, dst.flip());
}
if (handshakeStatus != HandshakeStatus.NOT_HANDSHAKING) {
if (handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
if (out != null) {
out.read(dst.flip());
return out.flip();
}
return gc(channel, dst.flip());
} else if (handshakeStatus == HandshakeStatus.NEED_WRAP) {
if (out == null) {
out = allocate(channel, 256);
}
out.read(dst.flip());
continue;
} else if (handshakeStatus == HandshakeStatus.FINISHED) {
channel.finishHandshake(null);
out.read(dst.flip());
return out.flip();
} else if (handshakeStatus == HandshakeStatus.NEED_TASK) {
runDelegatedTasks(engine);
continue;
}
}
if (src.hasRemaining()) {
if (out == null) {
int outLength = ((src.limit() / src.position()) + 1) * (dst.position() - src.position()) + src.limit();
out = allocate(channel, outLength);
}
out.read(dst.flip());
continue;
}
if (out != null) {
out.read(dst.flip());
return out.flip();
}
return gc(channel, dst.flip());
}
} catch (Throwable e) {
ReleaseUtil.release(out);
if (e instanceof IOException) {
throw (IOException) e;
}
throw new IOException(e);
}
}
use of javax.net.ssl.SSLEngineResult.Status in project webpieces by deanhiller.
the class AsyncSSLEngine3Impl method sendHandshakeMessageImpl.
private XFuture<Void> sendHandshakeMessageImpl(SSLEngine engine) throws SSLException {
SSLEngine sslEngine = mem.getEngine();
if (log.isTraceEnabled())
log.trace(mem + "sending handshake message");
ByteBuffer engineToSocketData = pool.nextBuffer(sslEngine.getSession().getPacketBufferSize());
// CLOSE and all the threads that call feedPlainPacket can have contention on wrapping to encrypt and
// must synchronize on sslEngine.wrap
Status lastStatus;
HandshakeStatus hsStatus;
HandshakeStatus beforeWrapHandshakeStatus;
synchronized (wrapLock) {
// this is in the sync block, so we are synchronized with the engine state!!! and get the actual
// state before calling wrap so we know the engine can't be switching states on us in another thread.
beforeWrapHandshakeStatus = sslEngine.getHandshakeStatus();
HandshakeStatus otherStatus = engine.getHandshakeStatus();
if (beforeWrapHandshakeStatus != HandshakeStatus.NEED_WRAP)
throw new IllegalStateException("we should only be calling this method when hsStatus=NEED_WRAP. hsStatus=" + beforeWrapHandshakeStatus + " connectionState=" + mem.getConnectionState() + " otherStat=" + otherStatus + " eng1=" + sslEngine + " eng2=" + engine);
circularBuffer.add(new Action(Thread.currentThread().getName(), ActionEnum.WRAP2_START, sslEngine));
// KEEEEEP This very small. wrap and then listener.packetEncrypted
SSLEngineResult result = sslEngine.wrap(SslMementoImpl.EMPTY, engineToSocketData);
circularBuffer.add(new Action(Thread.currentThread().getName(), ActionEnum.WRAP2_END, sslEngine));
lastStatus = result.getStatus();
hsStatus = result.getHandshakeStatus();
}
if (log.isTraceEnabled())
log.trace(mem + "write packet pos=" + engineToSocketData.position() + " lim=" + engineToSocketData.limit() + " status=" + lastStatus + " hs=" + hsStatus);
if (lastStatus == Status.BUFFER_OVERFLOW || lastStatus == Status.BUFFER_UNDERFLOW)
throw new RuntimeException("status not right, status=" + lastStatus + " even though we sized the buffer to consume all?");
boolean readNoData = engineToSocketData.position() == 0;
engineToSocketData.flip();
try {
XFuture<Void> sentMsgFuture;
if (readNoData) {
if (log.isTraceEnabled())
log.trace("ssl engine is farting. READ 0 data. hsStatus=" + hsStatus + " status=" + lastStatus + " previous=" + beforeWrapHandshakeStatus);
// Ok, I updated this thread https://stackoverflow.com/questions/56707024/java-sslengine-says-need-wrap-call-wrap-and-still-need-wrap/56822673#56822673
// but basicaly, turning on -Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack
// REALLY REALLY helps and you see that clients send a warning close_notify but I put logs before and after the call to
// sslEngine.wrap and between those logs, the sslEngine logged ZERO debug information and did NOT generate it's
// response close_notify :(. crappy sslEngine. This was in jdk 11.0.3 :(.
// On top of this, downgrading to jdk1.8.0_111 which uses TLSv1.2 instead of TLSv1.3 works
// just fine and sends back the close messages while jdk 11 is not doing that
// so this sslEngineIsFarting is covering up their bug.
// ADDITIONAL(different day): Every time in docker opening client to remote server caused the ssl engine to fart(ie. come into this whacky
// location). This location is specifically SSLEngine tells us to WRAP, and THEN decides to wrap NOTHING!! wtf.
sslEngineIsFarting = true;
sentMsgFuture = XFuture.completedFuture(null);
} else {
metrics.recordEncryptedToSocket(engineToSocketData.remaining());
sentMsgFuture = listener.sendEncryptedHandshakeData(engineToSocketData);
}
if (lastStatus == Status.CLOSED && !clientInitiated) {
fireClose();
} else if (hsStatus == HandshakeStatus.FINISHED) {
fireLinkEstablished();
}
return sentMsgFuture;
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e);
}
}
use of javax.net.ssl.SSLEngineResult.Status in project webpieces by deanhiller.
the class AsyncSSLEngine3Impl method unwrapPacket.
private boolean unwrapPacket() {
SSLEngine sslEngine = mem.getEngine();
HandshakeStatus hsStatus = sslEngine.getHandshakeStatus();
Status status = null;
logTrace1(mem.getCachedToProcess(), hsStatus);
ByteBuffer encryptedData = mem.getCachedToProcess();
SSLEngineResult result;
ByteBuffer cachedOutBuffer = pool.nextBuffer(sslEngine.getSession().getApplicationBufferSize());
int remainBeforeDecrypt = encryptedData.remaining();
try {
circularBuffer.add(new Action(Thread.currentThread().getName(), ActionEnum.UNWRAP_START, sslEngine));
result = sslEngine.unwrap(encryptedData, cachedOutBuffer);
mem.incrementCallToUnwrap();
} catch (SSLException e) {
// read before the buffer is cleared released
// record bytes consumed...
int consumedBytes = remainBeforeDecrypt - encryptedData.remaining();
int numCallToUnwrap = mem.getNumCallToUnwrap();
String extraInfo = createExtraInfo(encryptedData, e);
release(encryptedData, cachedOutBuffer);
mem.setCachedEncryptedData(ByteBuffer.allocate(0));
String message = e.getMessage();
if (message.contains("Received fatal alert: certificate_unknown")) {
// This is normal for self signed certs, so just return. Chrome closes the connection with
// a reason and SSLEngine throws an exception :(
mem.compareSet(ConnectionState.CONNECTING, ConnectionState.DISCONNECTED);
decryptionTracker.ackBytes(consumedBytes);
return true;
}
AsyncSSLEngineException ee = createExc(hsStatus, status, encryptedData, remainBeforeDecrypt, e, consumedBytes, numCallToUnwrap, extraInfo);
throw ee;
} finally {
circularBuffer.add(new Action(Thread.currentThread().getName(), ActionEnum.UNWRAP_END, sslEngine));
}
status = result.getStatus();
hsStatus = result.getHandshakeStatus();
if (status == Status.CLOSED) {
// If we are connected, then the close was remotely initiated
mem.compareSet(ConnectionState.CONNECTED, ConnectionState.DISCONNECTING);
// If we are NOT connected and are in Disconnecting state, then fireClose
if (mem.getConnectionState() == ConnectionState.DISCONNECTING)
fireClose();
}
// If we are in a state of NOT_HANDSHAKING, sometimes the bytes coming off are not enough for a FULL packet so BUFFER_UNDERFLOW will occur
// This is normal
logTrace(encryptedData, status, hsStatus);
int totalBytesToAck = remainBeforeDecrypt - encryptedData.remaining();
if (cachedOutBuffer.position() != 0) {
firePlainPacketToListener(cachedOutBuffer, totalBytesToAck);
} else {
// pretend like all data is consumed
cachedOutBuffer.position(cachedOutBuffer.limit());
// buffer not needed since we did not use it and fill it with data
pool.releaseBuffer(cachedOutBuffer);
if (hsStatus == HandshakeStatus.NEED_WRAP || hsStatus == HandshakeStatus.NEED_TASK) {
// THIS IS COMPLEX HERE. In this case, we need to run a task and/or wrap data and need to
// ack the bytes we just processed ONLY if those things get sent out. If the NIC is putting backpressure
// this then backpressures the incoming side until the peer can consumer our data first
doHandshakeLoop().handle((v, t) -> {
if (t != null)
log.error("Exception in ssl listener", t);
decryptionTracker.ackBytes(totalBytesToAck);
return null;
});
} else {
// The engine consumed the bytes so we are done with them, ack that payload as consumed.
decryptionTracker.ackBytes(totalBytesToAck);
}
}
if (encryptedData.hasRemaining()) {
mem.setCachedEncryptedData(encryptedData);
} else {
mem.setCachedEncryptedData(SslMementoImpl.EMPTY);
pool.releaseBuffer(encryptedData);
}
if (hsStatus == HandshakeStatus.FINISHED)
fireLinkEstablished();
if (status == Status.BUFFER_UNDERFLOW)
return true;
return false;
}
use of javax.net.ssl.SSLEngineResult.Status in project webpieces by deanhiller.
the class AsyncSSLEngine3Impl method feedPlainPacketImpl.
private XFuture<Void> feedPlainPacketImpl(ByteBuffer buffer) throws SSLException {
if (mem.getConnectionState() != ConnectionState.CONNECTED)
throw new NioClosedChannelException(mem + " SSLEngine is not connected right now");
else if (!buffer.hasRemaining())
throw new IllegalArgumentException("your buffer has no readable data");
SSLEngine sslEngine = mem.getEngine();
if (log.isTraceEnabled())
log.trace(mem + "feedPlainPacket [in-buffer] pos=" + buffer.position() + " lim=" + buffer.limit());
XFuture<Void> future = encryptionTracker.addBytesToTrack(buffer.remaining());
while (buffer.hasRemaining()) {
ByteBuffer engineToSocketData = pool.nextBuffer(sslEngine.getSession().getPacketBufferSize());
int remainBefore = buffer.remaining();
int numEncrypted;
SSLEngineResult result;
synchronized (wrapLock) {
circularBuffer.add(new Action(Thread.currentThread().getName(), ActionEnum.WRAP_START, sslEngine));
result = sslEngine.wrap(buffer, engineToSocketData);
circularBuffer.add(new Action(Thread.currentThread().getName(), ActionEnum.WRAP_END, sslEngine));
numEncrypted = remainBefore - buffer.remaining();
}
Status status = result.getStatus();
HandshakeStatus hsStatus = result.getHandshakeStatus();
if (status != Status.OK)
throw new RuntimeException("Bug, status=" + status + " instead of OK. hsStatus=" + hsStatus + " Something went wrong and we could not encrypt the data");
if (log.isTraceEnabled())
log.trace(mem + "SSLListener.packetEncrypted pos=" + engineToSocketData.position() + " lim=" + engineToSocketData.limit() + " hsStatus=" + hsStatus + " status=" + status);
engineToSocketData.flip();
metrics.recordEncryptedToSocket(engineToSocketData.remaining());
listener.packetEncrypted(engineToSocketData).handle((v, t) -> {
if (t != null) {
future.completeExceptionally(t);
}
encryptionTracker.ackBytes(numEncrypted);
return null;
});
}
pool.releaseBuffer(buffer);
return future;
}
use of javax.net.ssl.SSLEngineResult.Status in project webpieces by deanhiller.
the class AsyncSSLEngine2Impl method sendHandshakeMessageImpl.
private XFuture<Void> sendHandshakeMessageImpl() throws SSLException {
SSLEngine sslEngine = mem.getEngine();
if (log.isTraceEnabled())
log.trace(mem + "sending handshake message");
// HELPER.eraseBuffer(empty);
HandshakeStatus hsStatus = sslEngine.getHandshakeStatus();
if (hsStatus != HandshakeStatus.NEED_WRAP)
throw new IllegalStateException("we should only be calling this method when hsStatus=NEED_WRAP. hsStatus=" + hsStatus);
List<XFuture<Void>> futures = new ArrayList<>();
while (hsStatus == HandshakeStatus.NEED_WRAP) {
ByteBuffer engineToSocketData = pool.nextBuffer(sslEngine.getSession().getPacketBufferSize());
Status lastStatus = null;
synchronized (wrapLock) {
// KEEEEEP This very small. wrap and then listener.packetEncrypted
SSLEngineResult result = sslEngine.wrap(EMPTY, engineToSocketData);
lastStatus = result.getStatus();
hsStatus = result.getHandshakeStatus();
final Status lastStatus2 = lastStatus;
final HandshakeStatus hsStatus2 = hsStatus;
if (log.isTraceEnabled())
log.trace(mem + "write packet pos=" + engineToSocketData.position() + " lim=" + engineToSocketData.limit() + " status=" + lastStatus2 + " hs=" + hsStatus2);
if (lastStatus == Status.BUFFER_OVERFLOW || lastStatus == Status.BUFFER_UNDERFLOW)
throw new RuntimeException("status not right, status=" + lastStatus + " even though we sized the buffer to consume all?");
engineToSocketData.flip();
XFuture<Void> fut = listener.sendEncryptedHandshakeData(engineToSocketData);
futures.add(fut);
}
if (lastStatus == Status.CLOSED && !clientInitiated) {
fireClose();
}
}
if (hsStatus == HandshakeStatus.NEED_WRAP || hsStatus == HandshakeStatus.NEED_TASK)
throw new RuntimeException(mem + "BUG, need to implement more here status=" + hsStatus);
final HandshakeStatus hsStatus2 = hsStatus;
if (log.isTraceEnabled())
log.trace(mem + "status=" + hsStatus2 + " isConn=" + mem.getConnectionState());
if (hsStatus == HandshakeStatus.FINISHED) {
fireLinkEstablished();
}
XFuture<Void> futureAll = XFuture.allOf(futures.toArray(new XFuture[futures.size()]));
return futureAll;
}
Aggregations