use of javax.net.ssl.SSLHandshakeException in project Openfire by igniterealtime.
the class SocketReadingMode method negotiateTLS.
/**
* Tries to secure the connection using TLS. If the connection is secured then reset
* the parser to use the new secured reader. But if the connection failed to be secured
* then send a <failure> stanza and close the connection.
*
* @return true if the connection was secured.
*/
protected boolean negotiateTLS() {
if (socketReader.connection.getTlsPolicy() == Connection.TLSPolicy.disabled) {
// Set the not_authorized error
StreamError error = new StreamError(StreamError.Condition.not_authorized);
// Deliver stanza
socketReader.connection.deliverRawText(error.toXML());
// Close the underlying connection
socketReader.connection.close();
// Log a warning so that admins can track this case from the server side
Log.warn("TLS requested by initiator when TLS was never offered by server. " + "Closing connection : " + socketReader.connection);
return false;
}
// Client requested to secure the connection using TLS. Negotiate TLS.
try {
// This code is only used for s2s
socketReader.connection.startTLS(false);
} catch (SSLHandshakeException e) {
// RFC3620, section 5.4.3.2 "STARTTLS Failure" - close the socket *without* sending any more data (<failure/> nor </stream>).
Log.info("STARTTLS negotiation (with: {}) failed.", socketReader.connection, e);
socketReader.connection.forceClose();
return false;
} catch (IOException | RuntimeException e) {
// RFC3620, section 5.4.2.2 "Failure case" - Send a <failure/> element, then close the socket.
Log.warn("An exception occurred while performing STARTTLS negotiation (with: {})", socketReader.connection, e);
socketReader.connection.deliverRawText("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
socketReader.connection.close();
return false;
}
return true;
}
use of javax.net.ssl.SSLHandshakeException in project Openfire by igniterealtime.
the class TLSStreamHandler method doHandshake.
private boolean doHandshake(SelectionKey sk) throws IOException {
SSLEngineResult result;
if (initialHSComplete) {
return initialHSComplete;
}
/*
* Flush out the outgoing buffer, if there's anything left in it.
*/
if (outgoingNetBB.hasRemaining()) {
if (!flush(outgoingNetBB)) {
return false;
}
switch(initialHSStatus) {
/*
* Is this the last buffer?
*/
case FINISHED:
initialHSComplete = true;
case NEED_UNWRAP:
if (sk != null) {
sk.interestOps(SelectionKey.OP_READ);
}
break;
}
return initialHSComplete;
}
switch(initialHSStatus) {
case NEED_UNWRAP:
if (rbc.read(incomingNetBB) == -1) {
try {
tlsEngine.closeInbound();
} catch (javax.net.ssl.SSLException ex) {
// OF-1009 Process these as a 'normal' handshake rejection - it's the peer closing the connection abruptly.
if ("Inbound closed before receiving peer's close_notify: possible truncation attack?".equals(ex.getMessage())) {
throw new SSLHandshakeException("The peer closed the connection while performing a TLS handshake.");
}
throw ex;
}
return initialHSComplete;
}
needIO: while (initialHSStatus == HandshakeStatus.NEED_UNWRAP) {
/*
* Don't need to resize requestBB, since no app data should be generated here.
*/
incomingNetBB.flip();
result = tlsEngine.unwrap(incomingNetBB, appBB);
incomingNetBB.compact();
initialHSStatus = result.getHandshakeStatus();
switch(result.getStatus()) {
case OK:
switch(initialHSStatus) {
case NOT_HANDSHAKING:
throw new IOException("Not handshaking during initial handshake");
case NEED_TASK:
initialHSStatus = doTasks();
break;
case FINISHED:
initialHSComplete = true;
break needIO;
}
break;
case BUFFER_UNDERFLOW:
/*
* Need to go reread the Channel for more data.
*/
if (sk != null) {
sk.interestOps(SelectionKey.OP_READ);
}
break needIO;
default:
// BUFFER_OVERFLOW/CLOSED:
throw new IOException("Received" + result.getStatus() + "during initial handshaking");
}
}
/*
* Just transitioned from read to write.
*/
if (initialHSStatus != HandshakeStatus.NEED_WRAP) {
break;
}
case NEED_WRAP:
/*
* The flush above guarantees the out buffer to be empty
*/
outgoingNetBB.clear();
result = tlsEngine.wrap(hsBB, outgoingNetBB);
outgoingNetBB.flip();
initialHSStatus = result.getHandshakeStatus();
switch(result.getStatus()) {
case OK:
if (initialHSStatus == HandshakeStatus.NEED_TASK) {
initialHSStatus = doTasks();
}
if (sk != null) {
sk.interestOps(SelectionKey.OP_WRITE);
}
break;
default:
// BUFFER_OVERFLOW/BUFFER_UNDERFLOW/CLOSED:
throw new IOException("Received" + result.getStatus() + "during initial handshaking");
}
break;
default:
// NOT_HANDSHAKING/NEED_TASK/FINISHED
throw new RuntimeException("Invalid Handshaking State" + initialHSStatus);
}
return initialHSComplete;
}
use of javax.net.ssl.SSLHandshakeException in project Openfire by igniterealtime.
the class ServerDialback method validateRemoteDomain.
/**
* Returns true if the domain requested by the remote server was validated by the Authoritative
* Server. To validate the domain a new TCP connection will be established to the
* Authoritative Server. The Authoritative Server may be the same Originating Server or
* some other machine in the Originating Server's network.<p>
*
* If the domain was not valid or some error occurred while validating the domain then the
* underlying TCP connection may be closed.
*
* @param doc the request for validating the new domain.
* @param streamID the stream id generated by this server for the Originating Server.
* @return true if the requested domain is valid.
*/
public boolean validateRemoteDomain(Element doc, StreamID streamID) {
StringBuilder sb;
String recipient = doc.attributeValue("to");
String remoteDomain = doc.attributeValue("from");
final Logger log = LoggerFactory.getLogger(Log.getName() + "[Acting as Receiving Server: Validate domain:" + recipient + "(id " + streamID + ") for OS: " + remoteDomain + "]");
log.debug("Validating domain...");
if (connection.getTlsPolicy() == Connection.TLSPolicy.required && !connection.isSecure()) {
connection.deliverRawText(new StreamError(StreamError.Condition.policy_violation).toXML());
// Close the underlying connection
connection.close();
return false;
}
if (!RemoteServerManager.canAccess(remoteDomain)) {
connection.deliverRawText(new StreamError(StreamError.Condition.policy_violation).toXML());
// Close the underlying connection
connection.close();
log.debug("Unable to validate domain: Remote domain is not allowed to establish a connection to this server.");
return false;
} else if (isHostUnknown(recipient)) {
dialbackError(recipient, remoteDomain, new PacketError(PacketError.Condition.item_not_found, PacketError.Type.cancel, "Service not hosted here"));
log.debug("Unable to validate domain: recipient not recognized as a local domain.");
return false;
} else {
log.debug("Check if the remote domain already has a connection to the target domain/subdomain");
boolean alreadyExists = false;
for (IncomingServerSession session : sessionManager.getIncomingServerSessions(remoteDomain)) {
if (recipient.equals(session.getLocalDomain())) {
alreadyExists = true;
}
}
if (alreadyExists && !sessionManager.isMultipleServerConnectionsAllowed()) {
dialbackError(recipient, remoteDomain, new PacketError(PacketError.Condition.resource_constraint, PacketError.Type.cancel, "Incoming session already exists"));
log.debug("Unable to validate domain: An incoming connection already exists from this remote domain, and multiple connections are not allowed.");
return false;
} else {
log.debug("Checking to see if the remote server provides stronger authentication based on SASL. If that's the case, dialback-based authentication can be skipped.");
if (SASLAuthentication.verifyCertificates(connection.getPeerCertificates(), remoteDomain, true)) {
log.debug("Host authenticated based on SASL. Weaker dialback-based authentication is skipped.");
sb = new StringBuilder();
sb.append("<db:result");
sb.append(" from=\"").append(recipient).append("\"");
sb.append(" to=\"").append(remoteDomain).append("\"");
sb.append(" type=\"valid\"");
sb.append("/>");
connection.deliverRawText(sb.toString());
log.debug("Domain validated successfully!");
return true;
}
log.debug("Unable to authenticate host based on stronger SASL. Proceeding with dialback...");
String key = doc.getTextTrim();
Socket socket = SocketUtil.createSocketToXmppDomain(remoteDomain, RemoteServerManager.getPortForServer(remoteDomain));
if (socket == null) {
log.debug("Unable to validate domain: No server available for verifying key of remote server.");
dialbackError(recipient, remoteDomain, new PacketError(PacketError.Condition.remote_server_not_found, PacketError.Type.cancel, "Unable to connect to authoritative server"));
return false;
}
VerifyResult result;
try {
log.debug("Verifying dialback key...");
try {
result = verifyKey(key, streamID, recipient, remoteDomain, socket, false);
} catch (SSLHandshakeException e) {
log.debug("Verification of dialback key failed due to TLS failure. Retry without TLS...", e);
// The receiving entity is expected to close the socket *without* sending any more data (<failure/> nor </stream>).
// It is probably (see OF-794) best if we, as the initiating entity, therefor don't send any data either.
final SocketAddress oldAddress = socket.getRemoteSocketAddress();
socket.close();
log.debug("Re-opening socket (with the same remote peer)...");
// Retry, without TLS.
socket = new Socket();
socket.connect(oldAddress, RemoteServerManager.getSocketTimeout());
log.debug("Successfully re-opened socket! Try to validate dialback key again (without TLS this time)...");
result = verifyKey(key, streamID, recipient, remoteDomain, socket, true);
}
switch(result) {
case valid:
case invalid:
boolean valid = (result == VerifyResult.valid);
log.debug("Dialback key is" + (valid ? "valid" : "invalid") + ". Sending verification result to remote domain.");
sb = new StringBuilder();
sb.append("<db:result");
sb.append(" from=\"").append(recipient).append("\"");
sb.append(" to=\"").append(remoteDomain).append("\"");
sb.append(" type=\"");
sb.append(valid ? "valid" : "invalid");
sb.append("\"/>");
connection.deliverRawText(sb.toString());
if (!valid) {
log.debug("Close the underlying connection as key verification failed.");
connection.close();
log.debug("Unable to validate domain: dialback key is invalid.");
return false;
} else {
log.debug("Successfully validated domain!");
return true;
}
default:
break;
}
log.debug("Unable to validate domain: key verification did not complete (the AS likely returned an error or a time out occurred).");
dialbackError(recipient, remoteDomain, new PacketError(PacketError.Condition.remote_server_timeout, PacketError.Type.cancel, "Authoritative server returned error"));
return false;
} catch (Exception e) {
dialbackError(recipient, remoteDomain, new PacketError(PacketError.Condition.remote_server_timeout, PacketError.Type.cancel, "Authoritative server failed"));
log.warn("Unable to validate domain: An exception occurred while verifying the dialback key.", e);
return false;
}
}
}
}
use of javax.net.ssl.SSLHandshakeException in project jetty.project by eclipse.
the class SslConnectionTest method testSslConnectionClosedBeforeFill.
@Test
public void testSslConnectionClosedBeforeFill() throws Exception {
File keyStore = MavenTestingUtils.getTestResourceFile("keystore.jks");
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath(keyStore.getAbsolutePath());
sslContextFactory.setKeyStorePassword("storepwd");
sslContextFactory.start();
ByteBufferPool byteBufferPool = new MappedByteBufferPool();
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.start();
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
SSLEngine sslEngine = sslContextFactory.newSSLEngine();
sslEngine.setUseClientMode(false);
SslConnection sslConnection = new SslConnection(byteBufferPool, threadPool, endPoint, sslEngine);
EndPoint sslEndPoint = sslConnection.getDecryptedEndPoint();
sslEndPoint.setConnection(new AbstractConnection(sslEndPoint, threadPool) {
@Override
public void onFillable() {
}
});
// There are no bytes in the endPoint, so we fill zero.
// However, this will trigger state changes in SSLEngine
// that will later cause it to throw ISE("Internal error").
sslEndPoint.fill(BufferUtil.EMPTY_BUFFER);
// Close the connection before filling.
sslEndPoint.shutdownOutput();
// Put some bytes in the endPoint to trigger
// the required state changes in SSLEngine.
byte[] bytes = new byte[] { 0x16, 0x03, 0x03, 0x00, 0x00 };
endPoint.addInput(ByteBuffer.wrap(bytes));
// reads from the EndPoint.
try {
sslEndPoint.fill(BufferUtil.EMPTY_BUFFER);
Assert.fail();
} catch (SSLHandshakeException x) {
// Expected.
}
}
use of javax.net.ssl.SSLHandshakeException in project cassandra by apache.
the class OutboundTcpConnection method connect.
@SuppressWarnings("resource")
private boolean connect() {
logger.debug("Attempting to connect to {}", poolReference.endPoint());
long start = System.nanoTime();
long timeout = TimeUnit.MILLISECONDS.toNanos(DatabaseDescriptor.getRpcTimeout());
while (System.nanoTime() - start < timeout) {
targetVersion = MessagingService.instance().getVersion(poolReference.endPoint());
try {
socket = poolReference.newSocket();
socket.setKeepAlive(true);
if (isLocalDC(poolReference.endPoint())) {
socket.setTcpNoDelay(INTRADC_TCP_NODELAY);
} else {
socket.setTcpNoDelay(DatabaseDescriptor.getInterDCTcpNoDelay());
}
if (DatabaseDescriptor.getInternodeSendBufferSize() > 0) {
try {
socket.setSendBufferSize(DatabaseDescriptor.getInternodeSendBufferSize());
} catch (SocketException se) {
logger.warn("Failed to set send buffer size on internode socket.", se);
}
}
// SocketChannel may be null when using SSL
WritableByteChannel ch = socket.getChannel();
out = new BufferedDataOutputStreamPlus(ch != null ? ch : Channels.newChannel(socket.getOutputStream()), BUFFER_SIZE);
out.writeInt(MessagingService.PROTOCOL_MAGIC);
writeHeader(out, targetVersion, shouldCompressConnection());
out.flush();
DataInputStream in = new DataInputStream(socket.getInputStream());
int maxTargetVersion = handshakeVersion(in);
if (maxTargetVersion == NO_VERSION) {
// no version is returned, so disconnect an try again
logger.trace("Target max version is {}; no version information yet, will retry", maxTargetVersion);
disconnect();
continue;
} else {
MessagingService.instance().setVersion(poolReference.endPoint(), maxTargetVersion);
}
if (targetVersion > maxTargetVersion) {
logger.trace("Target max version is {}; will reconnect with that version", maxTargetVersion);
try {
if (DatabaseDescriptor.getSeeds().contains(poolReference.endPoint()))
logger.warn("Seed gossip version is {}; will not connect with that version", maxTargetVersion);
} catch (Throwable e) {
// If invalid yaml has been added to the config since startup, getSeeds() will throw an AssertionError
// Additionally, third party seed providers may throw exceptions if network is flakey
// Regardless of what's thrown, we must catch it, disconnect, and try again
JVMStabilityInspector.inspectThrowable(e);
logger.warn("Configuration error prevented outbound connection: {}", e.getLocalizedMessage());
} finally {
disconnect();
return false;
}
}
if (targetVersion < maxTargetVersion && targetVersion < MessagingService.current_version) {
logger.trace("Detected higher max version {} (using {}); will reconnect when queued messages are done", maxTargetVersion, targetVersion);
softCloseSocket();
}
out.writeInt(MessagingService.current_version);
CompactEndpointSerializationHelper.serialize(FBUtilities.getBroadcastAddress(), out);
if (shouldCompressConnection()) {
out.flush();
logger.trace("Upgrading OutputStream to {} to be compressed", poolReference.endPoint());
// TODO: custom LZ4 OS that supports BB write methods
LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
Checksum checksum = XXHashFactory.fastestInstance().newStreamingHash32(LZ4_HASH_SEED).asChecksum();
out = new WrappedDataOutputStreamPlus(new LZ4BlockOutputStream(socket.getOutputStream(), // 16k block size
1 << 14, compressor, checksum, // no async flushing
true));
}
logger.debug("Done connecting to {}", poolReference.endPoint());
return true;
} catch (SSLHandshakeException e) {
logger.error("SSL handshake error for outbound connection to " + socket, e);
socket = null;
// SSL errors won't be recoverable within timeout period so we'll just abort
return false;
} catch (IOException e) {
socket = null;
logger.debug("Unable to connect to {}", poolReference.endPoint(), e);
Uninterruptibles.sleepUninterruptibly(OPEN_RETRY_DELAY, TimeUnit.MILLISECONDS);
}
}
return false;
}
Aggregations