[前][次][番号順一覧][スレッド一覧]

ruby-changes:43117

From: rhe <ko1@a...>
Date: Sat, 28 May 2016 14:00:41 +0900 (JST)
Subject: [ruby-changes:43117] rhe:r55191 (trunk): openssl: move SSLSocket#initialize to C extension

rhe	2016-05-28 14:00:36 +0900 (Sat, 28 May 2016)

  New Revision: 55191

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=55191

  Log:
    openssl: move SSLSocket#initialize to C extension
    
    * ext/openssl/lib/openssl/ssl.rb (SSLSocket): Move the implementation of
      SSLSocket#initialize to C. Initialize the SSL (OpenSSL object) in it.
      Currently this is delayed until ossl_ssl_setup(), which is called from
      SSLSocket#accept or #connect. Say we call SSLSocket#hostname= with an
      illegal value. We expect an exception to be raised in #hostname= but
      actually we get it in the later SSLSocket#connect. Because the SSL is
      not ready at #hostname=, the actual call of SSL_set_tlsext_host_name()
      is also delayed.
      This also fixes: [ruby-dev:49376] [Bug #11724]
    
    * ext/openssl/ossl_ssl.c (ossl_ssl_initialize): Added. Almost the same
      as the Ruby version but this instantiate the SSL object at the same
      time.
    
      (ossl_ssl_setup): Adjust to the changes. Just set the underlying IO to
      the SSL.
    
      (ssl_started): Added. Make use of SSL_get_fd(). This returns -1 if not
      yet set by SSL_set_fd().
    
      (ossl_ssl_data_get_struct): Removed. Now GetSSL() checks that the SSL
      exists.
    
      (ossl_ssl_set_session): Don't call ossl_ssl_setup() here as now the
      SSL is already instantiated in #initialize.
    
      (ossl_ssl_shutdown, ossl_start_ssl, ossl_ssl_read_internal,
       ossl_ssl_write_internal, ossl_ssl_stop, ossl_ssl_get_cert,
       ossl_ssl_get_peer_cert, ossl_ssl_get_peer_cert_chain,
       ossl_ssl_get_version, ossl_ssl_get_cipher, ossl_ssl_get_state,
       ossl_ssl_pending, ossl_ssl_session_reused,
       ossl_ssl_get_verify_result, ossl_ssl_get_client_ca_list,
       ossl_ssl_npn_protocol, ossl_ssl_alpn_protocol, ossl_ssl_tmp_key): Use
      GetSSL() instead of ossl_ssl_data_get_struct(). Use ssl_started().
    
      (Init_ossl_ssl): Add method declarations of SSLSocket#{initialize,
      hostname=}.
    
    * ext/openssl/ossl_ssl.h (GetSSL): Check that the SSL is not NULL. It
      should not be NULL because we now set it in #initialize.
    
    * ext/openssl/ossl_ssl_session.c (ossl_ssl_session_initialize): No need
      to check if the SSL is NULL.

  Modified files:
    trunk/ChangeLog
    trunk/ext/openssl/lib/openssl/ssl.rb
    trunk/ext/openssl/ossl_ssl.c
    trunk/ext/openssl/ossl_ssl.h
    trunk/ext/openssl/ossl_ssl_session.c
Index: ext/openssl/ossl_ssl.h
===================================================================
--- ext/openssl/ossl_ssl.h	(revision 55190)
+++ ext/openssl/ossl_ssl.h	(revision 55191)
@@ -12,6 +12,9 @@ https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.h#L12
 
 #define GetSSL(obj, ssl) do { \
 	TypedData_Get_Struct((obj), SSL, &ossl_ssl_type, (ssl)); \
+	if (!(ssl)) { \
+		ossl_raise(rb_eRuntimeError, "SSL is not initialized"); \
+	} \
 } while (0)
 
 #define GetSSLSession(obj, sess) do { \
Index: ext/openssl/lib/openssl/ssl.rb
===================================================================
--- ext/openssl/lib/openssl/ssl.rb	(revision 55190)
+++ ext/openssl/lib/openssl/ssl.rb	(revision 55191)
@@ -247,43 +247,14 @@ module OpenSSL https://github.com/ruby/ruby/blob/trunk/ext/openssl/lib/openssl/ssl.rb#L247
       include Buffering
       include SocketForwarder
 
