[前][次][番号順一覧][スレッド一覧]

ruby-changes:65529

From: Jeremy <ko1@a...>
Date: Tue, 16 Mar 2021 20:39:26 +0900 (JST)
Subject: [ruby-changes:65529] e2ce383044 (master): [ruby/openssl] Enhance TLS 1.3 support on LibreSSL 3.2/3.3

https://git.ruby-lang.org/ruby.git/commit/?id=e2ce383044

From e2ce3830447b95fbb7d9b8dff80b8c1716688da0 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Thu, 3 Dec 2020 09:12:12 -0800
Subject: [ruby/openssl] Enhance TLS 1.3 support on LibreSSL 3.2/3.3

This defines TLS1_3_VERSION when using LibreSSL 3.2+.  LibreSSL 3.2/3.3
doesn't advertise this by default, even though it will use TLS 1.3
in both client and server modes.

Changes between LibreSSL 3.1 and 3.2/3.3 broke a few tests, Defining
TLS1_3_VERSION by itself fixes 1 test failure.  A few tests now
fail on LibreSSL 3.2/3.3 unless TLS 1.2 is set as the maximum version,
and this adjusts those tests.  The client CA test doesn't work in
LibreSSL 3.2+, so I've marked that as pending.

For the hostname verification, LibreSSL 3.2.2+ has a new stricter
hostname verifier that doesn't like subjectAltName such as
c*.example.com and d.*.example.com, so adjust the related tests.

With these changes, the tests pass on LibreSSL 3.2/3.3.

https://github.com/ruby/openssl/commit/a0e98d48c9
---
 ext/openssl/ossl_ssl.c           |  6 ++++++
 test/openssl/test_ssl.rb         | 25 +++++++++++++++++-----
 test/openssl/test_ssl_session.rb |  1 +
 test/openssl/test_ts.rb          |  2 ++
 test/openssl/test_x509store.rb   | 46 +++++++++++++++++++++++-----------------
 5 files changed, 56 insertions(+), 24 deletions(-)

diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index dfe0944..c38142b 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -13,6 +13,12 @@ https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L13
 
 #define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))
 
+#if !defined(TLS1_3_VERSION) && \
+    defined(LIBRESSL_VERSION_NUMBER) && \
+    LIBRESSL_VERSION_NUMBER >= 0x3020000fL
+#  define TLS1_3_VERSION 0x0304
+#endif
+
 #ifdef _WIN32
 #  define TO_SOCKET(s) _get_osfhandle(s)
 #else
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index 43f1fb9..750d64f 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -306,7 +306,10 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ssl.rb#L306
 
   def test_client_auth_success
     vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
-    start_server(verify_mode: vflag) { |port|
+    start_server(verify_mode: vflag,
+      ctx_proc: proc { |ctx|
+        ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?(3, 2, 0)
+    }) { |port|
       ctx = OpenSSL::SSL::SSLContext.new
       ctx.key = @cli_key
       ctx.cert = @cli_cert
@@ -348,6 +351,8 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ssl.rb#L351
   end
 
   def test_client_ca
+    pend "LibreSSL 3.2 has broken client CA support" if libressl?(3, 2, 0)
+
     ctx_proc = Proc.new do |ctx|
       ctx.client_ca = [@ca_cert]
     end
@@ -453,7 +458,11 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ssl.rb#L458
       ssl.sync_close = true
       begin
         assert_raise(OpenSSL::SSL::SSLError){ ssl.connect }
-        assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result)
+        assert_include(
+          [
+            OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
+            OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
+          ], ssl.verify_result)
       ensure
         ssl.close
       end
@@ -523,6 +532,8 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ssl.rb#L532
     start_server(accept_proc: proc { |server|
       server_finished = server.finished_message
       server_peer_finished = server.peer_finished_message
+    }, ctx_proc: proc { |ctx|
+      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?(3, 2, 0)
     }) { |port|
       ctx = OpenSSL::SSL::SSLContext.new
       ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
@@ -913,11 +924,13 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ssl.rb#L924
 
   def test_verify_hostname_on_connect
     ctx_proc = proc { |ctx|
+      san = "DNS:a.example.com,DNS:*.b.example.com"
+      san += ",DNS:c*.example.com,DNS:d.*.example.com" unless libressl?(3, 2, 2)
       exts = [
         ["keyUsage", "keyEncipherment,digitalSignature", true],
-        ["subjectAltName", "DNS:a.example.com,DNS:*.b.example.com," \
-                           "DNS:c*.example.com,DNS:d.*.example.com"],
+        ["subjectAltName", san],
       ]
+ 
       ctx.cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key)
       ctx.key = @svr_key
     }
@@ -939,6 +952,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ssl.rb#L952
         ["cx.example.com", true],
         ["d.x.example.com", false],
       ].each do |name, expected_ok|
+        next if name.start_with?('cx') if libressl?(3, 2, 2)
         begin
           sock = TCPSocket.new("127.0.0.1", port)
           ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
