Skip to content

OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE is not shareable across ractors #521

Closed

Description

@HoneyryderChuck

I'm working on ractor-safety in the http library I maintain, and I just got this error when performing an https request:

code looks like:

ctx = OpenSSL::SSL::SSLContext.new
ctx.set_params(ctx_options)
#=> `set_params': can not access non-shareable objects in constant OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE by non-main ractor. (Ractor::Isolation
Error)

I've seen that OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE is not frozen. I'm not sure if there's a reason for it. However, even after I freeze it, it's not shareable:

irb(main):005:0> c = OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE
=> #<OpenSSL::X509::Store:0x0000000108213b90 @chain=nil, @error=nil, @error_string=nil, @time=nil, @verify_callback=nil>
irb(main):006:0> c.frozen?
=> false
irb(main):008:0> c.freeze
=> #<OpenSSL::X509::Store:0x0000000108213b90 @chain=nil, @error=nil, @error_string=nil, @time=nil, @verify_callback=nil>
irb(main):009:0> c.frozen?
=> true
irb(main):010:0> Ractor.shareable?(c)
=> false

Activity

  1. rhenium commented on Sep 8, 2022

    @rhenium
    Member

    even after I freeze it, it's not shareable:

    The direct cause is that OpenSSL::X509::Store doesn't have the RUBY_TYPED_FROZEN_SHAREABLE flag set. X509_STORE appears to be safe to share across threads.

    Actually, OpenSSL::SSL::SSLContext/SSL_CTX should also be shareable

  2. nightpool commented on Sep 21, 2024

    @nightpool

    Is this still an issue?

  3. rhenium commented on Jan 29, 2025

    @rhenium
    Member

    Making ruby/openssl objects shareable when frozen has turned out to be significantly more complicated than anticipated (see #803 #807 #816) and I don't expect it can be finished soon.

    I wonder if we can allocate a separate default store for each Ractor for now. This won't allow usage of OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE in non-main Ractors (which I would discourage, and it's been :nodoc: for several years now), but we can at least make SSLContext#set_params compatible.

  4. rhenium commented on Feb 3, 2025

    @rhenium
    Member

    A few other things needed before we can use OpenSSL::SSL in non-main Ractors:

    • OpenSSL::SSL::SSLContext::DEFAULT_PARAMS needs to be frozen. Although it wasn't the intended usage scenario, it lacked the :nodoc: tag until some time, so we would have to consider this as a breaking change.
    • OpenSSL::SSL::Buffering methods use $/ that is global and not accessible from non-main Ractors. What is the alternative? Related to https://bugs.ruby-lang.org/issues/21109: core methods implemented in Ruby are facing the same issue as ruby/openssl is; core methods implemented in C currently access rb_rs from non-main Ractors, which is unsafe because $/ can be a mutable String object.
    • The default tmp_dh_callback proc is unshareable.
  5. rhenium commented on Aug 1, 2025

    @rhenium
    Member

    I wonder if we can allocate a separate default store for each Ractor for now. This won't allow usage of OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE in non-main Ractors (which I would discourage, and it's been :nodoc: for several years now), but we can at least make SSLContext#set_params compatible.

    A few other things needed before we can use OpenSSL::SSL in non-main Ractors:

    * `OpenSSL::SSL::SSLContext::DEFAULT_PARAMS` needs to be frozen. Although it wasn't the intended usage scenario, it lacked the `:nodoc:` tag until some time, so we would have to consider this as a breaking change.
    

    #925 makes these two changes.

    * `OpenSSL::SSL::Buffering` methods use `$/` that is global and not accessible from non-main Ractors. What is the alternative? Related to https://bugs.ruby-lang.org/issues/21109: core methods implemented in Ruby are facing the same issue as ruby/openssl is; core methods implemented in C currently access `rb_rs` from non-main Ractors, which is unsafe because `$/` can be a mutable String object.
    

    This is fixed in ruby/ruby's master branch. This is probably not backportable, so you will need the next Ruby release (3.5?).

    * The default tmp_dh_callback proc is unshareable.
    

    #924 replaces it with SSL_CTX_set_dh_auto().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions