use of javax.net.ssl.SSLException in project tomcat by apache.
the class WsWebSocketContainer method connectToServer.
// socketChannel is closed
@SuppressWarnings("resource")
@Override
public Session connectToServer(Endpoint endpoint, ClientEndpointConfig clientEndpointConfiguration, URI path) throws DeploymentException {
boolean secure = false;
ByteBuffer proxyConnect = null;
URI proxyPath;
// Validate scheme (and build proxyPath)
String scheme = path.getScheme();
if ("ws".equalsIgnoreCase(scheme)) {
proxyPath = URI.create("http" + path.toString().substring(2));
} else if ("wss".equalsIgnoreCase(scheme)) {
proxyPath = URI.create("https" + path.toString().substring(3));
secure = true;
} else {
throw new DeploymentException(sm.getString("wsWebSocketContainer.pathWrongScheme", scheme));
}
// Validate host
String host = path.getHost();
if (host == null) {
throw new DeploymentException(sm.getString("wsWebSocketContainer.pathNoHost"));
}
int port = path.getPort();
SocketAddress sa = null;
// Check to see if a proxy is configured. Javadoc indicates return value
// will never be null
List<Proxy> proxies = ProxySelector.getDefault().select(proxyPath);
Proxy selectedProxy = null;
for (Proxy proxy : proxies) {
if (proxy.type().equals(Proxy.Type.HTTP)) {
sa = proxy.address();
if (sa instanceof InetSocketAddress) {
InetSocketAddress inet = (InetSocketAddress) sa;
if (inet.isUnresolved()) {
sa = new InetSocketAddress(inet.getHostName(), inet.getPort());
}
}
selectedProxy = proxy;
break;
}
}
// scheme
if (port == -1) {
if ("ws".equalsIgnoreCase(scheme)) {
port = 80;
} else {
// Must be wss due to scheme validation above
port = 443;
}
}
// If sa is null, no proxy is configured so need to create sa
if (sa == null) {
sa = new InetSocketAddress(host, port);
} else {
proxyConnect = createProxyRequest(host, port);
}
// Create the initial HTTP request to open the WebSocket connection
Map<String, List<String>> reqHeaders = createRequestHeaders(host, port, clientEndpointConfiguration.getPreferredSubprotocols(), clientEndpointConfiguration.getExtensions());
clientEndpointConfiguration.getConfigurator().beforeRequest(reqHeaders);
if (Constants.DEFAULT_ORIGIN_HEADER_VALUE != null && !reqHeaders.containsKey(Constants.ORIGIN_HEADER_NAME)) {
List<String> originValues = new ArrayList<>(1);
originValues.add(Constants.DEFAULT_ORIGIN_HEADER_VALUE);
reqHeaders.put(Constants.ORIGIN_HEADER_NAME, originValues);
}
ByteBuffer request = createRequest(path, reqHeaders);
AsynchronousSocketChannel socketChannel;
try {
socketChannel = AsynchronousSocketChannel.open(getAsynchronousChannelGroup());
} catch (IOException ioe) {
throw new DeploymentException(sm.getString("wsWebSocketContainer.asynchronousSocketChannelFail"), ioe);
}
// Get the connection timeout
long timeout = Constants.IO_TIMEOUT_MS_DEFAULT;
String timeoutValue = (String) clientEndpointConfiguration.getUserProperties().get(Constants.IO_TIMEOUT_MS_PROPERTY);
if (timeoutValue != null) {
timeout = Long.valueOf(timeoutValue).intValue();
}
// Set-up
// Same size as the WsFrame input buffer
ByteBuffer response = ByteBuffer.allocate(maxBinaryMessageBufferSize);
String subProtocol;
boolean success = false;
List<Extension> extensionsAgreed = new ArrayList<>();
Transformation transformation = null;
// Open the connection
Future<Void> fConnect = socketChannel.connect(sa);
AsyncChannelWrapper channel = null;
if (proxyConnect != null) {
try {
fConnect.get(timeout, TimeUnit.MILLISECONDS);
// Proxy CONNECT is clear text
channel = new AsyncChannelWrapperNonSecure(socketChannel);
writeRequest(channel, proxyConnect, timeout);
HttpResponse httpResponse = processResponse(response, channel, timeout);
if (httpResponse.getStatus() != 200) {
throw new DeploymentException(sm.getString("wsWebSocketContainer.proxyConnectFail", selectedProxy, Integer.toString(httpResponse.getStatus())));
}
} catch (TimeoutException | InterruptedException | ExecutionException | EOFException e) {
if (channel != null) {
channel.close();
}
throw new DeploymentException(sm.getString("wsWebSocketContainer.httpRequestFailed"), e);
}
}
if (secure) {
// Regardless of whether a non-secure wrapper was created for a
// proxy CONNECT, need to use TLS from this point on so wrap the
// original AsynchronousSocketChannel
SSLEngine sslEngine = createSSLEngine(clientEndpointConfiguration.getUserProperties());
channel = new AsyncChannelWrapperSecure(socketChannel, sslEngine);
} else if (channel == null) {
// Only need to wrap as this point if it wasn't wrapped to process a
// proxy CONNECT
channel = new AsyncChannelWrapperNonSecure(socketChannel);
}
try {
fConnect.get(timeout, TimeUnit.MILLISECONDS);
Future<Void> fHandshake = channel.handshake();
fHandshake.get(timeout, TimeUnit.MILLISECONDS);
writeRequest(channel, request, timeout);
HttpResponse httpResponse = processResponse(response, channel, timeout);
// TODO: Handle redirects
if (httpResponse.status != 101) {
throw new DeploymentException(sm.getString("wsWebSocketContainer.invalidStatus", Integer.toString(httpResponse.status)));
}
HandshakeResponse handshakeResponse = httpResponse.getHandshakeResponse();
clientEndpointConfiguration.getConfigurator().afterResponse(handshakeResponse);
// Sub-protocol
List<String> protocolHeaders = handshakeResponse.getHeaders().get(Constants.WS_PROTOCOL_HEADER_NAME);
if (protocolHeaders == null || protocolHeaders.size() == 0) {
subProtocol = null;
} else if (protocolHeaders.size() == 1) {
subProtocol = protocolHeaders.get(0);
} else {
throw new DeploymentException(sm.getString("wsWebSocketContainer.invalidSubProtocol"));
}
// Extensions
// Should normally only be one header but handle the case of
// multiple headers
List<String> extHeaders = handshakeResponse.getHeaders().get(Constants.WS_EXTENSIONS_HEADER_NAME);
if (extHeaders != null) {
for (String extHeader : extHeaders) {
Util.parseExtensionHeader(extensionsAgreed, extHeader);
}
}
// Build the transformations
TransformationFactory factory = TransformationFactory.getInstance();
for (Extension extension : extensionsAgreed) {
List<List<Extension.Parameter>> wrapper = new ArrayList<>(1);
wrapper.add(extension.getParameters());
Transformation t = factory.create(extension.getName(), wrapper, false);
if (t == null) {
throw new DeploymentException(sm.getString("wsWebSocketContainer.invalidExtensionParameters"));
}
if (transformation == null) {
transformation = t;
} else {
transformation.setNext(t);
}
}
success = true;
} catch (ExecutionException | InterruptedException | SSLException | EOFException | TimeoutException e) {
throw new DeploymentException(sm.getString("wsWebSocketContainer.httpRequestFailed"), e);
} finally {
if (!success) {
channel.close();
}
}
// Switch to WebSocket
WsRemoteEndpointImplClient wsRemoteEndpointClient = new WsRemoteEndpointImplClient(channel);
WsSession wsSession = new WsSession(endpoint, wsRemoteEndpointClient, this, null, null, null, null, null, extensionsAgreed, subProtocol, Collections.<String, String>emptyMap(), secure, clientEndpointConfiguration);
WsFrameClient wsFrameClient = new WsFrameClient(response, channel, wsSession, transformation);
// WsFrame adds the necessary final transformations. Copy the
// completed transformation chain to the remote end point.
wsRemoteEndpointClient.setTransformation(wsFrameClient.getTransformation());
endpoint.onOpen(wsSession, clientEndpointConfiguration);
registerSession(endpoint, wsSession);
/* It is possible that the server sent one or more messages as soon as
* the WebSocket connection was established. Depending on the exact
* timing of when those messages were sent they could be sat in the
* input buffer waiting to be read and will not trigger a "data
* available to read" event. Therefore, it is necessary to process the
* input buffer here. Note that this happens on the current thread which
* means that this thread will be used for any onMessage notifications.
* This is a special case. Subsequent "data available to read" events
* will be handled by threads from the AsyncChannelGroup's executor.
*/
wsFrameClient.startInputProcessing();
return wsSession;
}
use of javax.net.ssl.SSLException in project tomcat by apache.
the class OpenSSLEngine method wrap.
@Override
public synchronized SSLEngineResult wrap(final ByteBuffer[] srcs, final int offset, final int length, final ByteBuffer dst) throws SSLException {
// Check to make sure the engine has not been closed
if (destroyed) {
return new SSLEngineResult(SSLEngineResult.Status.CLOSED, SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, 0, 0);
}
// Throw required runtime exceptions
if (srcs == null || dst == null) {
throw new IllegalArgumentException(sm.getString("engine.nullBuffer"));
}
if (offset >= srcs.length || offset + length > srcs.length) {
throw new IndexOutOfBoundsException(sm.getString("engine.invalidBufferArray", Integer.toString(offset), Integer.toString(length), Integer.toString(srcs.length)));
}
if (dst.isReadOnly()) {
throw new ReadOnlyBufferException();
}
// Prepare OpenSSL to work in server mode and receive handshake
if (accepted == 0) {
beginHandshakeImplicitly();
}
// In handshake or close_notify stages, check if call to wrap was made
// without regard to the handshake status.
SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus();
if ((!handshakeFinished || engineClosed) && handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
return new SSLEngineResult(getEngineStatus(), SSLEngineResult.HandshakeStatus.NEED_UNWRAP, 0, 0);
}
int bytesProduced = 0;
int pendingNet;
// Check for pending data in the network BIO
pendingNet = SSL.pendingWrittenBytesInBIO(networkBIO);
if (pendingNet > 0) {
// Do we have enough room in destination to write encrypted data?
int capacity = dst.remaining();
if (capacity < pendingNet) {
return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW, handshakeStatus, 0, 0);
}
// Write the pending data from the network BIO into the dst buffer
try {
bytesProduced = readEncryptedData(dst, pendingNet);
} catch (Exception e) {
throw new SSLException(e);
}
// for the receipt the peer's close_notify message -- shutdown.
if (isOutboundDone) {
shutdown();
}
return new SSLEngineResult(getEngineStatus(), getHandshakeStatus(), 0, bytesProduced);
}
// There was no pending data in the network BIO -- encrypt any application data
int bytesConsumed = 0;
int endOffset = offset + length;
for (int i = offset; i < endOffset; ++i) {
final ByteBuffer src = srcs[i];
if (src == null) {
throw new IllegalArgumentException(sm.getString("engine.nullBufferInArray"));
}
while (src.hasRemaining()) {
// Write plain text application data to the SSL engine
try {
bytesConsumed += writePlaintextData(src);
} catch (Exception e) {
throw new SSLException(e);
}
// Check to see if the engine wrote data into the network BIO
pendingNet = SSL.pendingWrittenBytesInBIO(networkBIO);
if (pendingNet > 0) {
// Do we have enough room in dst to write encrypted data?
int capacity = dst.remaining();
if (capacity < pendingNet) {
return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW, getHandshakeStatus(), bytesConsumed, bytesProduced);
}
// Write the pending data from the network BIO into the dst buffer
try {
bytesProduced += readEncryptedData(dst, pendingNet);
} catch (Exception e) {
throw new SSLException(e);
}
return new SSLEngineResult(getEngineStatus(), getHandshakeStatus(), bytesConsumed, bytesProduced);
}
}
}
return new SSLEngineResult(getEngineStatus(), getHandshakeStatus(), bytesConsumed, bytesProduced);
}
use of javax.net.ssl.SSLException in project kafka by apache.
the class SslTransportLayer method handshake.
/**
* Performs SSL handshake, non blocking.
* Before application data (kafka protocols) can be sent client & kafka broker must
* perform ssl handshake.
* During the handshake SSLEngine generates encrypted data that will be transported over socketChannel.
* Each SSLEngine operation generates SSLEngineResult , of which SSLEngineResult.handshakeStatus field is used to
* determine what operation needs to occur to move handshake along.
* A typical handshake might look like this.
* +-------------+----------------------------------+-------------+
* | client | SSL/TLS message | HSStatus |
* +-------------+----------------------------------+-------------+
* | wrap() | ClientHello | NEED_UNWRAP |
* | unwrap() | ServerHello/Cert/ServerHelloDone | NEED_WRAP |
* | wrap() | ClientKeyExchange | NEED_WRAP |
* | wrap() | ChangeCipherSpec | NEED_WRAP |
* | wrap() | Finished | NEED_UNWRAP |
* | unwrap() | ChangeCipherSpec | NEED_UNWRAP |
* | unwrap() | Finished | FINISHED |
* +-------------+----------------------------------+-------------+
*
* @throws IOException
*/
@Override
public void handshake() throws IOException {
boolean read = key.isReadable();
boolean write = key.isWritable();
handshakeComplete = false;
handshakeStatus = sslEngine.getHandshakeStatus();
if (!flush(netWriteBuffer)) {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
return;
}
try {
switch(handshakeStatus) {
case NEED_TASK:
log.trace("SSLHandshake NEED_TASK channelId {}, appReadBuffer pos {}, netReadBuffer pos {}, netWriteBuffer pos {}", channelId, appReadBuffer.position(), netReadBuffer.position(), netWriteBuffer.position());
handshakeStatus = runDelegatedTasks();
break;
case NEED_WRAP:
log.trace("SSLHandshake NEED_WRAP channelId {}, appReadBuffer pos {}, netReadBuffer pos {}, netWriteBuffer pos {}", channelId, appReadBuffer.position(), netReadBuffer.position(), netWriteBuffer.position());
handshakeResult = handshakeWrap(write);
if (handshakeResult.getStatus() == Status.BUFFER_OVERFLOW) {
int currentNetWriteBufferSize = netWriteBufferSize();
netWriteBuffer.compact();
netWriteBuffer = Utils.ensureCapacity(netWriteBuffer, currentNetWriteBufferSize);
netWriteBuffer.flip();
if (netWriteBuffer.limit() >= currentNetWriteBufferSize) {
throw new IllegalStateException("Buffer overflow when available data size (" + netWriteBuffer.limit() + ") >= network buffer size (" + currentNetWriteBufferSize + ")");
}
} else if (handshakeResult.getStatus() == Status.BUFFER_UNDERFLOW) {
throw new IllegalStateException("Should not have received BUFFER_UNDERFLOW during handshake WRAP.");
} else if (handshakeResult.getStatus() == Status.CLOSED) {
throw new EOFException();
}
log.trace("SSLHandshake NEED_WRAP channelId {}, handshakeResult {}, appReadBuffer pos {}, netReadBuffer pos {}, netWriteBuffer pos {}", channelId, handshakeResult, appReadBuffer.position(), netReadBuffer.position(), netWriteBuffer.position());
//we will break here otherwise we can do need_unwrap in the same call.
if (handshakeStatus != HandshakeStatus.NEED_UNWRAP || !flush(netWriteBuffer)) {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
break;
}
case NEED_UNWRAP:
log.trace("SSLHandshake NEED_UNWRAP channelId {}, appReadBuffer pos {}, netReadBuffer pos {}, netWriteBuffer pos {}", channelId, appReadBuffer.position(), netReadBuffer.position(), netWriteBuffer.position());
do {
handshakeResult = handshakeUnwrap(read);
if (handshakeResult.getStatus() == Status.BUFFER_OVERFLOW) {
int currentAppBufferSize = applicationBufferSize();
appReadBuffer = Utils.ensureCapacity(appReadBuffer, currentAppBufferSize);
if (appReadBuffer.position() > currentAppBufferSize) {
throw new IllegalStateException("Buffer underflow when available data size (" + appReadBuffer.position() + ") > packet buffer size (" + currentAppBufferSize + ")");
}
}
} while (handshakeResult.getStatus() == Status.BUFFER_OVERFLOW);
if (handshakeResult.getStatus() == Status.BUFFER_UNDERFLOW) {
int currentNetReadBufferSize = netReadBufferSize();
netReadBuffer = Utils.ensureCapacity(netReadBuffer, currentNetReadBufferSize);
if (netReadBuffer.position() >= currentNetReadBufferSize) {
throw new IllegalStateException("Buffer underflow when there is available data");
}
} else if (handshakeResult.getStatus() == Status.CLOSED) {
throw new EOFException("SSL handshake status CLOSED during handshake UNWRAP");
}
log.trace("SSLHandshake NEED_UNWRAP channelId {}, handshakeResult {}, appReadBuffer pos {}, netReadBuffer pos {}, netWriteBuffer pos {}", channelId, handshakeResult, appReadBuffer.position(), netReadBuffer.position(), netWriteBuffer.position());
//so the selector won't invoke this channel if we don't go through the handshakeFinished here.
if (handshakeStatus != HandshakeStatus.FINISHED) {
if (handshakeStatus == HandshakeStatus.NEED_WRAP) {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
} else if (handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
}
break;
}
case FINISHED:
handshakeFinished();
break;
case NOT_HANDSHAKING:
handshakeFinished();
break;
default:
throw new IllegalStateException(String.format("Unexpected status [%s]", handshakeStatus));
}
} catch (SSLException e) {
handshakeFailure();
throw e;
}
}
use of javax.net.ssl.SSLException in project tomcat by apache.
the class TestCustomSsl method doTestCustomTrustManager.
private void doTestCustomTrustManager(boolean serverTrustAll) throws Exception {
Tomcat tomcat = getTomcatInstance();
Assume.assumeTrue("SSL renegotiation has to be supported for this test", TesterSupport.isRenegotiationSupported(getTomcatInstance()));
TesterSupport.configureClientCertContext(tomcat);
// Override the defaults
ProtocolHandler handler = tomcat.getConnector().getProtocolHandler();
if (handler instanceof AbstractHttp11JsseProtocol) {
((AbstractHttp11JsseProtocol<?>) handler).setTruststoreFile(null);
} else {
// Unexpected
fail("Unexpected handler type");
}
if (serverTrustAll) {
tomcat.getConnector().setAttribute("trustManagerClassName", "org.apache.tomcat.util.net.TesterSupport$TrustAllCerts");
}
// Start Tomcat
tomcat.start();
TesterSupport.configureClientSsl();
// Unprotected resource
ByteChunk res = getUrl("https://localhost:" + getPort() + "/unprotected");
assertEquals("OK", res.toString());
// Protected resource
res.recycle();
int rc = -1;
try {
rc = getUrl("https://localhost:" + getPort() + "/protected", res, null, null);
} catch (SocketException se) {
if (serverTrustAll) {
fail(se.getMessage());
se.printStackTrace();
}
} catch (SSLException he) {
if (serverTrustAll) {
fail(he.getMessage());
he.printStackTrace();
}
}
if (serverTrustAll) {
assertEquals(200, rc);
assertEquals("OK-" + TesterSupport.ROLE, res.toString());
} else {
assertTrue(rc != 200);
assertEquals("", res.toString());
}
}
use of javax.net.ssl.SSLException in project jetty.project by eclipse.
the class SelectChannelEndPointSslTest method testTcpClose.
@Test
public void testTcpClose() throws Exception {
// This test replaces SSLSocket() with a very manual SSL client
// so we can close TCP underneath SSL.
SocketChannel client = SocketChannel.open(_connector.socket().getLocalSocketAddress());
client.socket().setSoTimeout(500);
SocketChannel server = _connector.accept();
server.configureBlocking(false);
_manager.accept(server);
SSLEngine engine = __sslCtxFactory.newSSLEngine();
engine.setUseClientMode(true);
engine.beginHandshake();
ByteBuffer appOut = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize());
ByteBuffer sslOut = ByteBuffer.allocate(engine.getSession().getPacketBufferSize() * 2);
ByteBuffer appIn = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize());
ByteBuffer sslIn = ByteBuffer.allocate(engine.getSession().getPacketBufferSize() * 2);
boolean debug = false;
if (debug)
System.err.println(engine.getHandshakeStatus());
int loop = 20;
while (engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) {
if (--loop == 0)
throw new IllegalStateException();
if (engine.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
if (debug)
System.err.printf("sslOut %d-%d-%d%n", sslOut.position(), sslOut.limit(), sslOut.capacity());
if (debug)
System.err.printf("appOut %d-%d-%d%n", appOut.position(), appOut.limit(), appOut.capacity());
SSLEngineResult result = engine.wrap(appOut, sslOut);
if (debug)
System.err.println(result);
sslOut.flip();
int flushed = client.write(sslOut);
if (debug)
System.err.println("out=" + flushed);
sslOut.clear();
}
if (engine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP) {
if (debug)
System.err.printf("sslIn %d-%d-%d%n", sslIn.position(), sslIn.limit(), sslIn.capacity());
if (sslIn.position() == 0) {
int filled = client.read(sslIn);
if (debug)
System.err.println("in=" + filled);
}
sslIn.flip();
if (debug)
System.err.printf("sslIn %d-%d-%d%n", sslIn.position(), sslIn.limit(), sslIn.capacity());
SSLEngineResult result = engine.unwrap(sslIn, appIn);
if (debug)
System.err.println(result);
if (debug)
System.err.printf("sslIn %d-%d-%d%n", sslIn.position(), sslIn.limit(), sslIn.capacity());
if (sslIn.hasRemaining())
sslIn.compact();
else
sslIn.clear();
if (debug)
System.err.printf("sslIn %d-%d-%d%n", sslIn.position(), sslIn.limit(), sslIn.capacity());
}
if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable task;
while ((task = engine.getDelegatedTask()) != null) task.run();
if (debug)
System.err.println(engine.getHandshakeStatus());
}
}
if (debug)
System.err.println("\nSay Hello");
// write a message
appOut.put("HelloWorld".getBytes(StandardCharsets.UTF_8));
appOut.flip();
SSLEngineResult result = engine.wrap(appOut, sslOut);
if (debug)
System.err.println(result);
sslOut.flip();
int flushed = client.write(sslOut);
if (debug)
System.err.println("out=" + flushed);
sslOut.clear();
appOut.clear();
// read the response
int filled = client.read(sslIn);
if (debug)
System.err.println("in=" + filled);
sslIn.flip();
result = engine.unwrap(sslIn, appIn);
if (debug)
System.err.println(result);
if (sslIn.hasRemaining())
sslIn.compact();
else
sslIn.clear();
appIn.flip();
String reply = new String(appIn.array(), appIn.arrayOffset(), appIn.remaining());
appIn.clear();
Assert.assertEquals("HelloWorld", reply);
if (debug)
System.err.println("Shutting down output");
client.socket().shutdownOutput();
filled = client.read(sslIn);
if (debug)
System.err.println("in=" + filled);
if (filled >= 0) {
// this is the old behaviour.
sslIn.flip();
try {
// Since the client closed abruptly, the server is sending a close alert with a failure
engine.unwrap(sslIn, appIn);
Assert.fail();
} catch (SSLException x) {
// Expected
}
}
sslIn.clear();
filled = client.read(sslIn);
Assert.assertEquals(-1, filled);
// TODO This should not be needed
Thread.sleep(100);
Assert.assertFalse(server.isOpen());
}
Aggregations