-      if ExtConfig::OPENSSL_NO_SOCK
-        def initialize(io, ctx = nil); raise NotImplementedError; end
-      else
-        if ExtConfig::HAVE_TLSEXT_HOST_NAME
-          attr_accessor :hostname
-        end
-
-        attr_reader :io, :context
-        attr_accessor :sync_close
-        alias :to_io :io
-
-        # call-seq:
-        #    SSLSocket.new(io) => aSSLSocket
-        #    SSLSocket.new(io, ctx) => aSSLSocket
-        #
-        # Creates a new SSL socket from +io+ which must be a real ruby object (not an
-        # IO-like object that responds to read/write).
-        #
-        # If +ctx+ is provided the SSL Sockets initial params will be taken from
-        # the context.
-        #
-        # The OpenSSL::Buffering module provides additional IO methods.
-        #
-        # This method will freeze the SSLContext if one is provided;
-        # however, session management is still allowed in the frozen SSLContext.
-
-        def initialize(io, context = OpenSSL::SSL::SSLContext.new)
-          @io         = io
-          @context    = context
-          @sync_close = false
-          @hostname   = nil
-          @io.nonblock = true if @io.respond_to?(:nonblock=)
-          context.setup
-          super()
-        end
+      if ExtConfig::HAVE_TLSEXT_HOST_NAME
+        attr_reader :hostname
       end
 
+      attr_reader :io, :context
+      attr_accessor :sync_close
+      alias :to_io :io
+
       # call-seq:
       #    ssl.sysclose => nil
       #
Index: ext/openssl/ossl_ssl_session.c
===================================================================
--- ext/openssl/ossl_ssl_session.c	(revision 55190)
+++ ext/openssl/ossl_ssl_session.c	(revision 55191)
@@ -46,7 +46,7 @@ static VALUE ossl_ssl_session_initialize https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl_session.c#L46
 
 		GetSSL(arg1, ssl);
 
