Search in sources :

Example 51 with SSLHandshakeException

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;
}
Also used : StreamError(org.xmpp.packet.StreamError) IOException(java.io.IOException) SSLHandshakeException(javax.net.ssl.SSLHandshakeException)

Example 52 with SSLHandshakeException

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;
}
Also used : SSLEngineResult(javax.net.ssl.SSLEngineResult) IOException(java.io.IOException) SSLHandshakeException(javax.net.ssl.SSLHandshakeException)

Example 53 with SSLHandshakeException

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;
            }
        }
    }
}
Also used : StreamError(org.xmpp.packet.StreamError) IncomingServerSession(org.jivesoftware.openfire.session.IncomingServerSession) LocalIncomingServerSession(org.jivesoftware.openfire.session.LocalIncomingServerSession) PacketError(org.xmpp.packet.PacketError) Logger(org.slf4j.Logger) SocketAddress(java.net.SocketAddress) InetSocketAddress(java.net.InetSocketAddress) Socket(java.net.Socket) SSLHandshakeException(javax.net.ssl.SSLHandshakeException) DocumentException(org.dom4j.DocumentException) SSLHandshakeException(javax.net.ssl.SSLHandshakeException) IOException(java.io.IOException) XmlPullParserException(org.xmlpull.v1.XmlPullParserException)

Example 54 with SSLHandshakeException

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.
    }
}
Also used : ByteBufferPool(org.eclipse.jetty.io.ByteBufferPool) MappedByteBufferPool(org.eclipse.jetty.io.MappedByteBufferPool) SSLEngine(javax.net.ssl.SSLEngine) ByteArrayEndPoint(org.eclipse.jetty.io.ByteArrayEndPoint) EndPoint(org.eclipse.jetty.io.EndPoint) ByteArrayEndPoint(org.eclipse.jetty.io.ByteArrayEndPoint) SSLHandshakeException(javax.net.ssl.SSLHandshakeException) MappedByteBufferPool(org.eclipse.jetty.io.MappedByteBufferPool) SslConnection(org.eclipse.jetty.io.ssl.SslConnection) SslContextFactory(org.eclipse.jetty.util.ssl.SslContextFactory) QueuedThreadPool(org.eclipse.jetty.util.thread.QueuedThreadPool) AbstractConnection(org.eclipse.jetty.io.AbstractConnection) File(java.io.File) Test(org.junit.Test)

Example 55 with SSLHandshakeException

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;
}
Also used : SocketException(java.net.SocketException) WritableByteChannel(java.nio.channels.WritableByteChannel) IOException(java.io.IOException) BufferedDataOutputStreamPlus(org.apache.cassandra.io.util.BufferedDataOutputStreamPlus) DataInputStream(java.io.DataInputStream) SSLHandshakeException(javax.net.ssl.SSLHandshakeException) LZ4Compressor(net.jpountz.lz4.LZ4Compressor) LZ4BlockOutputStream(net.jpountz.lz4.LZ4BlockOutputStream) Checksum(java.util.zip.Checksum) WrappedDataOutputStreamPlus(org.apache.cassandra.io.util.WrappedDataOutputStreamPlus)

Aggregations

SSLHandshakeException (javax.net.ssl.SSLHandshakeException)90 IOException (java.io.IOException)29 Test (org.junit.Test)22 CertificateException (java.security.cert.CertificateException)18 URL (java.net.URL)15 SSLException (javax.net.ssl.SSLException)15 SocketException (java.net.SocketException)13 HttpsURLConnection (javax.net.ssl.HttpsURLConnection)12 SSLProtocolException (javax.net.ssl.SSLProtocolException)10 Socket (java.net.Socket)9 SSLSocket (javax.net.ssl.SSLSocket)9 SSLPeerUnverifiedException (javax.net.ssl.SSLPeerUnverifiedException)8 SocketTimeoutException (java.net.SocketTimeoutException)7 SSLSession (javax.net.ssl.SSLSession)7 InputStream (java.io.InputStream)6 SSLSocketFactory (javax.net.ssl.SSLSocketFactory)6 Channel (io.netty.channel.Channel)5 InetSocketAddress (java.net.InetSocketAddress)5 MalformedURLException (java.net.MalformedURLException)5 ClosedChannelException (java.nio.channels.ClosedChannelException)5