下面列出了javax.net.ssl.SSLEngine#closeOutbound ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Test
public void testBeginHandshakeAfterEngineClosed() throws SSLException {
clientSslCtx = SslContextBuilder
.forClient()
.sslProvider(sslClientProvider())
.build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
try {
client.closeInbound();
client.closeOutbound();
try {
client.beginHandshake();
fail();
} catch (SSLException expected) {
// expected
}
} finally {
cleanupClientSslEngine(client);
}
}
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 static void testClientContextFromFile(SslProvider provider) throws Exception {
SelfSignedCertificate cert = new SelfSignedCertificate();
SslContextBuilder builder = SslContextBuilder.forClient()
.sslProvider(provider)
.keyManager(cert.certificate(),
cert.privateKey())
.trustManager(cert.certificate())
.clientAuth(ClientAuth.OPTIONAL);
SslContext context = builder.build();
SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
assertFalse(engine.getWantClientAuth());
assertFalse(engine.getNeedClientAuth());
engine.closeInbound();
engine.closeOutbound();
}
private static void testClientContext(SslProvider provider) throws Exception {
SelfSignedCertificate cert = new SelfSignedCertificate();
SslContextBuilder builder = SslContextBuilder.forClient()
.sslProvider(provider)
.keyManager(cert.key(), cert.cert())
.trustManager(cert.cert())
.clientAuth(ClientAuth.OPTIONAL);
SslContext context = builder.build();
SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
assertFalse(engine.getWantClientAuth());
assertFalse(engine.getNeedClientAuth());
engine.closeInbound();
engine.closeOutbound();
}
private static void testServerContextFromFile(SslProvider provider) throws Exception {
SelfSignedCertificate cert = new SelfSignedCertificate();
SslContextBuilder builder = SslContextBuilder.forServer(cert.certificate(), cert.privateKey())
.sslProvider(provider)
.trustManager(cert.certificate())
.clientAuth(ClientAuth.OPTIONAL);
SslContext context = builder.build();
SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
assertTrue(engine.getWantClientAuth());
assertFalse(engine.getNeedClientAuth());
engine.closeInbound();
engine.closeOutbound();
}
private static void testServerContext(SslProvider provider) throws Exception {
SelfSignedCertificate cert = new SelfSignedCertificate();
SslContextBuilder builder = SslContextBuilder.forServer(cert.key(), cert.cert())
.sslProvider(provider)
.trustManager(cert.cert())
.clientAuth(ClientAuth.REQUIRE);
SslContext context = builder.build();
SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
assertFalse(engine.getWantClientAuth());
assertTrue(engine.getNeedClientAuth());
engine.closeInbound();
engine.closeOutbound();
}
protected void testEnablingAnAlreadyDisabledSslProtocol(String[] protocols1, String[] protocols2) throws Exception {
SSLEngine sslEngine = null;
try {
File serverKeyFile = new File(getClass().getResource("test_unencrypted.pem").getFile());
File serverCrtFile = new File(getClass().getResource("test.crt").getFile());
serverSslCtx = SslContextBuilder.forServer(serverCrtFile, serverKeyFile)
.sslProvider(sslServerProvider())
.sslContextProvider(serverSslContextProvider())
.build();
sslEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
// Disable all protocols
sslEngine.setEnabledProtocols(EmptyArrays.EMPTY_STRINGS);
// The only protocol that should be enabled is SSLv2Hello
String[] enabledProtocols = sslEngine.getEnabledProtocols();
assertArrayEquals(protocols1, enabledProtocols);
// Enable a protocol that is currently disabled
sslEngine.setEnabledProtocols(new String[]{ PROTOCOL_TLS_V1_2 });
// The protocol that was just enabled should be returned
enabledProtocols = sslEngine.getEnabledProtocols();
assertEquals(protocols2.length, enabledProtocols.length);
assertArrayEquals(protocols2, enabledProtocols);
} finally {
if (sslEngine != null) {
sslEngine.closeInbound();
sslEngine.closeOutbound();
cleanupServerSslEngine(sslEngine);
}
}
}
@Test
public void testWrapAfterCloseOutbound() throws Exception {
SelfSignedCertificate cert = new SelfSignedCertificate();
clientSslCtx = SslContextBuilder
.forClient()
.trustManager(cert.cert())
.sslProvider(sslClientProvider())
.build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider())
.build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
try {
ByteBuffer dst = allocateBuffer(client.getSession().getPacketBufferSize());
ByteBuffer src = allocateBuffer(1024);
handshake(client, server);
// This will produce a close_notify
client.closeOutbound();
SSLEngineResult result = client.wrap(src, dst);
assertEquals(SSLEngineResult.Status.CLOSED, result.getStatus());
assertEquals(0, result.bytesConsumed());
assertTrue(result.bytesProduced() > 0);
assertTrue(client.isOutboundDone());
assertFalse(client.isInboundDone());
} finally {
cert.delete();
cleanupClientSslEngine(client);
cleanupServerSslEngine(server);
}
}
@Test
public void testClientContext() throws Exception {
SslContextGMBuilder builder = SslContextGMBuilder.forClient()
.keyManager(ENC_CERT, ENC_KEY, SIGN_CERT, SIGN_KEY, null)
.trustManager(TRUST_CERT)
.clientAuth(ClientAuth.OPTIONAL);
SslContext context = builder.build();
SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
assertFalse(engine.getWantClientAuth());
assertFalse(engine.getNeedClientAuth());
engine.closeInbound();
engine.closeOutbound();
}
@Test
public void testServerContext() throws Exception {
SslContextGMBuilder builder = SslContextGMBuilder.forServer(ENC_CERT, ENC_KEY, SIGN_CERT, SIGN_KEY, null)
.trustManager(TRUST_CERT)
.clientAuth(ClientAuth.REQUIRE);
SslContext context = builder.build();
SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
assertFalse(engine.getWantClientAuth());
assertTrue(engine.getNeedClientAuth());
engine.closeInbound();
engine.closeOutbound();
}
@Override
protected void doStart() throws Exception
{
super.doStart();
final SSLEngine engine = _sslContextFactory.newSSLEngine();
engine.setUseClientMode(false);
final SSLSession session = engine.getSession();
if (session.getPacketBufferSize() > this.getInputBufferSize())
{
this.setInputBufferSize(session.getPacketBufferSize());
}
engine.closeInbound();
engine.closeOutbound();
}
private void doHandshake(SocketChannel socketChannel, SSLEngine sslEngine, ByteBuffer myNetData, ByteBuffer peerNetData)
throws IOException {
// Create byte buffers to use for holding application data
int appBufferSize = sslEngine.getSession().getApplicationBufferSize();
ByteBuffer myAppData = ByteBuffer.allocate(appBufferSize);
ByteBuffer peerAppData = ByteBuffer.allocate(appBufferSize);
SSLEngineResult.HandshakeStatus hs = sslEngine.getHandshakeStatus();
// Process handshaking message
while (hs != SSLEngineResult.HandshakeStatus.FINISHED && hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
switch (hs) {
case NEED_UNWRAP:
// Receive handshaking data from peer
if (socketChannel.read(peerNetData) < 0) {
throw new SocketException("Channel closed");
}
// Process incoming handshaking data
peerNetData.flip();
SSLEngineResult res = sslEngine.unwrap(peerNetData, peerAppData);
peerNetData.compact();
hs = res.getHandshakeStatus();
// Check status
switch (res.getStatus()) {
case OK:
// Handle OK status
break;
case BUFFER_OVERFLOW:
peerAppData = enlargeBuffer(peerNetData, peerAppData);
break;
case BUFFER_UNDERFLOW:
break;
}
break;
case NEED_WRAP:
// Empty the local network packet buffer.
myNetData.clear();
// Generate handshaking data
res = sslEngine.wrap(myAppData, myNetData);
hs = res.getHandshakeStatus();
// Check status
switch (res.getStatus()) {
case OK:
myNetData.flip();
// Send the handshaking data to peer
while (myNetData.hasRemaining()) {
if (socketChannel.write(myNetData) < 0) {
// Handle closed channel
}
}
break;
case BUFFER_OVERFLOW:
myNetData = enlargeBuffer(myAppData, myNetData);
break;
case BUFFER_UNDERFLOW:
break;
case CLOSED:
if (sslEngine.isOutboundDone()) {
return;
} else {
sslEngine.closeOutbound();
hs = sslEngine.getHandshakeStatus();
break;
}
default:
throw new IOException("Cannot wrap data: " + res.getStatus());
}
break;
case NEED_TASK:
Runnable task;
while ((task = sslEngine.getDelegatedTask()) != null) {
task.run();
}
hs = sslEngine.getHandshakeStatus();
break;
case FINISHED:
return;
}
}
}
/**
* Close engines by sending "close outbound" message from one SSLEngine to
* another.
*
* @param fromEngine - Sending engine.
* @param toEngine - Receiving engine.
* @throws SSLException - thrown on engine errors.
*/
public static void closeEngines(SSLEngine fromEngine,
SSLEngine toEngine) throws SSLException {
String from = null;
String to = null;
ByteBuffer app;
if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) {
from = "Client";
to = "Server";
} else if (toEngine.getUseClientMode() &&
!fromEngine.getUseClientMode()) {
from = "Server";
to = "Client";
} else {
throw new Error("Both engines are in the same mode");
}
System.out.println("=============================================");
System.out.println(
"Trying to close engines from " + from + " to " + to);
// Sending close outbound request to peer
fromEngine.closeOutbound();
app = ByteBuffer.allocate(
fromEngine.getSession().getApplicationBufferSize());
net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);
doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);
app = ByteBuffer.allocate(
fromEngine.getSession().getApplicationBufferSize());
net = doWrap(toEngine, to, 0, app, SSLEngineResult.Status.CLOSED);
doUnWrap(fromEngine, from, net, SSLEngineResult.Status.CLOSED);
if (!toEngine.isInboundDone()) {
throw new AssertionError(from + " sent close request to " + to
+ ", but " + to + "did not close inbound.");
}
// Executing close inbound
fromEngine.closeInbound();
app = ByteBuffer.allocate(
fromEngine.getSession().getApplicationBufferSize());
net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);
doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);
if (!toEngine.isOutboundDone()) {
throw new AssertionError(from + "sent close request to " + to
+ ", but " + to + "did not close outbound.");
}
System.out.println("Successful closing from " + from + " to " + to);
}
private static HandshakeHolder doHandshakeUnwrap(final SocketChannel socketChannel, final SSLEngine sslEngine,
ByteBuffer peerAppData, ByteBuffer peerNetData, final int appBufferSize) throws IOException {
if (socketChannel == null || sslEngine == null || peerAppData == null || peerNetData == null || appBufferSize < 0) {
return new HandshakeHolder(peerAppData, peerNetData, false);
}
if (socketChannel.read(peerNetData) < 0) {
if (sslEngine.isInboundDone() && sslEngine.isOutboundDone()) {
return new HandshakeHolder(peerAppData, peerNetData, false);
}
try {
sslEngine.closeInbound();
} catch (SSLException e) {
s_logger.warn("This SSL engine was forced to close inbound due to end of stream.", e);
}
sslEngine.closeOutbound();
// After closeOutbound the engine will be set to WRAP state,
// in order to try to send a close message to the client.
return new HandshakeHolder(peerAppData, peerNetData, true);
}
peerNetData.flip();
SSLEngineResult result = null;
try {
result = sslEngine.unwrap(peerNetData, peerAppData);
peerNetData.compact();
} catch (final SSLException sslException) {
s_logger.error(String.format("SSL error caught during unwrap data: %s, for local address=%s, remote address=%s. The client may have invalid ca-certificates.",
sslException.getMessage(), socketChannel.getLocalAddress(), socketChannel.getRemoteAddress()));
sslEngine.closeOutbound();
return new HandshakeHolder(peerAppData, peerNetData, false);
}
if (result == null) {
return new HandshakeHolder(peerAppData, peerNetData, false);
}
switch (result.getStatus()) {
case OK:
break;
case BUFFER_OVERFLOW:
// Will occur when peerAppData's capacity is smaller than the data derived from peerNetData's unwrap.
peerAppData = enlargeBuffer(peerAppData, appBufferSize);
break;
case BUFFER_UNDERFLOW:
// Will occur either when no data was read from the peer or when the peerNetData buffer
// was too small to hold all peer's data.
peerNetData = handleBufferUnderflow(sslEngine, peerNetData);
break;
case CLOSED:
if (sslEngine.isOutboundDone()) {
return new HandshakeHolder(peerAppData, peerNetData, false);
} else {
sslEngine.closeOutbound();
}
break;
default:
throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
}
return new HandshakeHolder(peerAppData, peerNetData, true);
}
private static HandshakeHolder doHandshakeWrap(final SocketChannel socketChannel, final SSLEngine sslEngine,
ByteBuffer myAppData, ByteBuffer myNetData, ByteBuffer peerNetData,
final int netBufferSize) throws IOException {
if (socketChannel == null || sslEngine == null || myNetData == null || peerNetData == null
|| myAppData == null || netBufferSize < 0) {
return new HandshakeHolder(myAppData, myNetData, false);
}
myNetData.clear();
SSLEngineResult result = null;
try {
result = sslEngine.wrap(myAppData, myNetData);
} catch (final SSLException sslException) {
s_logger.error(String.format("SSL error caught during wrap data: %s, for local address=%s, remote address=%s.",
sslException.getMessage(), socketChannel.getLocalAddress(), socketChannel.getRemoteAddress()));
sslEngine.closeOutbound();
return new HandshakeHolder(myAppData, myNetData, true);
}
if (result == null) {
return new HandshakeHolder(myAppData, myNetData, false);
}
switch (result.getStatus()) {
case OK :
myNetData.flip();
while (myNetData.hasRemaining()) {
socketChannel.write(myNetData);
}
break;
case BUFFER_OVERFLOW:
// Will occur if there is not enough space in myNetData buffer to write all the data
// that would be generated by the method wrap. Since myNetData is set to session's packet
// size we should not get to this point because SSLEngine is supposed to produce messages
// smaller or equal to that, but a general handling would be the following:
myNetData = enlargeBuffer(myNetData, netBufferSize);
break;
case BUFFER_UNDERFLOW:
throw new SSLException("Buffer underflow occurred after a wrap. We should not reach here.");
case CLOSED:
try {
myNetData.flip();
while (myNetData.hasRemaining()) {
socketChannel.write(myNetData);
}
// At this point the handshake status will probably be NEED_UNWRAP
// so we make sure that peerNetData is clear to read.
peerNetData.clear();
} catch (Exception e) {
s_logger.error("Failed to send server's CLOSE message due to socket channel's failure.");
}
break;
default:
throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
}
return new HandshakeHolder(myAppData, myNetData, true);
}