From 26dd9e15bb9e913af38473a74e2a1049c21df29b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 11 Jan 2015 01:53:20 +0100 Subject: [PATCH] build,src: remove sslv2 support SSLv2 has been deprecated and known broken for nearly twenty years now. I made SSLv2 support opt-in well over a year ago in commit 39aa894 and now this commit removes it entirely. PR-URL: https://github.com/iojs/io.js/pull/290 Reviewed-By: Fedor Indutny Reviewed-By: Rod Vagg --- configure | 10 ------- deps/openssl/openssl.gyp | 4 +++ doc/api/tls.markdown | 4 --- src/node_crypto.cc | 17 ++++------- src/node_crypto_clienthello.cc | 66 +++++------------------------------------- src/node_crypto_clienthello.h | 6 ---- 6 files changed, 17 insertions(+), 90 deletions(-) diff --git a/configure b/configure index 1d91f21..c0517c3 100755 --- a/configure +++ b/configure @@ -252,11 +252,6 @@ parser.add_option('--with-perfctr', dest='with_perfctr', help='build with performance counters (default is true on Windows)') -parser.add_option('--with-sslv2', - action='store_true', - dest='with_sslv2', - help='enable SSL v2') - parser.add_option('--without-dtrace', action='store_true', dest='without_dtrace', @@ -588,11 +583,6 @@ def configure_openssl(o): if options.without_ssl: return - # OpenSSL uses `#ifndef OPENSSL_NO_SSL2` checks so only define the - # macro when we want to _disable_ SSL2. - if not options.with_sslv2: - o['defines'] += ['OPENSSL_NO_SSL2=1'] - if options.shared_openssl: (libs, cflags) = pkg_config('openssl') or ('-lssl -lcrypto', '') diff --git a/deps/openssl/openssl.gyp b/deps/openssl/openssl.gyp index ea85838..edb0a5b 100644 --- a/deps/openssl/openssl.gyp +++ b/deps/openssl/openssl.gyp @@ -1095,6 +1095,10 @@ 'PURIFY', '_REENTRANT', + # SSLv2 is known broken and has been superseded by SSLv3 for almost + # twenty years now. + 'OPENSSL_NO_SSL2', + # Heartbeat is a TLS extension, that couldn't be turned off or # asked to be not advertised. Unfortunately this is unacceptable for # Microsoft's IIS, which seems to be ignoring whole ClientHello after diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown index 7fcafb9..11cea44 100644 --- a/doc/api/tls.markdown +++ b/doc/api/tls.markdown @@ -184,10 +184,6 @@ automatically set as a listener for the [secureConnection][] event. The use this option in conjunction with the `ciphers` option to mitigate BEAST attacks. - Note: If SSLv2 is used, the server will send its list of preferences to the - client, and the client chooses the cipher. Support for SSLv2 is disabled - unless node.js was configured with `./configure --with-sslv2`. - - `requestCert`: If `true` the server will request a certificate from clients that connect and attempt to verify that certificate. Default: `false`. diff --git a/src/node_crypto.cc b/src/node_crypto.cc index fc75499..efed0a6 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -310,23 +310,11 @@ void SecureContext::Init(const FunctionCallbackInfo& args) { const node::Utf8Value sslmethod(env->isolate(), args[0]); if (strcmp(*sslmethod, "SSLv2_method") == 0) { -#ifndef OPENSSL_NO_SSL2 - method = SSLv2_method(); -#else return env->ThrowError("SSLv2 methods disabled"); -#endif } else if (strcmp(*sslmethod, "SSLv2_server_method") == 0) { -#ifndef OPENSSL_NO_SSL2 - method = SSLv2_server_method(); -#else return env->ThrowError("SSLv2 methods disabled"); -#endif } else if (strcmp(*sslmethod, "SSLv2_client_method") == 0) { -#ifndef OPENSSL_NO_SSL2 - method = SSLv2_client_method(); -#else return env->ThrowError("SSLv2 methods disabled"); -#endif } else if (strcmp(*sslmethod, "SSLv3_method") == 0) { #ifndef OPENSSL_NO_SSL3 method = SSLv3_method(); @@ -376,6 +364,11 @@ void SecureContext::Init(const FunctionCallbackInfo& args) { sc->ctx_ = SSL_CTX_new(method); + // Disable SSLv2 in the case when method == SSLv23_method() and the + // cipher list contains SSLv2 ciphers (not the default, should be rare.) + // The bundled OpenSSL doesn't have SSLv2 support but the system OpenSSL may. + SSL_CTX_set_options(sc->ctx_, SSL_OP_NO_SSLv2); + // SSL session cache configuration SSL_CTX_set_session_cache_mode(sc->ctx_, SSL_SESS_CACHE_SERVER | diff --git a/src/node_crypto_clienthello.cc b/src/node_crypto_clienthello.cc index fd7ed79..0423049 100644 --- a/src/node_crypto_clienthello.cc +++ b/src/node_crypto_clienthello.cc @@ -32,7 +32,6 @@ void ClientHelloParser::Parse(const uint8_t* data, size_t avail) { break; // Fall through case kTLSHeader: - case kSSL2Header: ParseHeader(data, avail); break; case kPaused: @@ -59,20 +58,8 @@ bool ClientHelloParser::ParseRecordHeader(const uint8_t* data, size_t avail) { state_ = kTLSHeader; body_offset_ = 5; } else { -#ifdef OPENSSL_NO_SSL2 - frame_len_ = ((data[0] << 8) & kSSL2HeaderMask) + data[1]; - state_ = kSSL2Header; - if (data[0] & kSSL2TwoByteHeaderBit) { - // header without padding - body_offset_ = 2; - } else { - // header with padding - body_offset_ = 3; - } -#else End(); return false; -#endif // OPENSSL_NO_SSL2 } // Sanity check (too big frame, or too small) @@ -85,12 +72,6 @@ bool ClientHelloParser::ParseRecordHeader(const uint8_t* data, size_t avail) { return true; } -#ifdef OPENSSL_NO_SSL2 -# define NODE_SSL2_VER_CHECK(buf) false -#else -# define NODE_SSL2_VER_CHECK(buf) ((buf)[0] == 0x00 && (buf)[1] == 0x02) -#endif // OPENSSL_NO_SSL2 - void ClientHelloParser::ParseHeader(const uint8_t* data, size_t avail) { ClientHello hello; @@ -99,24 +80,20 @@ void ClientHelloParser::ParseHeader(const uint8_t* data, size_t avail) { if (body_offset_ + frame_len_ > avail) return; - // Skip unsupported frames and gather some data from frame - // Check hello protocol version - if (!(data[body_offset_ + 4] == 0x03 && data[body_offset_ + 5] <= 0x03) && - !NODE_SSL2_VER_CHECK(data + body_offset_ + 4)) { + // Check hello protocol version. Protocol tuples that we know about: + // + // (3,0) SSL v3.0 + // (3,1) TLS v1.0 + // (3,2) TLS v1.1 + // (3,3) TLS v1.2 + // + if (data[body_offset_ + 4] != 0x03 || data[body_offset_ + 5] > 0x03) goto fail; - } if (data[body_offset_] == kClientHello) { if (state_ == kTLSHeader) { if (!ParseTLSClientHello(data, avail)) goto fail; - } else if (state_ == kSSL2Header) { -#ifdef OPENSSL_NO_SSL2 - if (!ParseSSL2ClientHello(data, avail)) - goto fail; -#else - abort(); // Unreachable -#endif // OPENSSL_NO_SSL2 } else { // We couldn't get here, but whatever goto fail; @@ -145,9 +122,6 @@ void ClientHelloParser::ParseHeader(const uint8_t* data, size_t avail) { } -#undef NODE_SSL2_VER_CHECK - - void ClientHelloParser::ParseExtension(ClientHelloParser::ExtensionType type, const uint8_t* data, size_t len) { @@ -269,28 +243,4 @@ bool ClientHelloParser::ParseTLSClientHello(const uint8_t* data, size_t avail) { return true; } - -#ifdef OPENSSL_NO_SSL2 -bool ClientHelloParser::ParseSSL2ClientHello(const uint8_t* data, - size_t avail) { - const uint8_t* body; - - // Skip header, version - size_t session_offset = body_offset_ + 3; - - if (session_offset + 4 < avail) { - body = data + session_offset; - - uint16_t ciphers_size = (body[0] << 8) + body[1]; - - if (body + 4 + ciphers_size < data + avail) { - session_size_ = (body[2] << 8) + body[3]; - session_id_ = body + 4 + ciphers_size; - } - } - - return true; -} -#endif // OPENSSL_NO_SSL2 - } // namespace node diff --git a/src/node_crypto_clienthello.h b/src/node_crypto_clienthello.h index bbd46e5..e1a5b9b 100644 --- a/src/node_crypto_clienthello.h +++ b/src/node_crypto_clienthello.h @@ -77,8 +77,6 @@ class ClientHelloParser { inline bool IsEnded() const; private: - static const uint8_t kSSL2TwoByteHeaderBit = 0x80; - static const uint8_t kSSL2HeaderMask = 0x3f; static const size_t kMaxTLSFrameLen = 16 * 1024 + 5; static const size_t kMaxSSLExFrameLen = 32 * 1024; static const uint8_t kServernameHostname = 0; @@ -88,7 +86,6 @@ class ClientHelloParser { enum ParseState { kWaiting, kTLSHeader, - kSSL2Header, kPaused, kEnded }; @@ -117,9 +114,6 @@ class ClientHelloParser { const uint8_t* data, size_t len); bool ParseTLSClientHello(const uint8_t* data, size_t avail); -#ifdef OPENSSL_NO_SSL2 - bool ParseSSL2ClientHello(const uint8_t* data, size_t avail); -#endif // OPENSSL_NO_SSL2 ParseState state_; OnHelloCb onhello_cb_; -- 2.7.4