Bug 1473816 - Hardening Satellite 6.2+ network security by disabling vulnerable ciphers and enabling new secure ones
Hardening Satellite 6.2+ network security by disabling vulnerable ciphers and...
Status: CLOSED DUPLICATE of bug 1388198
Product: Red Hat Satellite 6
Classification: Red Hat
Component: Security (Show other bugs)
6.2.10
All Unspecified
unspecified Severity medium (vote)
: Unspecified
: --
Assigned To: satellite6-bugs
Katello QA List
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2017-07-21 14:57 EDT by Pablo Hess
Modified: 2017-08-07 18:51 EDT (History)
4 users (show)

See Also:
Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2017-07-24 10:46:58 EDT
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Pablo Hess 2017-07-21 14:57:06 EDT
Description of problem:
Pentest showed weak ciphers used by Satellite. In addition to disabling such ciphers there is the need to add new ones, mainly ECDHE-based ciphers.

Version-Release number of selected component (if applicable):
6.2.x (preferable) or 6.3.0

How reproducible:
n.a.

Steps to Reproduce:
n.a.

Actual results:

 Testing all 121 locally available ciphers against the server, ordered by encryption strength

Hexcode  Cipher Suite Name (OpenSSL)       KeyExch.  Encryption Bits
------------------------------------------------------------------------
 x9f     DHE-RSA-AES256-GCM-SHA384         DH 2048    AESGCM    256
 x6b     DHE-RSA-AES256-SHA256             DH 2048    AES       256
 x39     DHE-RSA-AES256-SHA                DH 2048    AES       256
 x88     DHE-RSA-CAMELLIA256-SHA           DH 2048    Camellia  256
 x9d     AES256-GCM-SHA384                 RSA        AESGCM    256
 x3d     AES256-SHA256                     RSA        AES       256
 x35     AES256-SHA                        RSA        AES       256
 x84     CAMELLIA256-SHA                   RSA        Camellia  256
 x9e     DHE-RSA-AES128-GCM-SHA256         DH 2048    AESGCM    128
 x67     DHE-RSA-AES128-SHA256             DH 2048    AES       128
 x33     DHE-RSA-AES128-SHA                DH 2048    AES       128
 x9a     DHE-RSA-SEED-SHA                  DH 2048    SEED      128
 x45     DHE-RSA-CAMELLIA128-SHA           DH 2048    Camellia  128
 x9c     AES128-GCM-SHA256                 RSA        AESGCM    128
 x3c     AES128-SHA256                     RSA        AES       128
 x2f     AES128-SHA                        RSA        AES       128
 x96     SEED-SHA                          RSA        SEED      128
 x41     CAMELLIA128-SHA                   RSA        Camellia  128
 x16     EDH-RSA-DES-CBC3-SHA              DH 2048    3DES      168
 x0a     DES-CBC3-SHA                      RSA        3DES      168
 x07     IDEA-CBC-SHA                      RSA        IDEA      128
 x05     RC4-SHA                           RSA        RC4       128
 x04     RC4-MD5                           RSA        RC4       128
 x15     EDH-RSA-DES-CBC-SHA               DH 2048    DES       56
 x09     DES-CBC-SHA                       RSA        DES       56

So the service might be vulnerable to BEAST:

 TLS1: IDEA-CBC-SHA DES-CBC-SHA
       DES-CBC3-SHA EDH-RSA-DES-CBC-SHA
       EDH-RSA-DES-CBC3-SHA AES128-SHA 
       DHE-RSA-AES128-SHA AES256-SHA
       DHE-RSA-AES256-SHA CAMELLIA128-SHA
       DHE-RSA-CAMELLIA128-SHA CAMELLIA256-SHA
       DHE-RSA-CAMELLIA256-SHA SEED-SHA DHE-RSA-SEED-SHA




Expected results:

We need a configuration option where we can limit the ciphers / TLS versions just like in Apache (where the defaults as of Satellite 6.2.10 are really bad as well):

~~~
  SSLProtocol             -ALL +TLSv1.2
  SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ECDH+3DES:!DH+3DES:RSA+AEGCM:RSA+AES:!RSA+3DES:!aNULL:!MD5:!DSS:!SHA
  SSLHonorCipherOrder     on
