diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2015-08-15 12:00:04 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2015-08-18 15:42:30 +0900 |
commit | 498ec1d4f3d295c5e2e943e79740e803d467a8a8 (patch) | |
tree | e4c79060fae3d646a03e17d15fa8b6027208729c | |
parent | 218a0c560135ce1f8d3afe6eae0c09165ab42f2f (diff) | |
download | plum-498ec1d4f3d295c5e2e943e79740e803d467a8a8.tar.gz |
https_connection: raise INADEQUATE_SECURITY when negotiated in non-secure cipher suite
-rw-r--r-- | lib/plum/https_connection.rb | 24 | ||||
-rw-r--r-- | test/plum/test_https_connection.rb | 51 |
2 files changed, 75 insertions, 0 deletions
diff --git a/lib/plum/https_connection.rb b/lib/plum/https_connection.rb index a1def19..95f2837 100644 --- a/lib/plum/https_connection.rb +++ b/lib/plum/https_connection.rb @@ -1,7 +1,31 @@ module Plum class HTTPSConnection < Connection def initialize(io, local_settings = {}) + if io.respond_to?(:cipher) # OpenSSL::SSL::SSLSocket-like + if CIPHER_BLACKLIST.include?(io.cipher.first) # [cipher-suite, ssl-version, keylen, alglen] + self.on(:negotiated) { + raise ConnectionError.new(:inadequate_security) + } + end + end + super end + + CIPHER_BLACKLIST = %w( + NULL-MD5 NULL-SHA EXP-RC4-MD5 RC4-MD5 RC4-SHA EXP-RC2-CBC-MD5 IDEA-CBC-SHA EXP-DES-CBC-SHA DES-CBC-SHA DES-CBC3-SHA + DH-DSS-DES-CBC-SHA DH-DSS-DES-CBC3-SHA DH-RSA-DES-CBC-SHA DH-RSA-DES-CBC3-SHA EXP-EDH-DSS-DES-CBC-SHA EDH-DSS-DES-CBC-SHA EDH-DSS-DES-CBC3-SHA EXP-EDH-RSA-DES-CBC-SHA EDH-RSA-DES-CBC-SHA EDH-RSA-DES-CBC3-SHA + EXP-ADH-RC4-MD5 ADH-RC4-MD5 EXP-ADH-DES-CBC-SHA ADH-DES-CBC-SHA ADH-DES-CBC3-SHA AES128-SHA DH-DSS-AES128-SHA DH-RSA-AES128-SHA DHE-DSS-AES128-SHA DHE-RSA-AES128-SHA + ADH-AES128-SHA AES256-SHA DH-DSS-AES256-SHA DH-RSA-AES256-SHA DHE-DSS-AES256-SHA DHE-RSA-AES256-SHA ADH-AES256-SHA NULL-SHA256 AES128-SHA256 AES256-SHA256 + DH-DSS-AES128-SHA256 DH-RSA-AES128-SHA256 DHE-DSS-AES128-SHA256 CAMELLIA128-SHA DH-DSS-CAMELLIA128-SHA DH-RSA-CAMELLIA128-SHA DHE-DSS-CAMELLIA128-SHA DHE-RSA-CAMELLIA128-SHA ADH-CAMELLIA128-SHA DHE-RSA-AES128-SHA256 + DH-DSS-AES256-SHA256 DH-RSA-AES256-SHA256 DHE-DSS-AES256-SHA256 DHE-RSA-AES256-SHA256 ADH-AES128-SHA256 ADH-AES256-SHA256 CAMELLIA256-SHA DH-DSS-CAMELLIA256-SHA DH-RSA-CAMELLIA256-SHA DHE-DSS-CAMELLIA256-SHA + DHE-RSA-CAMELLIA256-SHA ADH-CAMELLIA256-SHA PSK-RC4-SHA PSK-3DES-EDE-CBC-SHA PSK-AES128-CBC-SHA PSK-AES256-CBC-SHA SEED-SHA DH-DSS-SEED-SHA DH-RSA-SEED-SHA DHE-DSS-SEED-SHA + DHE-RSA-SEED-SHA ADH-SEED-SHA AES128-GCM-SHA256 AES256-GCM-SHA384 DH-RSA-AES128-GCM-SHA256 DH-RSA-AES256-GCM-SHA384 DH-DSS-AES128-GCM-SHA256 DH-DSS-AES256-GCM-SHA384 ADH-AES128-GCM-SHA256 ADH-AES256-GCM-SHA384 + ECDH-ECDSA-NULL-SHA ECDH-ECDSA-RC4-SHA ECDH-ECDSA-DES-CBC3-SHA ECDH-ECDSA-AES128-SHA ECDH-ECDSA-AES256-SHA ECDHE-ECDSA-NULL-SHA ECDHE-ECDSA-RC4-SHA ECDHE-ECDSA-DES-CBC3-SHA ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA + ECDH-RSA-NULL-SHA ECDH-RSA-RC4-SHA ECDH-RSA-DES-CBC3-SHA ECDH-RSA-AES128-SHA ECDH-RSA-AES256-SHA ECDHE-RSA-NULL-SHA ECDHE-RSA-RC4-SHA ECDHE-RSA-DES-CBC3-SHA ECDHE-RSA-AES128-SHA ECDHE-RSA-AES256-SHA + AECDH-NULL-SHA AECDH-RC4-SHA AECDH-DES-CBC3-SHA AECDH-AES128-SHA AECDH-AES256-SHA SRP-3DES-EDE-CBC-SHA SRP-RSA-3DES-EDE-CBC-SHA SRP-DSS-3DES-EDE-CBC-SHA SRP-AES-128-CBC-SHA SRP-RSA-AES-128-CBC-SHA + SRP-DSS-AES-128-CBC-SHA SRP-AES-256-CBC-SHA SRP-RSA-AES-256-CBC-SHA SRP-DSS-AES-256-CBC-SHA ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES256-SHA384 ECDH-ECDSA-AES128-SHA256 ECDH-ECDSA-AES256-SHA384 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-SHA384 + ECDH-RSA-AES128-SHA256 ECDH-RSA-AES256-SHA384 ECDH-ECDSA-AES128-GCM-SHA256 ECDH-ECDSA-AES256-GCM-SHA384 ECDH-RSA-AES128-GCM-SHA256 ECDH-RSA-AES256-GCM-SHA384 + ) end end diff --git a/test/plum/test_https_connection.rb b/test/plum/test_https_connection.rb index ba86b1e..d8c3789 100644 --- a/test/plum/test_https_connection.rb +++ b/test/plum/test_https_connection.rb @@ -34,4 +34,55 @@ class HTTPSConnectionNegotiationTest < Minitest::Test con << Frame.new(type: :settings, stream_id: 0).assemble } end + + def test_inadequate_security_ssl_socket + run = false + + ctx = OpenSSL::SSL::SSLContext.new + ctx.alpn_select_cb = -> protocols { "h2" } + ctx.cert = OpenSSL::X509::Certificate.new File.read(File.expand_path("../../server.crt", __FILE__)) + ctx.key = OpenSSL::PKey::RSA.new File.read(File.expand_path("../../server.key", __FILE__)) + tcp_server = TCPServer.new("127.0.0.1", LISTEN_PORT) + ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx) + + server_thread = Thread.new { + begin + timeout(3) { + sock = ssl_server.accept + plum = HTTPSConnection.new(sock) + assert_connection_error(:inadequate_security) { + run = true + plum.run + } + } + rescue TimeoutError + flunk "server timeout" + ensure + tcp_server.close + end + } + client_thread = Thread.new { + sock = TCPSocket.new("127.0.0.1", LISTEN_PORT) + begin + timeout(3) { + ctx = OpenSSL::SSL::SSLContext.new.tap {|ctx| + ctx.alpn_protocols = ["h2"] + ctx.ciphers = "AES256-GCM-SHA384" + } + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.connect + ssl.write Connection::CLIENT_CONNECTION_PREFACE + ssl.write Frame.settings.assemble + } + rescue TimeoutError + flunk "client timeout" + ensure + sock.close + end + } + client_thread.join + server_thread.join + + flunk "test not run" unless run + end end |