Skip to content

Commit 52be043

Browse files
Jeff McCunejoshcooper
authored andcommitted
(#19151) Reject SSLv2 SSL handshakes and ciphers
Without this patch, SSL connections on older versions of Ruby will negotiate down to insecure modes of operation, specifically SSLv2. This is a problem because SSLv2 needs to be rejected outright to meet security policies. This patch addresses the problem by changing the behavior of the OpenSSL::SSL::SSLContext class. With this patch applied, all SSLContext objects will be initialized with a default cipher rule set that always contains the '!SSLv2' substring. This has the effect of removing SSLv2 ciphers from the cipher list and prohibiting them from being re-added by later elements in the cipher spec. Details regarding how OpenSSL behaves with this cipher string are available at: http://www.openssl.org/docs/apps/ciphers.html In order to see which ciphers are enabled for a specific version of the OpenSSL library, please see the output of the command: $ openssl ciphers $CIPHERS This command will display an ordered list of the ciphers enabled for use during the SSL handshake. This change is a monkey patch to MRI Core and will affect all SSL socket clients and servers. The options and cipher list may still be explicitly set by passing an options hash with the :options and :ciphers keys to the SSLContext#set_params method.
1 parent 480379d commit 52be043

5 files changed

Lines changed: 48 additions & 1 deletion

File tree

lib/puppet/network/http/webrick.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ def setup_ssl
9494
results[:SSLCertificate] = host.certificate.content
9595
results[:SSLStartImmediately] = true
9696
results[:SSLEnable] = true
97+
results[:SSLOptions] = OpenSSL::SSL::OP_NO_SSLv2
9798

9899
raise Puppet::Error, "Could not find CA certificate" unless Puppet::SSL::Certificate.indirection.find(Puppet::SSL::CA_NAME)
99100

lib/puppet/util/monkey_patches.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,3 +356,26 @@ def Dir.mktmpdir(prefix_suffix=nil, tmpdir=nil)
356356
end
357357
end
358358
end
359+
360+
# (#19151) Reject all SSLv2 ciphers and handshakes
361+
require 'openssl'
362+
class OpenSSL::SSL::SSLContext
363+
if DEFAULT_PARAMS[:options]
364+
DEFAULT_PARAMS[:options] |= OpenSSL::SSL::OP_NO_SSLv2
365+
else
366+
DEFAULT_PARAMS[:options] = OpenSSL::SSL::OP_NO_SSLv2
367+
end
368+
DEFAULT_PARAMS[:ciphers] << ':!SSLv2'
369+
370+
alias __original_initialize initialize
371+
private :__original_initialize
372+
373+
def initialize(*args)
374+
__original_initialize(*args)
375+
params = {
376+
:options => DEFAULT_PARAMS[:options],
377+
:ciphers => DEFAULT_PARAMS[:ciphers],
378+
}
379+
set_params(params)
380+
end
381+
end

spec/unit/network/http/connection_spec.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@
9090

9191
it { should be_use_ssl }
9292
its(:cert) { should be_nil }
93-
its(:cert_store) { should be_nil }
9493
its(:ca_file) { should be_nil }
9594
its(:key) { should be_nil }
9695
its(:verify_mode) { should == OpenSSL::SSL::VERIFY_NONE }

spec/unit/network/http/webrick_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,10 @@
241241
server.setup_ssl[:SSLEnable].should be_true
242242
end
243243

244+
it "should reject SSLv2" do
245+
server.setup_ssl[:SSLOptions].should == OpenSSL::SSL::OP_NO_SSLv2
246+
end
247+
244248
it "should configure the verification method as 'OpenSSL::SSL::VERIFY_PEER'" do
245249
server.setup_ssl[:SSLVerifyClient].should == OpenSSL::SSL::VERIFY_PEER
246250
end

spec/unit/util/monkey_patches_spec.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,23 @@ def do_test( range, other, expected )
254254
o.instance_variables.should =~ [:@foo, :@bar, :@baz]
255255
end
256256
end
257+
258+
describe OpenSSL::SSL::SSLContext do
259+
it 'disables SSLv2 via the SSLContext#options bitmask' do
260+
(subject.options & OpenSSL::SSL::OP_NO_SSLv2).should == OpenSSL::SSL::OP_NO_SSLv2
261+
end
262+
it 'explicitly disable SSLv2 ciphers using the ! prefix so they cannot be re-added' do
263+
cipher_str = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:ciphers]
264+
cipher_str.split(':').should include('!SSLv2')
265+
end
266+
it 'sets parameters on initialization' do
267+
described_class.any_instance.expects(:set_params)
268+
subject
269+
end
270+
it 'has no ciphers with version SSLv2 enabled' do
271+
ciphers = subject.ciphers.select do |name, version, bits, alg_bits|
272+
/SSLv2/.match(version)
273+
end
274+
ciphers.should be_empty
275+
end
276+
end

0 commit comments

Comments
 (0)