@@ -1001,7 +1015,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ssl.rb#L1015
     start_server(ignore_listener_error: true) { |port|
       ctx = OpenSSL::SSL::SSLContext.new
       ctx.set_params
-      assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed/) {
+      assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed|unable to get local issuer certificate/) {
         server_connect(port, ctx)
       }
     }
@@ -1609,6 +1623,7 @@ end https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ssl.rb#L1623
     ctx_proc = -> ctx {
       # Enable both ECDHE (~ TLS 1.2) cipher suites and TLS 1.3
       ctx.ciphers = "DEFAULT:!kRSA:!kEDH"
+      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?(3, 2, 0)
       ctx.ecdh_curves = "P-384:P-521"
     }
     start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|
diff --git a/test/openssl/test_ssl_session.rb b/test/openssl/test_ssl_session.rb
index 89726d4..a98efda 100644
--- a/test/openssl/test_ssl_session.rb
+++ b/test/openssl/test_ssl_session.rb
@@ -122,6 +122,7 @@ __EOS__ https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ssl_session.rb#L122
       ctx.options &= ~OpenSSL::SSL::OP_NO_TICKET
       # Disable server-side session cache which is enabled by default
       ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_OFF
+      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?(3, 2, 0)
     }
     start_server(ctx_proc: ctx_proc) do |port|
       sess1 = server_connect_with_session(port, nil, nil) { |ssl|
diff --git a/test/openssl/test_ts.rb b/test/openssl/test_ts.rb
index 6e9c308..d39f3d3 100644
--- a/test/openssl/test_ts.rb
+++ b/test/openssl/test_ts.rb
@@ -382,6 +382,7 @@ _end_of_pem_ https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ts.rb#L382
   end
 
   def test_verify_ee_wrong_root_no_intermediate
+    pend "LibreSSL 3.2.2 Timestamp Issue" if libressl?(3, 2, 2)
     assert_raise(OpenSSL::Timestamp::TimestampError) do
       ts, req = timestamp_ee
       ts.verify(req, intermediate_store)
@@ -389,6 +390,7 @@ _end_of_pem_ https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ts.rb#L390
   end
 
   def test_verify_ee_wrong_root_wrong_intermediate
+    pend "LibreSSL 3.2.2 Timestamp Issue" if libressl?(3, 2, 2)
     assert_raise(OpenSSL::Timestamp::TimestampError) do
       ts, req = timestamp_ee
       ts.verify(req, intermediate_store, [ca_cert])
diff --git a/test/openssl/test_x509store.rb b/test/openssl/test_x509store.rb
index 7bbbc66..897f0f8 100644
--- a/test/openssl/test_x509store.rb
+++ b/test/openssl/test_x509store.rb
@@ -32,15 +32,17 @@ class OpenSSL::TestX509Store < OpenSSL::TestCase https://github.com/ruby/ruby/blob/trunk/test/openssl/test_x509store.rb#L32
     assert_equal true, store.verify(cert1)
     assert_equal true, store.verify(cert2)
 
-    # X509::Store#add_path
-    Dir.mktmpdir do |dir|
-      hash1 = "%08x.%d" % [cert1_subj.hash, 0]
-      File.write(File.join(dir, hash1), cert1.to_pem)
-      store = OpenSSL::X509::Store.new
-      store.add_path(dir)
-
-      assert_equal true, store.verify(cert1)
-      assert_equal false, store.verify(cert2)
+    unless libressl?(3, 2, 2)
+      # X509::Store#add_path
+      Dir.mktmpdir do |dir|
+        hash1 = "%08x.%d" % [cert1_subj.hash, 0]
+        File.write(File.join(dir, hash1), cert1.to_pem)
+        store = OpenSSL::X509::Store.new
+        store.add_path(dir)
+
+        assert_equal true, store.verify(cert1)
+        assert_equal false, store.verify(cert2)
+      end
     end
 
     # OpenSSL < 1.1.1 leaks an error on a duplicate certificate
@@ -75,8 +77,8 @@ class OpenSSL::TestX509Store < OpenSSL::TestCase https://github.com/ruby/ruby/blob/trunk/test/openssl/test_x509store.rb#L77
     # Nothing trusted
     store = OpenSSL::X509::Store.new
     assert_equal(false, store.verify(ee1_cert, [ca2_cert, ca1_cert]))
-    assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, store.error)
-    assert_match(/self.signed/i, store.error_string)
+    assert_include([OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY], store.error)
+    assert_match(/self.signed|unable to get local issuer certificate/i, store.error_string)
 
     # CA1 trusted, CA2 missing
     store = OpenSSL::X509::Store.new
@@ -121,10 +123,11 @@ class OpenSSL::TestX509Store < OpenSSL::TestCase https://github.com/ruby/ruby/blob/trunk/test/openssl/test_x509store.rb#L123
     }
     store.add_cert(ca1_cert)
     assert_equal(true, store.verify(ee1_cert, [ca2_cert]))
-    assert_equal(3, cb_calls.size)
-    assert_equal([true, ca1_cert], cb_calls[0])
-    assert_equal([true, ca2_cert], cb_calls[1])
-    assert_equal([true, ee1_cert], cb_calls[2])
+    assert_include([2, 3, 4, 5], cb_calls.size)
+     (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]