-		if (!ssl || (ctx = SSL_get1_session(ssl)) == NULL)
+		if ((ctx = SSL_get1_session(ssl)) == NULL)
 			ossl_raise(eSSLSession, "no session available");
 	} else {
 		BIO *in = ossl_obj2bio(arg1);
Index: ext/openssl/ossl_ssl.c
===================================================================
--- ext/openssl/ossl_ssl.c	(revision 55190)
+++ ext/openssl/ossl_ssl.c	(revision 55191)
@@ -70,6 +70,10 @@ static VALUE eSSLErrorWaitWritable; https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L70
 #define ossl_ssl_get_x509(o)         rb_iv_get((o),"@x509")
 #define ossl_ssl_get_key(o)          rb_iv_get((o),"@key")
 
+#define ossl_ssl_set_io(o,v)         rb_iv_set((o),"@io",(v))
+#define ossl_ssl_set_ctx(o,v)        rb_iv_set((o),"@context",(v))
+#define ossl_ssl_set_sync_close(o,v) rb_iv_set((o),"@sync_close",(v))
+#define ossl_ssl_set_hostname_v(o,v) rb_iv_set((o),"@hostname",(v))
 #define ossl_ssl_set_x509(o,v)       rb_iv_set((o),"@x509",(v))
 #define ossl_ssl_set_key(o,v)        rb_iv_set((o),"@key",(v))
 #define ossl_ssl_set_tmp_dh(o,v)     rb_iv_set((o),"@tmp_dh",(v))
@@ -1139,25 +1143,29 @@ ossl_sslctx_flush_sessions(int argc, VAL https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1143
  * SSLSocket class
  */
 #ifndef OPENSSL_NO_SOCK
+static inline int
+ssl_started(SSL *ssl)
+{
+    /* the FD is set in ossl_ssl_setup(), called by #connect or #accept */
+    return SSL_get_fd(ssl) >= 0;
+}
+
 static void
 ossl_ssl_shutdown(SSL *ssl)
 {
-    int i, rc;
+    int i;
 
-    if (ssl) {
-	/* 4 is from SSL_smart_shutdown() of mod_ssl.c (v2.2.19) */
-	/* It says max 2x pending + 2x data = 4 */
-	for (i = 0; i < 4; ++i) {
-	    /*
-	     * Ignore the case SSL_shutdown returns -1. Empty handshake_func
-	     * must not happen.
-	     */
-	    if ((rc = SSL_shutdown(ssl)) != 0)
-		break;
-	}
-	SSL_clear(ssl);
-	ossl_clear_error();
+    /* 4 is from SSL_smart_shutdown() of mod_ssl.c (v2.2.19) */
+    /* It says max 2x pending + 2x data = 4 */
+    for (i = 0; i < 4; ++i) {
+	/*
+	 * Ignore the case SSL_shutdown returns -1. Empty handshake_func
+	 * must not happen.
+	 */
+	if (SSL_shutdown(ssl) != 0)
+	    break;
     }
+    ossl_clear_error();
 }
 
 static void
@@ -1180,45 +1188,77 @@ ossl_ssl_s_alloc(VALUE klass) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1188
     return TypedData_Wrap_Struct(klass, &ossl_ssl_type, NULL);
 }
 
+/*
+ * call-seq:
+ *    SSLSocket.new(io) => aSSLSocket
+ *    SSLSocket.new(io, ctx) => aSSLSocket
+ *
+ * Creates a new SSL socket from +io+ which must be a real ruby object (not an
+ * IO-like object that responds to read/write).
+ *
+ * If +ctx+ is provided the SSL Sockets initial params will be taken from
+ * the context.
+ *
+ * The OpenSSL::Buffering module provides additional IO methods.
+ *
+ * This method will freeze the SSLContext if one is provided;
+ * however, session management is still allowed in the frozen SSLContext.
+ */
 static VALUE
-ossl_ssl_setup(VALUE self)
+ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
 {
-    VALUE io, v_ctx, cb;
+    VALUE io, v_ctx, verify_cb;
+    SSL *ssl;
     SSL_CTX *ctx;
+
+    TypedData_Get_Struct(self, SSL, &ossl_ssl_type, ssl);
+    if (ssl)
+	ossl_raise(eSSLError, "SSL already initialized");
+
+    if (rb_scan_args(argc, argv, "11", &io, &v_ctx) == 1)
+	v_ctx = rb_funcall(cSSLContext, rb_intern("new"), 0);
+
+    GetSSLCTX(v_ctx, ctx);
+    ossl_ssl_set_ctx(self, v_ctx);
+    ossl_sslctx_setup(v_ctx);
+
+    if (rb_respond_to(io, rb_intern("nonblock=")))
+	rb_funcall(io, rb_intern("nonblock="), 1, Qtrue);
+    ossl_ssl_set_io(self, io);
+
+    ossl_ssl_set_sync_close(self, Qfalse);
+
+    ssl = SSL_new(ctx);
+    if (!ssl)
+	ossl_raise(eSSLError, NULL);
+    RTYPEDDATA_DATA(self) = ssl;
+
+    SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void *)self);
+    SSL_set_info_callback(ssl, ssl_info_cb);
+    verify_cb = ossl_sslctx_get_verify_cb(v_ctx);
+    SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)verify_cb);
+
+    rb_call_super(0, NULL);
+
+    return self;
+}
+
+static VALUE
+ossl_ssl_setup(VALUE self)
+{
+    VALUE io;
     SSL *ssl;
     rb_io_t *fptr;
 
     GetSSL(self, ssl);
-    if(!ssl){
-#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
-	VALUE hostname = rb_iv_get(self, "@hostname");
-#endif
-
-        v_ctx = ossl_ssl_get_ctx(self);
-        GetSSLCTX(v_ctx, ctx);
+    if (ssl_started(ssl))
+	return Qtrue;
 
-        ssl = SSL_new(ctx);
-        if (!ssl) {
-            ossl_raise(eSSLError, "SSL_new");
-        }
-        DATA_PTR(self) = ssl;
-
-#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
-        if (!NIL_P(hostname)) {
-           if (SSL_set_tlsext_host_name(ssl, StringValueCStr(hostname)) != 1)
-               ossl_raise(eSSLError, "SSL_set_tlsext_host_name");
-        }
-#endif
-        io = ossl_ssl_get_io(self);
-        GetOpenFile(io, fptr);
-        rb_io_check_readable(fptr);
-        rb_io_check_writable(fptr);
-        SSL_set_fd(ssl, TO_SOCKET(FPTR_TO_FD(fptr)));
-	SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void*)self);
-	cb = ossl_sslctx_get_verify_cb(v_ctx);
-	SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void*)cb);
-	SSL_set_info_callback(ssl, ssl_info_cb);
-    }
+    io = ossl_ssl_get_io(self);
+    GetOpenFile(io, fptr);
+    rb_io_check_readable(fptr);
+    rb_io_check_writable(fptr);
+    SSL_set_fd(ssl, TO_SOCKET(FPTR_TO_FD(fptr)));
 
     return Qtrue;
 }