~~~




Additional info:

The next few messages on this BZ detail how this customer is working to disable weak ciphers and implement ECDHE in all Red Hat Satellite 6.2.10 components.
Comment 1 Pablo Hess 2017-07-21 15:59:34 EDT
I have some configuration issues with the WEBricks serving https on the following ports:

- tcp/9090
- tcp/8008

For the WEBrick running on tcp/9090 (aka. "foreman-proxy") there is at least some kind of configuration option which allows to reduce the ciphers ("/etc/foreman-proxy/settings.yml"):

# Use this option only if you need to disable certain cipher suites.
# Note: we use the OpenSSL suite name, take a look at:
# https://www.openssl.org/docs/manmaster/apps/ciphers.html#CIPHER-SUITE-NAMES
# for more information.
:ssl_disabled_ciphers: [DHE-RSA-CAMELLIA256-SHA, DHE-DSS-CAMELLIA256-SHA,
  ECDH-RSA-AES256-SHA, ECDH-ECDSA-AES256-SHA, AES256-SHA, CAMELLIA256-SHA,
  PSK-AES256-CBC-SHA, ECDHE-RSA-AES128-SHA, ECDHE-ECDSA-AES128-SHA,
  DHE-RSA-AES128-SHA, DHE-DSS-AES128-SHA, DHE-RSA-SEED-SHA,
  DHE-DSS-SEED-SHA, DHE-RSA-CAMELLIA128-SHA, DHE-DSS-CAMELLIA128-SHA,
  ECDH-RSA-AES128-SHA, ECDH-ECDSA-AES128-SHA, AES128-SHA, SEED-SHA,
  CAMELLIA128-SHA, PSK-AES128-CBC-SHA, ECDHE-RSA-DES-CBC3-SHA,
  ECDHE-ECDSA-DES-CBC3-SHA, EDH-RSA-DES-CBC3-SHA,  EDH-DSS-DES-CBC3-SHA,
  ECDH-RSA-DES-CBC3-SHA, ECDH-ECDSA-DES-CBC3-SHA, DES-CBC3-SHA,
  IDEA-CBC-SHA, PSK-3DES-EDE-CBC-SHA, KRB5-IDEA-CBC-SHA,
  KRB5-DES-CBC3-SHA, KRB5-IDEA-CBC-MD5, KRB5-DES-CBC3-MD5,
  ECDHE-RSA-RC4-SHA, ECDHE-ECDSA-RC4-SHA, ECDH-RSA-RC4-SHA,
  ECDH-ECDSA-RC4-SHA, RC4-SHA, RC4-MD5, PSK-RC4-SHA, KRB5-RC4-SHA,
  KRB5-RC4-MD5]



This is not available for the other WEBrick running on tcp/8008 (aka. "smart_proxy_dynflow_core").

So I patched the service myself to get rid of "TLSv1.1" and all those "Medium grade encryption" and triple DES ciphers.

Patches were modified from https://github.com/theforeman/smart_proxy_dynflow/blob/master/lib/smart_proxy_dynflow_core/webrick-patch.rb and were applied as files:
/opt/theforeman/tfm/root/usr/share/gems/gems/smart_proxy_dynflow_core-0.1.3.1/lib/smart_proxy_dynflow_core/launcher.rb
   and
