From 51de9c303e70892285a55ccff8d0b49377a78e03 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Wed, 24 Jun 2026 20:03:57 +0900 Subject: [PATCH] ssl: let SSLServer accept frozen SSLContext Do not raise FrozenError in SSLServer.new when SSLContext#session_id_context cannot be updated. session_id_context is only necessary for session resumption, so its absence is not critical. Fixes https://github.com/ruby/openssl/pull/742 --- lib/openssl/ssl.rb | 2 +- test/openssl/test_ssl_server.rb | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 test/openssl/test_ssl_server.rb diff --git a/lib/openssl/ssl.rb b/lib/openssl/ssl.rb index 3268c126b..dccc11a55 100644 --- a/lib/openssl/ssl.rb +++ b/lib/openssl/ssl.rb @@ -486,7 +486,7 @@ class SSLServer def initialize(svr, ctx) @svr = svr @ctx = ctx - unless ctx.session_id_context + if !ctx.frozen? && !ctx.session_id_context # see #6137 - session id may not exceed 32 bytes prng = ::Random.new($0.hash) session_id = prng.bytes(16).unpack1('H*') diff --git a/test/openssl/test_ssl_server.rb b/test/openssl/test_ssl_server.rb new file mode 100644 index 000000000..076b58965 --- /dev/null +++ b/test/openssl/test_ssl_server.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true +require_relative "utils" + +return unless defined?(OpenSSL::SSL) + +class OpenSSL::TestSSLServer < OpenSSL::SSLTestCase + def test_tcpserver + tcps = TCPServer.new("127.0.0.1", 0) + sctx = OpenSSL::SSL::SSLContext.new + sctx.add_certificate(@svr_cert, @svr_key) + server = OpenSSL::SSL::SSLServer.new(tcps, sctx) + assert_same(tcps, server.to_io) + assert_kind_of(String, sctx.session_id_context) + th = Thread.start do + sssl = server.accept + sssl.puts(sssl.gets) + ensure + sssl&.close + end + server_connect(tcps.local_address.ip_port) do |ssl| + assert_equal(@svr_cert.to_der, ssl.peer_cert.to_der) + ssl.puts("abc") + assert_equal("abc\n", ssl.gets) + end + th.join + server.close + assert_predicate(tcps, :closed?) + end + + def test_ctx_frozen + tcps = TCPServer.new("127.0.0.1", 0) + sctx = OpenSSL::SSL::SSLContext.new + sctx.add_certificate(@svr_cert, @svr_key) + sctx.setup + server = OpenSSL::SSL::SSLServer.new(tcps, sctx) + assert_nil(sctx.session_id_context) + th = Thread.start do + sssl = server.accept + sssl.puts(sssl.gets) + ensure + sssl&.close + end + server_connect(tcps.local_address.ip_port) do |ssl| + assert_equal(@svr_cert.to_der, ssl.peer_cert.to_der) + ssl.puts("abc") + assert_equal("abc\n", ssl.gets) + end + th.join + server.close + end + + private + + def server_connect(port, ctx = nil) + sock = TCPSocket.new("127.0.0.1", port) + ssl = ctx ? OpenSSL::SSL::SSLSocket.new(sock, ctx) : OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + ssl.connect + yield ssl if block_given? + ensure + if ssl + ssl.close + elsif sock + sock.close + end + end +end