diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb index 3268c126b9efad..dccc11a5567f04 100644 --- a/ext/openssl/lib/openssl/ssl.rb +++ b/ext/openssl/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/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c index 9e43336c4406f2..bed124dc3ed454 100644 --- a/ext/openssl/ossl_x509store.c +++ b/ext/openssl/ossl_x509store.c @@ -224,6 +224,41 @@ ossl_x509store_initialize(int argc, VALUE *argv, VALUE self) return self; } +/* + * call-seq: + * store.flags -> Integer + * + * Gets the verification flags for the Store. + * + * See also the man page X509_VERIFY_PARAM_get_flags(3). + */ +static VALUE +ossl_x509store_get_flags(VALUE self) +{ + X509_STORE *store; + X509_VERIFY_PARAM *vpm; + + GetX509Store(self, store); + vpm = X509_STORE_get0_param(store); + return ULONG2NUM(X509_VERIFY_PARAM_get_flags(vpm)); +} + +static void +x509vpm_set_flags_i(X509_VERIFY_PARAM *vpm, VALUE flags) +{ + unsigned long curr = X509_VERIFY_PARAM_get_flags(vpm); + unsigned long f = NUM2ULONG(flags); + + if ((curr | f) != f) { + rb_warn("`obj.flags = new_flags` does not clear existing flags; " \ + "use `obj.clear_flags` first if you want to replace them, " \ + "or `obj.flags |= new_flags` to indicate that " \ + "appending flags is intentional"); + } + if (!X509_VERIFY_PARAM_set_flags(vpm, f)) + ossl_raise(eX509StoreError, "X509_VERIFY_PARAM_set_flags"); +} + /* * call-seq: * store.flags = flags @@ -231,6 +266,10 @@ ossl_x509store_initialize(int argc, VALUE *argv, VALUE self) * Sets the default flags used by certificate chain verification performed with * the Store. * + * *NOTE*: Despite the name, this method appends the specified flags to the + * existing flag set rather than replacing it. To clear existing flags, use + * #clear_flags before calling this method. + * * _flags_ consists of zero or more of the constants defined in OpenSSL::X509 * with name V_FLAG_* or'ed together. * @@ -243,14 +282,42 @@ static VALUE ossl_x509store_set_flags(VALUE self, VALUE flags) { X509_STORE *store; - long f = NUM2LONG(flags); GetX509Store(self, store); - X509_STORE_set_flags(store, f); - + x509vpm_set_flags_i(X509_STORE_get0_param(store), flags); return flags; } +static void +x509vpm_clear_flags_i(X509_VERIFY_PARAM *vpm, VALUE flags) +{ + unsigned long f = NIL_P(flags) ? ~0UL : NUM2ULONG(flags); + + if (!X509_VERIFY_PARAM_clear_flags(vpm, f)) + ossl_raise(eX509StoreError, "X509_VERIFY_PARAM_clear_flags"); +} + +/* + * call-seq: + * store.clear_flags(flags = nil) + * + * Clears verification flags _flags_ for the Store. If _flags_ is omitted, + * clears all existing flags. + * + * See also the man page X509_VERIFY_PARAM_clear_flags(3). + */ +static VALUE +ossl_x509store_clear_flags(int argc, VALUE *argv, VALUE self) +{ + X509_STORE *store; + VALUE flags; + + rb_scan_args(argc, argv, "01", &flags); + GetX509Store(self, store); + x509vpm_clear_flags_i(X509_STORE_get0_param(store), flags); + return Qnil; +} + /* * call-seq: * store.purpose = purpose @@ -768,6 +835,25 @@ ossl_x509stctx_get_curr_crl(VALUE self) return ossl_x509crl_new(crl); } +/* + * call-seq: + * stctx.flags -> Integer + * + * Gets the verification flags for the context. + * + * See also the man page X509_VERIFY_PARAM_get_flags(3). + */ +static VALUE +ossl_x509stctx_get_flags(VALUE self) +{ + X509_STORE_CTX *ctx; + X509_VERIFY_PARAM *vpm; + + GetX509StCtx(self, ctx); + vpm = X509_STORE_CTX_get0_param(ctx); + return ULONG2NUM(X509_VERIFY_PARAM_get_flags(vpm)); +} + /* * call-seq: * stctx.flags = flags @@ -775,20 +861,43 @@ ossl_x509stctx_get_curr_crl(VALUE self) * Sets the verification flags to the context. This overrides the default value * set by Store#flags=. * + * *NOTE*: Despite the name, this method appends the specified flags to the + * existing flag set rather than replacing it. To clear existing flags, use + * #clear_flags before calling this method. + * * See also the man page X509_VERIFY_PARAM_set_flags(3). */ static VALUE ossl_x509stctx_set_flags(VALUE self, VALUE flags) { - X509_STORE_CTX *store; - long f = NUM2LONG(flags); - - GetX509StCtx(self, store); - X509_STORE_CTX_set_flags(store, f); + X509_STORE_CTX *ctx; + GetX509StCtx(self, ctx); + x509vpm_set_flags_i(X509_STORE_CTX_get0_param(ctx), flags); return flags; } +/* + * call-seq: + * stctx.clear_flags(flags = nil) + * + * Clears verification flags _flags_ for the Store. If _flags_ is omitted, + * clears all existing flags. + * + * See also the man page X509_VERIFY_PARAM_clear_flags(3). + */ +static VALUE +ossl_x509stctx_clear_flags(int argc, VALUE *argv, VALUE self) +{ + X509_STORE_CTX *ctx; + VALUE flags; + + rb_scan_args(argc, argv, "01", &flags); + GetX509StCtx(self, ctx); + x509vpm_clear_flags_i(X509_STORE_CTX_get0_param(ctx), flags); + return Qnil; +} + /* * call-seq: * stctx.purpose = purpose @@ -944,7 +1053,9 @@ Init_ossl_x509store(void) rb_define_method(cX509Store, "initialize", ossl_x509store_initialize, -1); rb_undef_method(cX509Store, "initialize_copy"); rb_define_method(cX509Store, "verify_callback=", ossl_x509store_set_vfy_cb, 1); + rb_define_method(cX509Store, "flags", ossl_x509store_get_flags, 0); rb_define_method(cX509Store, "flags=", ossl_x509store_set_flags, 1); + rb_define_method(cX509Store, "clear_flags", ossl_x509store_clear_flags, -1); rb_define_method(cX509Store, "purpose=", ossl_x509store_set_purpose, 1); rb_define_method(cX509Store, "trust=", ossl_x509store_set_trust, 1); rb_define_method(cX509Store, "time=", ossl_x509store_set_time, 1); @@ -973,7 +1084,9 @@ Init_ossl_x509store(void) rb_define_method(cX509StoreContext, "error_depth", ossl_x509stctx_get_err_depth, 0); rb_define_method(cX509StoreContext, "current_cert", ossl_x509stctx_get_curr_cert, 0); rb_define_method(cX509StoreContext, "current_crl", ossl_x509stctx_get_curr_crl, 0); + rb_define_method(cX509StoreContext, "flags", ossl_x509stctx_get_flags, 0); rb_define_method(cX509StoreContext, "flags=", ossl_x509stctx_set_flags, 1); + rb_define_method(cX509StoreContext, "clear_flags", ossl_x509stctx_clear_flags, -1); rb_define_method(cX509StoreContext, "purpose=", ossl_x509stctx_set_purpose, 1); rb_define_method(cX509StoreContext, "trust=", ossl_x509stctx_set_trust, 1); rb_define_method(cX509StoreContext, "time=", ossl_x509stctx_set_time, 1); diff --git a/gems/bundled_gems b/gems/bundled_gems index c89365a8526530..d67684d6e5d672 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -37,7 +37,7 @@ ostruct 0.6.3 https://github.com/ruby/ostruct pstore 0.2.1 https://github.com/ruby/pstore benchmark 0.5.0 https://github.com/ruby/benchmark logger 1.7.0 https://github.com/ruby/logger -rdoc 7.2.0 https://github.com/ruby/rdoc 1f93543615928b6d45357432f16ec6006e2d8b1e +rdoc 7.2.0 https://github.com/ruby/rdoc a8df5c5d03b63cf05425bf676644688ac673a329 win32ole 1.9.3 https://github.com/ruby/win32ole irb 1.18.0 https://github.com/ruby/irb reline 0.6.3 https://github.com/ruby/reline diff --git a/lib/net/http.rb b/lib/net/http.rb index 7765a11588d6c3..0e8d8bf3fa869f 100644 --- a/lib/net/http.rb +++ b/lib/net/http.rb @@ -1550,7 +1550,7 @@ def use_ssl=(flag) attr_accessor :cert_store # Sets or returns the available SSL ciphers. - # See {OpenSSL::SSL::SSLContext#ciphers=}[rdoc-ref:OpenSSL::SSL::SSLContext#ciphers-3D]. + # See {OpenSSL::SSL::SSLContext#ciphers=}[rdoc-ref:OpenSSL::SSL::SSLContext#ciphers=]. attr_accessor :ciphers # Sets or returns the extra X509 certificates to be added to the certificate chain. @@ -1564,15 +1564,15 @@ def use_ssl=(flag) attr_accessor :ssl_timeout # Sets or returns the SSL version. - # See {OpenSSL::SSL::SSLContext#ssl_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#ssl_version-3D]. + # See {OpenSSL::SSL::SSLContext#ssl_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#ssl_version=]. attr_accessor :ssl_version # Sets or returns the minimum SSL version. - # See {OpenSSL::SSL::SSLContext#min_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#min_version-3D]. + # See {OpenSSL::SSL::SSLContext#min_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#min_version=]. attr_accessor :min_version # Sets or returns the maximum SSL version. - # See {OpenSSL::SSL::SSLContext#max_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#max_version-3D]. + # See {OpenSSL::SSL::SSLContext#max_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#max_version=]. attr_accessor :max_version # Sets or returns the callback for the server certification verification. @@ -1588,7 +1588,7 @@ def use_ssl=(flag) # Sets or returns whether to verify that the server certificate is valid # for the hostname. - # See {OpenSSL::SSL::SSLContext#verify_hostname=}[rdoc-ref:OpenSSL::SSL::SSLContext#attribute-i-verify_hostname]. + # See {OpenSSL::SSL::SSLContext#verify_hostname=}[rdoc-ref:OpenSSL::SSL::SSLContext#verify_hostname]. attr_accessor :verify_hostname # Returns the X509 certificate chain (an array of strings) diff --git a/test/openssl/test_ssl_server.rb b/test/openssl/test_ssl_server.rb new file mode 100644 index 00000000000000..076b589658cb85 --- /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 diff --git a/test/openssl/test_x509store.rb b/test/openssl/test_x509store.rb index c13beae364ff1b..6385a46d95bdb0 100644 --- a/test/openssl/test_x509store.rb +++ b/test/openssl/test_x509store.rb @@ -370,6 +370,24 @@ def test_dup assert_raise(NoMethodError) { ctx.dup } end + def test_flags_clear + store = OpenSSL::X509::Store.new + assert_equal(0, store.flags) + store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK + assert_equal(OpenSSL::X509::V_FLAG_CRL_CHECK, store.flags) + assert_warning(/clear_flags/) { + store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL + } + assert_equal( + OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL, + store.flags + ) + store.clear_flags(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL) + assert_equal(OpenSSL::X509::V_FLAG_CRL_CHECK, store.flags) + store.clear_flags + assert_equal(0, store.flags) + end + def test_ctx_cleanup # Deprecated in Ruby 1.9.3 cert = OpenSSL::X509::Certificate.new diff --git a/tool/rbs_skip_tests b/tool/rbs_skip_tests index 39ac16cb8f1551..54259cfdf424f8 100644 --- a/tool/rbs_skip_tests +++ b/tool/rbs_skip_tests @@ -50,3 +50,13 @@ test_new(RegexpSingletonTest) # Errno::ENOENT: No such file or directory - bundle test_collection_install__pathname_set(RBS::CliTest) test_collection_install__set_pathname__manifest(RBS::CliTest) + +# RBS 4.0.3's RDoc plugin is incompatible with the RDoc 7.2.0 development revision +test_attr_decl_1(RDocPluginParserTest) +test_attr_decl_2(RDocPluginParserTest) +test_instance_method_1(RDocPluginParserTest) +test_instance_method_comment_and_tokens(RDocPluginParserTest) +test_instance_method_generic(RDocPluginParserTest) +test_instance_method_with_block(RDocPluginParserTest) +test_method_alias_decl_1(RDocPluginParserTest) +test_method_alias_decl_2(RDocPluginParserTest) diff --git a/tool/sync_default_gems.rb b/tool/sync_default_gems.rb index 3242dee5d2b541..9ab602ac801f9e 100755 --- a/tool/sync_default_gems.rb +++ b/tool/sync_default_gems.rb @@ -344,9 +344,10 @@ def replace_rdoc_ref(file) changed |= src.gsub!(%r[\[\Khttps://docs\.ruby-lang\.org/en/master(?:/doc)?/(([A-Z]\w+(?:/[A-Z]\w+)*)|\w+_rdoc)\.html(\#\S+)?(?=\])]) do name, mod, label = $1, $2, $3 mod &&= mod.gsub('/', '::') - if label && (m = label.match(/\A\#(?:method-([ci])|(?:(?:class|module)-#{mod}-)?label)-([-+\w]+)\z/)) + if label && (m = label.match(/\A\#(?:(?:method|attribute)-([ci])|(?:(?:class|module)-#{mod}-)?label)-(.+)\z/)) scope, label = m[1], m[2] scope = scope ? scope.tr('ci', '.#') : '@' + label.gsub!(/-(\h\h)/) {$1.to_i(16).chr(Encoding::ASCII_8BIT)} end "rdoc-ref:#{mod || name.chomp("_rdoc") + ".rdoc"}#{scope}#{label}" end diff --git a/zjit/src/invariants.rs b/zjit/src/invariants.rs index 1433b8b9b3ce56..233ffc21a7903d 100644 --- a/zjit/src/invariants.rs +++ b/zjit/src/invariants.rs @@ -374,10 +374,10 @@ pub extern "C" fn rb_zjit_constant_state_changed(id: ID) { let invariants = ZJITState::get_invariants(); if let Some(patch_points) = invariants.constant_state_patch_points.remove(&id) { let cb = ZJITState::get_code_block(); - debug!("Constant state changed: {:?}", id); + debug!("Constant state changed: {id:?}: {}", id.contents_lossy()); // Invalidate all patch points for this constant ID - compile_patch_points!(cb, patch_points, Const, "Constant state changed: {:?}", id); + compile_patch_points!(cb, patch_points, Const, "Constant state changed: {id:?}: {}", id.contents_lossy()); cb.mark_all_executable(); }