@@ -1229,15 +1269,6 @@ ossl_ssl_setup(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1269
 #define ssl_get_error(ssl, ret) SSL_get_error((ssl), (ret))
 #endif
 
-#define ossl_ssl_data_get_struct(v, ssl)		\
-do {							\
-    GetSSL((v), (ssl)); 				\
-    if (!(ssl)) {					\
-        rb_warning("SSL session is not started yet.");  \
-        return Qnil;					\
-    }							\
-} while (0)
-
 static void
 write_would_block(int nonblock)
 {
@@ -1276,7 +1307,7 @@ ossl_start_ssl(VALUE self, int (*func)() https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1307
 
     rb_ivar_set(self, ID_callback_state, Qnil);
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     GetOpenFile(ossl_ssl_get_io(self), fptr);
     for(;;){
@@ -1436,7 +1467,7 @@ ossl_ssl_read_internal(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1467
 
     GetSSL(self, ssl);
     GetOpenFile(ossl_ssl_get_io(self), fptr);
-    if (ssl) {
+    if (ssl_started(ssl)) {
 	if(!nonblock && SSL_pending(ssl) <= 0)
 	    rb_thread_wait_fd(FPTR_TO_FD(fptr));
 	for (;;){
@@ -1530,7 +1561,7 @@ ossl_ssl_write_internal(VALUE self, VALU https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1561
     GetSSL(self, ssl);
     GetOpenFile(ossl_ssl_get_io(self), fptr);
 
-    if (ssl) {
+    if (ssl_started(ssl)) {
 	for (;;){
 	    nwrite = SSL_write(ssl, RSTRING_PTR(str), RSTRING_LENINT(str));
 	    switch(ssl_get_error(ssl, nwrite)){
@@ -1604,7 +1635,7 @@ ossl_ssl_stop(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1635
 {
     SSL *ssl;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     ossl_ssl_shutdown(ssl);
 
@@ -1623,7 +1654,7 @@ ossl_ssl_get_cert(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1654
     SSL *ssl;
     X509 *cert = NULL;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     /*
      * Is this OpenSSL bug? Should add a ref?
@@ -1650,7 +1681,7 @@ ossl_ssl_get_peer_cert(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1681
     X509 *cert = NULL;
     VALUE obj;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     cert = SSL_get_peer_certificate(ssl); /* Adds a ref => Safe to FREE. */
 
@@ -1678,7 +1709,7 @@ ossl_ssl_get_peer_cert_chain(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1709
     VALUE ary;
     int i, num;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     chain = SSL_get_peer_cert_chain(ssl);
     if(!chain) return Qnil;
@@ -1704,7 +1735,7 @@ ossl_ssl_get_version(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1735
 {
     SSL *ssl;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     return rb_str_new2(SSL_get_version(ssl));
 }
@@ -1721,7 +1752,7 @@ ossl_ssl_get_cipher(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1752
     SSL *ssl;
     SSL_CIPHER *cipher;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     cipher = (SSL_CIPHER *)SSL_get_current_cipher(ssl);
 
@@ -1740,7 +1771,7 @@ ossl_ssl_get_state(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1771
     SSL *ssl;
     VALUE ret;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     ret = rb_str_new2(SSL_state_string(ssl));
     if (ruby_verbose) {
@@ -1761,7 +1792,7 @@ ossl_ssl_pending(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1792
 {
     SSL *ssl;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     return INT2NUM(SSL_pending(ssl));
 }
@@ -1777,15 +1808,9 @@ ossl_ssl_session_reused(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1808
 {
     SSL *ssl;
 
-    ossl_ssl_data_get_struct(self, ssl);
-
-    switch(SSL_session_reused(ssl)) {
-    case 1:	return Qtrue;
-    case 0:	return Qfalse;
-    default:	ossl_raise(eSSLError, "SSL_session_reused");
-    }
+    GetSSL(self, ssl);
 
-    UNREACHABLE;
+    return SSL_session_reused(ssl) ? Qtrue : Qfalse;
 }
 
 /*
@@ -1800,11 +1825,7 @@ ossl_ssl_set_session(VALUE self, VALUE a https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1825
     SSL *ssl;
     SSL_SESSION *sess;
 
-/* why is ossl_ssl_setup delayed? */
-    ossl_ssl_setup(self);
-
-    ossl_ssl_data_get_struct(self, ssl);
-
+    GetSSL(self, ssl);
     SafeGetSSLSession(arg1, sess);
 
     if (SSL_set_session(ssl, sess) != 1)
@@ -1815,6 +1836,35 @@ ossl_ssl_set_session(VALUE self, VALUE a https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1836
 
 /*
  * call-seq:
+ *    ssl.hostname = hostname -> hostname
+ *
+ * Sets the server hostname used for SNI. This needs to be set before
+ * SSLSocket#connect.
+ */
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+static VALUE
+ossl_ssl_set_hostname(VALUE self, VALUE arg)
+{
+    SSL *ssl;
+    char *hostname = NULL;
+
+    GetSSL(self, ssl);
+
+    if (!NIL_P(arg))
+	hostname = StringValueCStr(arg);
+
+    if (!SSL_set_tlsext_host_name(ssl, hostname))
+	ossl_raise(eSSLError, NULL);
+
+    /* for SSLSocket#hostname */
+    ossl_ssl_set_hostname_v(self, arg);
+
+    return arg;
+}
+#endif
+
+/*
+ * call-seq:
  *    ssl.verify_result => Integer
  *
  * Returns the result of the peer certificates verification.  See verify(1)
@@ -1827,7 +1877,7 @@ ossl_ssl_get_verify_result(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1877
 {
     SSL *ssl;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     return INT2FIX(SSL_get_verify_result(ssl));
 }
@@ -1849,7 +1899,7 @@ ossl_ssl_get_client_ca_list(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1899
     SSL *ssl;
     STACK_OF(X509_NAME) *ca;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     ca = SSL_get_client_CA_list(ssl);
     return ossl_x509name_sk2ary(ca);
@@ -1870,7 +1920,7 @@ ossl_ssl_npn_protocol(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1920
     const unsigned char *out;
     unsigned int outlen;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     SSL_get0_next_proto_negotiated(ssl, &out, &outlen);
     if (!outlen)
@@ -1895,7 +1945,7 @@ ossl_ssl_alpn_protocol(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1945
     const unsigned char *out;
     unsigned int outlen;
 
-    ossl_ssl_data_get_struct(self, ssl);
+    GetSSL(self, ssl);
 
     SSL_get0_alpn_selected(ssl, &out, &outlen);
     if (!outlen)
@@ -1915,12 +1965,13 @@ ossl_ssl_alpn_protocol(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1965
 static VALUE
 ossl_ssl_tmp_key(VALUE self)
 {
-   SSL *ssl;
-   EVP_PKEY *key;
-   ossl_ssl_data_get_struct(self, ssl);
-   if (!SSL_get_server_tmp_key(ssl, &key))
-       return Qnil;
-   return ossl_pkey_new(key);
+    SSL *ssl;
+    EVP_PKEY *key;
+
+    GetSSL(self, ssl);
+    if (!SSL_get_server_tmp_key(ssl, &key))
+	return Qnil;
+    return ossl_pkey_new(key);
 }
 # endif /* defined(HAVE_SSL_GET_SERVER_TMP_KEY) */
 #endif /* !defined(OPENSSL_NO_SOCK) */
@@ -2293,9 +2344,11 @@ Init_ossl_ssl(void) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L2344
     cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject);
 #ifdef OPENSSL_NO_SOCK
     rb_define_const(mSSLExtConfig, "OPENSSL_NO_SOCK", Qtrue);
+    rb_define_method(cSSLSocket, "initialize", rb_f_notimplement, -1);
 #else
     rb_define_const(mSSLExtConfig, "OPENSSL_NO_SOCK", Qfalse);
     rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc);
+    rb_define_method(cSSLSocket, "initialize", ossl_ssl_initialize, -1);
     rb_define_method(cSSLSocket, "connect",    ossl_ssl_connect, 0);
     rb_define_method(cSSLSocket, "connect_nonblock",    ossl_ssl_connect_nonblock, -1);
     rb_define_method(cSSLSocket, "accept",     ossl_ssl_accept, 0);
@@ -2317,6 +2370,10 @@ Init_ossl_ssl(void) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L2370
     rb_define_method(cSSLSocket, "session=",    ossl_ssl_set_session, 1);
     rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0);
     rb_define_method(cSSLSocket, "client_ca", ossl_ssl_get_client_ca_list, 0);
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+    /* #hostname is defined in lib/openssl/ssl.rb */
+    rb_define_method(cSSLSocket, "hostname=", ossl_ssl_set_hostname, 1);
+#endif
 # ifdef HAVE_SSL_GET_SERVER_TMP_KEY
     rb_define_method(cSSLSocket, "tmp_key", ossl_ssl_tmp_key, 0);
 # endif
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 55190)
+++ ChangeLog	(revision 55191)
@@ -1,3 +1,49 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sat May 28 14:00:10 2016  Kazuki Yamaguchi  <k@r...>
+
+	* ext/openssl/lib/openssl/ssl.rb (SSLSocket): Move the implementation of
+	  SSLSocket#initialize to C. Initialize the SSL (OpenSSL object) in it.
+	  Currently this is delayed until ossl_ssl_setup(), which is called from
+	  SSLSocket#accept or #connect. Say we call SSLSocket#hostname= with an
+	  illegal value. We expect an exception to be raised in #hostname= but
+	  actually we get it in the later SSLSocket#connect. Because the SSL is
+	  not ready at #hostname=, the actual call of SSL_set_tlsext_host_name()
+	  is also delayed.
+	  This also fixes: [ruby-dev:49376] [Bug #11724]
+
+	* ext/openssl/ossl_ssl.c (ossl_ssl_initialize): Added. Almost the same
+	  as the Ruby version but this instantiate the SSL object at the same
+	  time.
+
+	  (ossl_ssl_setup): Adjust to the changes. Just set the underlying IO to
+	  the SSL.
+
+	  (ssl_started): Added. Make use of SSL_get_fd(). This returns -1 if not
+	  yet set by SSL_set_fd().
+
+	  (ossl_ssl_data_get_struct): Removed. Now GetSSL() checks that the SSL
+	  exists.
+
+	  (ossl_ssl_set_session): Don't call ossl_ssl_setup() here as now the
+	  SSL is already instantiated in #initialize.
+
+	  (ossl_ssl_shutdown, ossl_start_ssl, ossl_ssl_read_internal,
+	   ossl_ssl_write_internal, ossl_ssl_stop, ossl_ssl_get_cert,
+	   ossl_ssl_get_peer_cert, ossl_ssl_get_peer_cert_chain,
+	   ossl_ssl_get_version, ossl_ssl_get_cipher, ossl_ssl_get_state,
+	   ossl_ssl_pending, ossl_ssl_session_reused,
+	   ossl_ssl_get_verify_result, ossl_ssl_get_client_ca_list,
+	   ossl_ssl_npn_protocol, ossl_ssl_alpn_protocol, ossl_ssl_tmp_key): Use
+	  GetSSL() instead of ossl_ssl_data_get_struct(). Use ssl_started().
+
+	  (Init_ossl_ssl): Add method declarations of SSLSocket#{initialize,
+	  hostname=}.
+
+	* ext/openssl/ossl_ssl.h (GetSSL): Check that the SSL is not NULL. It
+	  should not be NULL because we now set it in #initialize.
+
+	* ext/openssl/ossl_ssl_session.c (ossl_ssl_session_initialize): No need
+	  to check if the SSL is NULL.
+
 Sat May 28 10:47:40 2016  SHIBATA Hiroshi  <hsbt@r...>
 
 	* gems/bundled_gems: Update latest releases, power_assert-0.3.0,

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]