aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2015-08-15 12:00:04 +0900
committerKazuki Yamaguchi <k@rhe.jp>2015-08-18 15:42:30 +0900
commit498ec1d4f3d295c5e2e943e79740e803d467a8a8 (patch)
treee4c79060fae3d646a03e17d15fa8b6027208729c
parent218a0c560135ce1f8d3afe6eae0c09165ab42f2f (diff)
downloadplum-498ec1d4f3d295c5e2e943e79740e803d467a8a8.tar.gz
https_connection: raise INADEQUATE_SECURITY when negotiated in non-secure cipher suite
-rw-r--r--lib/plum/https_connection.rb24
-rw-r--r--test/plum/test_https_connection.rb51
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