/opt/theforeman/tfm/root/usr/share/gems/gems/smart_proxy_dynflow_core-0.1.3.1/lib/smart_proxy_dynflow_core/webrick-patch.rb
Comment 2 Pablo Hess 2017-07-21 16:04:16 EDT
Scan results against port 9090 of the internal capsule BEFORE the patches:
-------------------------------------------------------------------------

 Testing protocols (via sockets except TLS 1.2, SPDY+HTTP2) 

 SSLv2               not offered (OK)
 SSLv3               not offered (OK)
 TLS 1               not offered
 TLS 1.1             not offered
 TLS 1.2             offered (OK)
 Version tolerance   downgraded to TLSv1.2 (OK)
 SPDY/NPN            not offered
 HTTP2/ALPN          Local problem: /bin/openssl doesn't support HTTP2/ALPN


 Testing ~standard cipher lists 

 Null Ciphers                 not offered (OK)
 Anonymous NULL Ciphers       not offered (OK)
 Anonymous DH Ciphers         not offered (OK)
 40 Bit encryption            not offered (OK)
 56 Bit export ciphers        Local problem: No 56 Bit export ciphers configured in /bin/openssl
 Export Ciphers (general)     not offered (OK)
 Low (<=64 Bit)               not offered (OK)
 DES Ciphers                  not offered (OK)
 "Medium" grade encryption    not offered (OK)
 Triple DES Ciphers           not offered (OK)
 High grade encryption        offered (OK)


 Testing robust (perfect) forward secrecy, (P)FS -- omitting Null Authentication/Encryption, 3DES, RC4 

 No ciphers supporting Forward Secrecy offered


 Testing server preferences 

 Has server cipher order?     yes (OK)
 Negotiated protocol          TLSv1.2
 Negotiated cipher            AES128-GCM-SHA256 (openssl cannot show DH bits)
 Cipher order
    TLSv1.2:   AES128-GCM-SHA256 AES256-GCM-SHA384 AES128-SHA256 AES256-SHA256 AES128-SHA AES256-SHA


 Testing vulnerabilities 

 Heartbleed (CVE-2014-0160)                not vulnerable (OK), timed out
 CCS (CVE-2014-0224)                       not vulnerable (OK)
 Secure Renegotiation (CVE-2009-3555)      not vulnerable (OK)
 Secure Client-Initiated Renegotiation     VULNERABLE (NOT ok), DoS threat
 CRIME, TLS (CVE-2012-4929)                not vulnerable (OK)
 BREACH (CVE-2013-3587)                    no HTTP compression (OK)  - only supplied "/" tested
 POODLE, SSL (CVE-2014-3566)               not vulnerable (OK)
 TLS_FALLBACK_SCSV (RFC 7507),             No fallback possible, TLS 1.2 is the only protocol (OK)
 FREAK (CVE-2015-0204)                     not vulnerable (OK) (tested with 4/9 ciphers)
 DROWN (2016-0800, CVE-2016-0703)          not vulnerable on this port (OK)
 LOGJAM (CVE-2015-4000), experimental      not vulnerable (OK) (tested w/ 2/4 ciphers only!), common primes not checked.
 BEAST (CVE-2011-3389)                     no SSL3 or TLS1 (OK)
 RC4 (CVE-2013-2566, CVE-2015-2808)        no RC4 ciphers detected (OK)
Comment 3 Pablo Hess 2017-07-21 16:05:30 EDT
Scan results against port 8008 of the internal capsule BEFORE the patches:
-------------------------------------------------------------------------

 Testing protocols (via sockets except TLS 1.2, SPDY+HTTP2) 

 SSLv2               not offered (OK)
 SSLv3               not offered (OK)
 TLS 1               not offered
 TLS 1.1             offered
 TLS 1.2             offered (OK)
 Version tolerance   downgraded to TLSv1.2 (OK)
 SPDY/NPN            not offered
 HTTP2/ALPN          Local problem: /bin/openssl doesn't support HTTP2/ALPN


 Testing ~standard cipher lists 

 Null Ciphers                 not offered (OK)
 Anonymous NULL Ciphers       not offered (OK)
 Anonymous DH Ciphers         not offered (OK)
 40 Bit encryption            not offered (OK)
 56 Bit export ciphers        Local problem: No 56 Bit export ciphers configured in /bin/openssl
 Export Ciphers (general)     not offered (OK)
 Low (<=64 Bit)               not offered (OK)
 DES Ciphers                  not offered (OK)
 "Medium" grade encryption    offered (NOT ok)
 Triple DES Ciphers           offered
 High grade encryption        offered (OK)


 Testing robust (perfect) forward secrecy, (P)FS -- omitting Null Authentication/Encryption, 3DES, RC4 

 PFS is offered (OK)          DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA DHE-RSA-CAMELLIA128-SHA DHE-RSA-CAMELLIA256-SHA
 DHE-RSA-SEED-SHA


 Testing server preferences 

 Has server cipher order?     yes (OK)
 Negotiated protocol          TLSv1.2
 Negotiated cipher            DHE-RSA-AES256-GCM-SHA384, 1024 bit DH
 Cipher order
    TLSv1.1:   DHE-RSA-AES256-SHA DHE-RSA-CAMELLIA256-SHA AES256-SHA CAMELLIA256-SHA DHE-RSA-AES128-SHA DHE-RSA-SEED-SHA DHE-RSA-CAMELLIA128-SHA AES128-SHA SEED-SHA CAMELLIA128-SHA EDH-RSA-DES-CBC3-SHA DES-CBC3-
