summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--ext/openssl/ossl_ssl.c1
-rw-r--r--test/openssl/test_ssl.rb33
3 files changed, 44 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 8ea533ba54..acf8de672e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Sun Jul 26 10:26:35 2015 Aaron Patterson <tenderlove@ruby-lang.org>
+
+ * ext/openssl/ossl_ssl.c (ossl_call_servername_cb): set the ssl context
+ object returned by the servername callback on to the socket as an
+ instance variable. If the callback allocated a new context object
+ and didn't keep a reference to it, it could be GC'd out from under
+ the socket object.
+
+ * test/openssl/test_ssl.rb (class OpenSSL): test for change.
+
Sun Jul 26 10:07:26 2015 Aaron Patterson <tenderlove@ruby-lang.org>
* test/openssl/test_ssl.rb (class OpenSSL): add test coverage around
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index ca5f43cf0e..60ed9e033e 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -515,6 +515,7 @@ ossl_call_servername_cb(VALUE ary)
GetSSL(ssl_obj, ssl);
GetSSLCTX(ret_obj, ctx2);
SSL_set_SSL_CTX(ssl, ctx2);
+ rb_iv_set(ssl_obj, "@context", ret_obj);
} else if (!NIL_P(ret_obj)) {
ossl_raise(rb_eArgError, "servername_cb must return an OpenSSL::SSL::SSLContext object or nil");
}
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index 58ab76f412..d714b4010f 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -607,6 +607,39 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
cert
end
+ def test_servername_cb_sets_context_on_the_socket
+ hostname = 'example.org'
+
+ ctx3 = OpenSSL::SSL::SSLContext.new
+ ctx3.ciphers = "DH"
+
+ ctx2 = OpenSSL::SSL::SSLContext.new
+ ctx2.ciphers = "DH"
+ ctx2.servername_cb = lambda { |args| ctx3 }
+
+ sock1, sock2 = UNIXSocket.pair
+
+ s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)
+
+ ctx1 = OpenSSL::SSL::SSLContext.new
+ ctx1.ciphers = "DH"
+
+ s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
+ s1.hostname = hostname
+ t = Thread.new { s1.connect }
+
+ assert_equal ctx2, s2.context
+ accepted = s2.accept
+ assert_equal ctx3, s2.context
+ assert t.value
+ ensure
+ s1.close if s1
+ s2.close if s2
+ sock1.close if sock1
+ sock2.close if sock2
+ accepted.close if accepted.respond_to?(:close)
+ end
+
def test_servername_cb_raises_an_exception_on_unknown_objects
hostname = 'example.org'