From 801c7dfa503f0d0db8af675811224d0ebd106988 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Thu, 6 Aug 2026 04:26:39 +0900 Subject: [PATCH] ssl: keep original SSLContext alive after servername_cb Keep the original SSLContext in a separate instance variable to prevent it from being GC'ed. When the SNI callback accepts the provided server name, it may replace the SSL_CTX with SSL_set_SSL_CTX() and update SSLSocket#context. However, despite its name, SSL_set_SSL_CTX() does not use all parameters from the new SSL_CTX. In particular, callbacks set by the original SSL_CTX remain in use and therefore require the corresponding SSLContext object to stay alive. --- ext/openssl/ossl_ssl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index fcbbec0b3..63bd8ab43 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -36,7 +36,8 @@ VALUE cSSLSocket; static VALUE eSSLErrorWaitReadable; static VALUE eSSLErrorWaitWritable; -static ID id_call, ID_callback_state, id_npn_protocols_encoded, id_each; +static ID id_call, ID_callback_state, id_npn_protocols_encoded, id_each, + id_original_context; static VALUE sym_exception, sym_wait_readable, sym_wait_writable; static ID id_i_cert_store, id_i_ca_file, id_i_ca_path, id_i_verify_mode, @@ -1694,6 +1695,7 @@ ossl_ssl_initialize(int argc, VALUE *argv, VALUE self) GetSSLCTX(v_ctx, ctx); rb_ivar_set(self, id_i_context, v_ctx); + rb_ivar_set(self, id_original_context, v_ctx); ossl_sslctx_setup(v_ctx); if (rb_respond_to(io, rb_intern("nonblock="))) @@ -3359,6 +3361,7 @@ Init_ossl_ssl(void) id_npn_protocols_encoded = rb_intern_const("npn_protocols_encoded"); id_each = rb_intern_const("each"); + id_original_context = rb_intern_const("original_context"); #define DefIVarID(name) do \ id_i_##name = rb_intern_const("@"#name); while (0)