SHA IDEA-CBC-SHA RC4-SHA RC4-MD5
    TLSv1.2:   DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA DHE-RSA-CAMELLIA256-SHA AES256-GCM-SHA384 AES256-SHA256 AES256-SHA CAMELLIA256-SHA DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-SHA25
6 DHE-RSA-AES128-SHA DHE-RSA-SEED-SHA DHE-RSA-CAMELLIA128-SHA AES128-GCM-SHA256 AES128-SHA256 AES128-SHA SEED-SHA CAMELLIA128-SHA EDH-RSA-DES-CBC3-SHA DES-CBC3-SHA IDEA-CBC-SHA RC4-SHA RC4-MD5
Comment 4 Pablo Hess 2017-07-21 16:07:48 EDT
Patch applied as:
/opt/theforeman/tfm/root/usr/share/gems/gems/smart_proxy_dynflow_core-0.1.3.1/lib/smart_proxy_dynflow_core/webrick-patch.rb
------------------------------------------------------------

require 'webrick/https'

CIPHERS = ['ECDHE-RSA-AES128-GCM-SHA256','ECDHE-RSA-AES256-GCM-SHA384',
           'ECDHE-RSA-AES128-CBC-SHA256','ECDHE-RSA-AES256-CBC-SHA384',
           'ECDHE-RSA-AES128-GCM-SHA256','ECDHE-RSA-AES256-GCM-SHA256',
           'AES256-GCM-SHA384','AES128-GCM-SHA256','AES128-SHA256',
           'AES256-SHA256','DHE-RSA-AES256-GCM-SHA384','DHE-RSA-AES128-GCM-SHA256', 
           'DHE-RSA-AES128-SHA256','DHE-RSA-AES256-SHA256']

module WEBrick
  class GenericServer
    def setup_ssl_context(config) # :nodoc:
      unless config[:SSLCertificate]
        cn = config[:SSLCertName]
        comment = config[:SSLCertComment]
        cert, key = Utils::create_self_signed_cert(1024, cn, comment)
        config[:SSLCertificate] = cert
        config[:SSLPrivateKey] = key
      end
      ctx = OpenSSL::SSL::SSLContext.new
      ctx.set_params
      ctx.ciphers = (CIPHERS).join(':')
      ctx.key = config[:SSLPrivateKey]
      ctx.cert = config[:SSLCertificate]
      ctx.client_ca = config[:SSLClientCA]
      ctx.extra_chain_cert = config[:SSLExtraChainCert]
      ctx.ca_file = config[:SSLCACertificateFile]
      ctx.ca_path = config[:SSLCACertificatePath]
      ctx.cert_store = config[:SSLCertificateStore]
      ctx.tmp_dh_callback = config[:SSLTmpDhCallback]
      ctx.verify_mode = config[:SSLVerifyClient]
      ctx.verify_depth = config[:SSLVerifyDepth]
      ctx.verify_callback = config[:SSLVerifyCallback]
      ctx.timeout = config[:SSLTimeout]
      ctx.options |= config[:SSLOptions] unless config[:SSLOptions].nil?
      ctx
    end
  end
end
Comment 5 Pablo Hess 2017-07-21 16:08:45 EDT
Patch applied as /opt/theforeman/tfm/root/usr/share/gems/gems/smart_proxy_dynflow_core-0.1.3.1/lib/smart_proxy_dynflow_core/webrick-patch.rb
------------------------------------------------------------


require 'webrick/https'
require 'smart_proxy_dynflow_core/bundler_helper'
require 'smart_proxy_dynflow_core/settings'
require 'smart_proxy_dynflow_core/webrick-patch'
module SmartProxyDynflowCore
  class Launcher

    def self.launch!(options)
      self.new.start options
    end

    def start(options)
      load_settings!(options)
      Settings.instance.standalone = true
      Rack::Server.new(rack_settings).start
    end

    def load_settings!(options = {})
      config_dir, one_config = options.values_at(:config_dir, :one_config)
      possible_config_dirs = [
        '/etc/smart_proxy_dynflow_core',
        File.expand_path('~/.config/smart_proxy_dynflow_core'),
        File.join(File.dirname(__FILE__), '..', '..', 'config'),
      ]
      possible_config_dirs << config_dir if config_dir
      BundlerHelper.require_groups(:default)
      possible_config_dirs.reverse! if one_config
      possible_config_dirs.select { |config_dir| File.directory? config_dir }.each do |config_dir|
        break if load_config_dir(config_dir) && one_config
      end
      Settings.instance.daemonize = options[:daemonize] if options.key?(:daemonize)
      Settings.instance.pid_file = options[:pid_file] if options.key?(:pid_file)
      Settings.loaded!
    end

    def self.route_mapping(rack_builder)
      rack_builder.map '/console' do
        run Core.web_console
      end

      rack_builder.map '/' do
        run Api
      end
    end

    private

    def rack_settings
      settings = if https_enabled?
                   Log.instance.debug "Using HTTPS"
                   https_app
                 else
                   Log.instance.debug "Using HTTP"
                   {}
                 end
      settings.merge(base_settings)
    end

    def app
      Rack::Builder.new do
        SmartProxyDynflowCore::Launcher.route_mapping(self)
      end
    end

    def base_settings
      {
        :app => app,
        :Host => Settings.instance.listen,
        :Port => Settings.instance.port,
        :AccessLog => [[Log.log_file, WEBrick::AccessLog::COMMON_LOG_FORMAT]],
        :Logger => Log.instance,
        :daemonize => Settings.instance.daemonize,
        :pid => Settings.instance.pid_file
      }
    end

    def https_app
      ssl_options  = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
      ssl_options |= OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE if defined?(OpenSSL::SSL::OP_CIPHER_SERVER_PREFERENCE)
      # This is required to disable SSLv3 on Ruby 1.8.7
      ssl_options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
      ssl_options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
      ssl_options |= OpenSSL::SSL::OP_NO_TLSv1 if defined?(OpenSSL::SSL::OP_NO_TLSv1)
      ssl_options |= OpenSSL::SSL::OP_NO_TLSv1_1 if defined?(OpenSSL::SSL::OP_NO_TLSv1_1)

      {
        :SSLEnable => true,
        :SSLVerifyClient => OpenSSL::SSL::VERIFY_PEER,
        :SSLPrivateKey => ssl_private_key,
        :SSLCertificate => ssl_certificate,
        :SSLCACertificateFile => Settings.instance.ssl_ca_file,
        :SSLOptions => ssl_options
      }
    end

    def https_enabled?
      Settings.instance.use_https
    end

    def ssl_private_key
      OpenSSL::PKey::RSA.new(File.read(Settings.instance.ssl_private_key))
    rescue Exception => e
      Log.instance.fatal "Unable to load private SSL key. Are the values correct in settings.yml and do permissions allow reading?: #{e}"
      raise e
    end

    def ssl_certificate
      OpenSSL::X509::Certificate.new(File.read(Settings.instance.ssl_certificate))
    rescue Exception => e
      Log.instance.fatal "Unable to load SSL certificate. Are the values correct in settings.yml and do permissions allow reading?: #{e}"
      raise e
    end

    def load_config_dir(dir)
      settings_yml = File.join(dir, 'settings.yml')
      if File.exist? settings_yml
        Log.instance.debug "Loading settings from #{dir}"
        Settings.load_global_settings settings_yml
        Dir[File.join(dir, 'settings.d', '*.yml')].each { |path| Settings.load_plugin_settings(path) }
        true
      end
    end
  end
end

Note You need to log in before you can comment on or make changes to this bug.