diff --git a/lib/launcher.rb b/lib/launcher.rb index 0967485bb..a245c4ca2 100644 --- a/lib/launcher.rb +++ b/lib/launcher.rb @@ -118,13 +118,46 @@ def resolve_tls_ciphers return nil if configured&.empty? return configured unless configured.nil? - if File.exist?(CRYPTO_POLICIES_CONFIG) - logger.info "Crypto-policies detected, using PROFILE=SYSTEM for TLS ciphers." - 'PROFILE=SYSTEM' - else + unless File.exist?(CRYPTO_POLICIES_CONFIG) logger.debug "No crypto-policies detected, using HIGH cipher string as default." - 'HIGH' + return 'HIGH' + end + + if cipher_string_supported?('PROFILE=SYSTEM') + logger.info "Crypto-policies detected, using PROFILE=SYSTEM for TLS ciphers." + return 'PROFILE=SYSTEM' end + + cipher_string = crypto_policies_cipher_string + if cipher_string && cipher_string_supported?(cipher_string) + logger.info "Crypto-policies detected, but this OpenSSL build does not support the " \ + "'PROFILE=SYSTEM' cipher-list alias. Using the CipherString resolved from " \ + "#{CRYPTO_POLICIES_CONFIG} directly instead." + return cipher_string + end + + logger.warn "Crypto-policies detected but could not be applied on this Ruby/OpenSSL build; " \ + "falling back to the 'HIGH' cipher string." + 'HIGH' + end + + # Extracted so resolve_tls_ciphers can probe candidate cipher strings before + # committing to them, instead of only discovering they're unusable at startup. + def cipher_string_supported?(ciphers) + OpenSSL::SSL::SSLContext.new.ciphers = ciphers + true + rescue OpenSSL::SSL::SSLError + false + end + + def crypto_policies_cipher_string + File.foreach(CRYPTO_POLICIES_CONFIG) do |line| + return Regexp.last_match(1).strip if line =~ /^CipherString\s*=\s*(.+)$/ + end + nil + rescue SystemCallError => e + logger.warn "Unable to read #{CRYPTO_POLICIES_CONFIG}: #{e.message}" + nil end def validate_tls_ciphers!(ciphers) @@ -135,12 +168,7 @@ def validate_tls_ciphers!(ciphers) "The system crypto policy minimum TLS version may be overridden by this setting." end - cipher_list = begin - OpenSSL::SSL::SSLContext.new.ciphers = ciphers - ciphers - rescue OpenSSL::SSL::SSLError - nil - end + cipher_list = cipher_string_supported?(ciphers) ? ciphers : nil if OpenSSL::SSL::SSLContext.method_defined?(:ciphersuites=) ciphersuites = begin diff --git a/test/launcher_test.rb b/test/launcher_test.rb index df8195e53..b5b0c84ac 100644 --- a/test/launcher_test.rb +++ b/test/launcher_test.rb @@ -53,6 +53,7 @@ def test_resolve_tls_ciphers_raises_on_non_string def test_resolve_tls_ciphers_autodetects_profile_system_when_crypto_policies_present launcher = launcher_with({}) File.expects(:exist?).with(CRYPTO_POLICIES_CONFIG).returns(true) + launcher.stubs(:cipher_string_supported?).with('PROFILE=SYSTEM').returns(true) launcher.logger.stubs(:info) assert_equal 'PROFILE=SYSTEM', launcher.resolve_tls_ciphers end @@ -64,6 +65,35 @@ def test_resolve_tls_ciphers_defaults_to_high_when_no_crypto_policies assert_equal 'HIGH', launcher.resolve_tls_ciphers end + def test_resolve_tls_ciphers_falls_back_to_parsed_cipher_string_when_profile_system_unsupported + launcher = launcher_with({}) + File.expects(:exist?).with(CRYPTO_POLICIES_CONFIG).returns(true) + launcher.stubs(:cipher_string_supported?).with('PROFILE=SYSTEM').returns(false) + launcher.stubs(:crypto_policies_cipher_string).returns('HIGH:!aNULL') + launcher.stubs(:cipher_string_supported?).with('HIGH:!aNULL').returns(true) + launcher.logger.stubs(:info) + assert_equal 'HIGH:!aNULL', launcher.resolve_tls_ciphers + end + + def test_resolve_tls_ciphers_falls_back_to_high_when_crypto_policies_unparseable + launcher = launcher_with({}) + File.expects(:exist?).with(CRYPTO_POLICIES_CONFIG).returns(true) + launcher.stubs(:cipher_string_supported?).with('PROFILE=SYSTEM').returns(false) + launcher.stubs(:crypto_policies_cipher_string).returns(nil) + launcher.logger.stubs(:warn) + assert_equal 'HIGH', launcher.resolve_tls_ciphers + end + + def test_resolve_tls_ciphers_falls_back_to_high_when_parsed_cipher_string_also_unsupported + launcher = launcher_with({}) + File.expects(:exist?).with(CRYPTO_POLICIES_CONFIG).returns(true) + launcher.stubs(:cipher_string_supported?).with('PROFILE=SYSTEM').returns(false) + launcher.stubs(:crypto_policies_cipher_string).returns('BOGUS') + launcher.stubs(:cipher_string_supported?).with('BOGUS').returns(false) + launcher.logger.stubs(:warn) + assert_equal 'HIGH', launcher.resolve_tls_ciphers + end + def test_validate_tls_ciphers_returns_nil_pair_for_nil assert_equal [nil, nil], @launcher.validate_tls_ciphers!(nil) end