This is an automated email from the ASF dual-hosted git repository. grag pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 4bb7ef93a9555b4c40efa4a1000b560e58ac9858 Author: Joseph Wu <[email protected]> AuthorDate: Wed Feb 26 17:14:59 2020 +0100 SSL Socket: Added downgrade support. This adds downgrade support, in the same fashion that the Libevent SSL socket does (and copies a good chunk of the code from there too). To account for Windows not having `io::poll`, a slight hack is taken to check for readable bytes. Review: https://reviews.apache.org/r/72017/ --- 3rdparty/libprocess/src/ssl/openssl_socket.cpp | 66 ++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/3rdparty/libprocess/src/ssl/openssl_socket.cpp b/3rdparty/libprocess/src/ssl/openssl_socket.cpp index 43909f0..a2ec0a3 100644 --- a/3rdparty/libprocess/src/ssl/openssl_socket.cpp +++ b/3rdparty/libprocess/src/ssl/openssl_socket.cpp @@ -573,6 +573,72 @@ Future<std::shared_ptr<SocketImpl>> OpenSSLSocketImpl::accept() return Break(); } + // If we support downgrading the connection, first wait for this + // socket to become readable. We will then MSG_PEEK it to test + // whether we want to dispatch as SSL or non-SSL. + if (openssl::flags().support_downgrade) { +#ifdef __WINDOWS__ + // Since there is no `io::poll` on Windows, we instead make + // a 0-byte read, which will only return once there is something + // to read. + return io::read(socket->get(), nullptr, 0) +#else + return io::poll(socket->get(), process::io::READ) +#endif // __WINDOWS__ + .then([weak_self, socket]() -> Future<ControlFlow<Nothing>> { + std::shared_ptr<OpenSSLSocketImpl> self(weak_self.lock()); + + if (self == nullptr) { + return Break(); + } + + char data[6]; + + // Try to peek the first 6 bytes of the message. + ssize_t size = ::recv(socket->get(), data, 6, MSG_PEEK); + + // Based on the function 'ssl23_get_client_hello' in openssl, we + // test whether to dispatch to the SSL or non-SSL based accept + // based on the following rules: + // 1. If there are fewer than 3 bytes: non-SSL. + // 2. If the 1st bit of the 1st byte is set AND the 3rd byte + // is equal to SSL2_MT_CLIENT_HELLO: SSL. + // 3. If the 1st byte is equal to SSL3_RT_HANDSHAKE AND the + // 2nd byte is equal to SSL3_VERSION_MAJOR and the 6th byte + // is equal to SSL3_MT_CLIENT_HELLO: SSL. + // 4. Otherwise: non-SSL. + + // For an ascii based protocol to falsely get dispatched to SSL + // it needs to: + // 1. Start with an invalid ascii character (0x80). + // 2. OR have the first 2 characters be a SYN followed by ETX, + // and then the 6th character be SOH. + // These conditions clearly do not constitute valid HTTP + // requests, and are unlikely to collide with other existing + // protocols. + + bool ssl = false; // Default to rule 4. + + if (size < 2) { // Rule 1. + ssl = false; + } else if ((data[0] & 0x80) && + data[2] == SSL2_MT_CLIENT_HELLO) { // Rule 2. + ssl = true; + } else if (data[0] == SSL3_RT_HANDSHAKE && + data[1] == SSL3_VERSION_MAJOR && + data[5] == SSL3_MT_CLIENT_HELLO) { // Rule 3. + ssl = true; + } + + if (ssl) { + return self->handle_accept_callback(socket); + } else { + self->accept_queue.put(socket); + return Continue(); + } + }); + } + return self->handle_accept_callback(socket); });
