2013-09-26 17:14:40 +02:00

443 lines
13 KiB
Plaintext

$NetBSD: patch-dq,v 1.2 2010/09/10 03:29:00 taca Exp $
* r18172: suppress warnings.
* r20494: (ossl_ssl_read_nonblock): OpenSSL::SSL::SSLSocket should implement
read_nonblock. a patch from Aaron Patterson in [ruby-core:20277].
fix: #814 [ruby-core:20241]
* r21772: Test for Server Name Indication support.
* r23008: revert incomplete read_nonblock implemenatation.
* r26835: backport fixes in 1.9.
* r26838: backport the commit from trunk.
* Constify (some cases are depends on OpenSSL's version).
--- ext/openssl/ossl_ssl.c.orig 2010-06-21 09:18:59.000000000 +0000
+++ ext/openssl/ossl_ssl.c
@@ -26,6 +26,12 @@
# define TO_SOCKET(s) s
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+#define OSSL_CONST const
+#else
+#define OSSL_CONST
+#endif
+
VALUE mSSL;
VALUE eSSLError;
VALUE cSSLContext;
@@ -69,6 +75,9 @@ static const char *ossl_sslctx_attrs[] =
"verify_callback", "options", "cert_store", "extra_chain_cert",
"client_cert_cb", "tmp_dh_callback", "session_id_context",
"session_get_cb", "session_new_cb", "session_remove_cb",
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+ "servername_cb",
+#endif
};
#define ossl_ssl_get_io(o) rb_iv_get((o),"@io")
@@ -86,7 +95,12 @@ static const char *ossl_sslctx_attrs[] =
#define ossl_ssl_set_tmp_dh(o,v) rb_iv_set((o),"@tmp_dh",(v))
static const char *ossl_ssl_attr_readers[] = { "io", "context", };
-static const char *ossl_ssl_attrs[] = { "sync_close", };
+static const char *ossl_ssl_attrs[] = {
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+ "hostname",
+#endif
+ "sync_close",
+};
ID ID_callback_state;
@@ -95,7 +109,7 @@ ID ID_callback_state;
*/
struct {
const char *name;
- SSL_METHOD *(*func)(void);
+ OSSL_CONST SSL_METHOD *(*func)(void);
} ossl_ssl_method_tab[] = {
#define OSSL_SSL_METHOD_ENTRY(name) { #name, name##_method }
OSSL_SSL_METHOD_ENTRY(TLSv1),
@@ -144,7 +158,7 @@ ossl_sslctx_s_alloc(VALUE klass)
static VALUE
ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method)
{
- SSL_METHOD *method = NULL;
+ OSSL_CONST SSL_METHOD *method = NULL;
const char *s;
int i;
@@ -297,7 +311,7 @@ ossl_ssl_verify_callback(int preverify_o
static VALUE
ossl_call_session_get_cb(VALUE ary)
{
- VALUE ssl_obj, sslctx_obj, cb, ret;
+ VALUE ssl_obj, sslctx_obj, cb;
Check_Type(ary, T_ARRAY);
ssl_obj = rb_ary_entry(ary, 0);
@@ -325,7 +339,7 @@ ossl_sslctx_session_get_cb(SSL *ssl, uns
ssl_obj = (VALUE)ptr;
ary = rb_ary_new2(2);
rb_ary_push(ary, ssl_obj);
- rb_ary_push(ary, rb_str_new(buf, len));
+ rb_ary_push(ary, rb_str_new((const char *)buf, len));
ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_get_cb, ary, &state);
if (state) {
@@ -344,7 +358,7 @@ ossl_sslctx_session_get_cb(SSL *ssl, uns
static VALUE
ossl_call_session_new_cb(VALUE ary)
{
- VALUE ssl_obj, sslctx_obj, cb, ret;
+ VALUE ssl_obj, sslctx_obj, cb;
Check_Type(ary, T_ARRAY);
ssl_obj = rb_ary_entry(ary, 0);
@@ -387,10 +401,11 @@ ossl_sslctx_session_new_cb(SSL *ssl, SSL
return RTEST(ret_obj) ? 1 : 0;
}
+#if 0 /* unused */
static VALUE
ossl_call_session_remove_cb(VALUE ary)
{
- VALUE sslctx_obj, cb, ret;
+ VALUE sslctx_obj, cb;
Check_Type(ary, T_ARRAY);
sslctx_obj = rb_ary_entry(ary, 0);
@@ -400,6 +415,7 @@ ossl_call_session_remove_cb(VALUE ary)
return rb_funcall(cb, rb_intern("call"), 1, ary);
}
+#endif
static void
ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
@@ -446,6 +462,66 @@ ossl_sslctx_add_extra_chain_cert_i(VALUE
return i;
}
+static VALUE ossl_sslctx_setup(VALUE self);
+
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+static VALUE
+ossl_call_servername_cb(VALUE ary)
+{
+ VALUE ssl_obj, sslctx_obj, cb, ret_obj;
+
+ Check_Type(ary, T_ARRAY);
+ ssl_obj = rb_ary_entry(ary, 0);
+
+ sslctx_obj = rb_iv_get(ssl_obj, "@context");
+ if (NIL_P(sslctx_obj)) return Qnil;
+ cb = rb_iv_get(sslctx_obj, "@servername_cb");
+ if (NIL_P(cb)) return Qnil;
+
+ ret_obj = rb_funcall(cb, rb_intern("call"), 1, ary);
+ if (rb_obj_is_kind_of(ret_obj, cSSLContext)) {
+ SSL *ssl;
+ SSL_CTX *ctx2;
+
+ ossl_sslctx_setup(ret_obj);
+ Data_Get_Struct(ssl_obj, SSL, ssl);
+ Data_Get_Struct(ret_obj, SSL_CTX, ctx2);
+ SSL_set_SSL_CTX(ssl, ctx2);
+ } else if (!NIL_P(ret_obj)) {
+ rb_raise(rb_eArgError, "servername_cb must return an OpenSSL::SSL::SSLContext object or nil");
+ }
+
+ return ret_obj;
+}
+
+static int
+ssl_servername_cb(SSL *ssl, int *ad, void *arg)
+{
+ VALUE ary, ssl_obj, ret_obj;
+ void *ptr;
+ int state = 0;
+ const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+
+ if (!servername)
+ return SSL_TLSEXT_ERR_OK;
+
+ if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL)
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ ssl_obj = (VALUE)ptr;
+ ary = rb_ary_new2(2);
+ rb_ary_push(ary, ssl_obj);
+ rb_ary_push(ary, rb_str_new2(servername));
+
+ ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_servername_cb, ary, &state);
+ if (state) {
+ rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
/*
* call-seq:
* ctx.setup => Qtrue # first time
@@ -563,7 +639,7 @@ ossl_sslctx_setup(VALUE self)
val = ossl_sslctx_get_sess_id_ctx(self);
if (!NIL_P(val)){
StringValue(val);
- if (!SSL_CTX_set_session_id_context(ctx, RSTRING_PTR(val),
+ if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
RSTRING_LEN(val))){
ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:");
}
@@ -581,11 +657,20 @@ ossl_sslctx_setup(VALUE self)
SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
OSSL_Debug("SSL SESSION remove callback added");
}
+
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+ val = rb_iv_get(self, "@servername_cb");
+ if (!NIL_P(val)) {
+ SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
+ OSSL_Debug("SSL TLSEXT servername callback added");
+ }
+#endif
+
return Qtrue;
}
static VALUE
-ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher)
+ossl_ssl_cipher_to_ary(OSSL_CONST SSL_CIPHER *cipher)
{
VALUE ary;
int bits, alg_bits;
@@ -609,7 +694,7 @@ ossl_sslctx_get_ciphers(VALUE self)
{
SSL_CTX *ctx;
STACK_OF(SSL_CIPHER) *ciphers;
- SSL_CIPHER *cipher;
+ OSSL_CONST SSL_CIPHER *cipher;
VALUE ary;
int i, num;
@@ -623,10 +708,10 @@ ossl_sslctx_get_ciphers(VALUE self)
if (!ciphers)
return rb_ary_new();
- num = sk_num((STACK*)ciphers);
+ num = sk_SSL_CIPHER_num(ciphers);
ary = rb_ary_new2(num);
for(i = 0; i < num; i++){
- cipher = (SSL_CIPHER*)sk_value((STACK*)ciphers, i);
+ cipher = sk_SSL_CIPHER_value(ciphers, i);
rb_ary_push(ary, ossl_ssl_cipher_to_ary(cipher));
}
return ary;
@@ -815,7 +900,6 @@ ossl_sslctx_flush_sessions(int argc, VAL
VALUE arg1;
SSL_CTX *ctx;
time_t tm = 0;
- int cb_state;
rb_scan_args(argc, argv, "01", &arg1);
@@ -889,6 +973,8 @@ ossl_ssl_initialize(int argc, VALUE *arg
ossl_sslctx_setup(ctx);
rb_call_super(0, 0);
+ rb_iv_set(self, "@hostname", Qnil);
+
return self;
}
@@ -902,6 +988,10 @@ ossl_ssl_setup(VALUE self)
Data_Get_Struct(self, SSL, 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);
Data_Get_Struct(v_ctx, SSL_CTX, ctx);
@@ -911,6 +1001,12 @@ ossl_ssl_setup(VALUE self)
}
DATA_PTR(self) = ssl;
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+ if (!NIL_P(hostname)) {
+ if (SSL_set_tlsext_host_name(ssl, StringValuePtr(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);
@@ -947,7 +1043,15 @@ ossl_start_ssl(VALUE self, int (*func)()
Data_Get_Struct(self, SSL, ssl);
GetOpenFile(ossl_ssl_get_io(self), fptr);
for(;;){
- if((ret = func(ssl)) > 0) break;
+ ret = func(ssl);
+
+ cb_state = rb_ivar_get(self, ID_callback_state);
+ if (!NIL_P(cb_state))
+ rb_jump_tag(NUM2INT(cb_state));
+
+ if (ret > 0)
+ break;
+
switch((ret2 = ssl_get_error(ssl, ret))){
case SSL_ERROR_WANT_WRITE:
rb_io_wait_writable(FPTR_TO_FD(fptr));
@@ -963,10 +1067,6 @@ ossl_start_ssl(VALUE self, int (*func)()
}
}
- cb_state = rb_ivar_get(self, ID_callback_state);
- if (!NIL_P(cb_state))
- rb_jump_tag(NUM2INT(cb_state));
-
return self;
}
@@ -1004,6 +1104,72 @@ ossl_ssl_accept(VALUE self)
static VALUE
ossl_ssl_read(int argc, VALUE *argv, VALUE self)
{
+ SSL *ssl;
+ int ilen, nread = 0;
+ VALUE len, str;
+ rb_io_t *fptr;
+
+ rb_scan_args(argc, argv, "11", &len, &str);
+ ilen = NUM2INT(len);
+ if(NIL_P(str)) str = rb_str_new(0, ilen);
+ else{
+ StringValue(str);
+ rb_str_modify(str);
+ rb_str_resize(str, ilen);
+ }
+ if(ilen == 0) return str;
+
+ Data_Get_Struct(self, SSL, ssl);
+ GetOpenFile(ossl_ssl_get_io(self), fptr);
+ if (ssl) {
+ if(SSL_pending(ssl) <= 0)
+ rb_thread_wait_fd(FPTR_TO_FD(fptr));
+ for (;;){
+ nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
+ switch(SSL_get_error(ssl, nread)){
+ case SSL_ERROR_NONE:
+ goto end;
+ case SSL_ERROR_ZERO_RETURN:
+ rb_eof_error();
+ case SSL_ERROR_WANT_WRITE:
+ rb_io_wait_writable(FPTR_TO_FD(fptr));
+ continue;
+ case SSL_ERROR_WANT_READ:
+ rb_io_wait_readable(FPTR_TO_FD(fptr));
+ continue;
+ case SSL_ERROR_SYSCALL:
+ if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
+ rb_sys_fail(0);
+ default:
+ ossl_raise(eSSLError, "SSL_read:");
+ }
+ }
+ }
+ else {
+ ID id_sysread = rb_intern("sysread");
+ rb_warning("SSL session is not started yet.");
+ return rb_funcall(ossl_ssl_get_io(self), id_sysread, 2, len, str);
+ }
+
+end:
+ rb_str_set_len(str, nread);
+ OBJ_TAINT(str);
+
+ return str;
+}
+
+/*
+ * call-seq:
+ * ssl.read_nonblock(length) => string
+ * ssl.read_nonblock(length, buffer) => buffer
+ *
+ * === Parameters
+ * * +length+ is a positive integer.
+ * * +buffer+ is a string used to store the result.
+ */
+static VALUE
+ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self)
+{
SSL *ssl;
int ilen, nread = 0;
VALUE len, str;
@@ -1021,12 +1187,11 @@ ossl_ssl_read(int argc, VALUE *argv, VAL
Data_Get_Struct(self, SSL, ssl);
GetOpenFile(ossl_ssl_get_io(self), fptr);
+ rb_io_set_nonblock(fptr);
if (ssl) {
- if(SSL_pending(ssl) <= 0)
- rb_thread_wait_fd(FPTR_TO_FD(fptr));
for (;;){
nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
- switch(ssl_get_error(ssl, nread)){
+ switch(SSL_get_error(ssl, nread)){
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_ZERO_RETURN:
@@ -1035,7 +1200,7 @@ ossl_ssl_read(int argc, VALUE *argv, VAL
rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
- rb_io_wait_readable(FPTR_TO_FD(fptr));
+ rb_sys_fail(fptr->path);
continue;
case SSL_ERROR_SYSCALL:
if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
@@ -1046,9 +1211,8 @@ ossl_ssl_read(int argc, VALUE *argv, VAL
}
}
else {
- ID id_sysread = rb_intern("sysread");
rb_warning("SSL session is not started yet.");
- return rb_funcall(ossl_ssl_get_io(self), id_sysread, 2, len, str);
+ return rb_funcall(ossl_ssl_get_io(self), rb_intern("sysread"), 2, len, str);
}
end:
@@ -1221,7 +1385,7 @@ ossl_ssl_get_cipher(VALUE self)
rb_warning("SSL session is not started yet.");
return Qnil;
}
- cipher = SSL_get_current_cipher(ssl);
+ cipher = (SSL_CIPHER *)SSL_get_current_cipher(ssl);
return ossl_ssl_cipher_to_ary(cipher);
}
@@ -1344,13 +1508,13 @@ Init_ossl_ssl()
ID_callback_state = rb_intern("@callback_state");
- ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_vcb_idx",0,0,0);
- ossl_ssl_ex_store_p = SSL_get_ex_new_index(0,"ossl_ssl_ex_store_p",0,0,0);
- ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_ptr_idx",0,0,0);
+ ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_vcb_idx",0,0,0);
+ ossl_ssl_ex_store_p = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_store_p",0,0,0);
+ ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_ptr_idx",0,0,0);
ossl_ssl_ex_client_cert_cb_idx =
- SSL_get_ex_new_index(0,"ossl_ssl_ex_client_cert_cb_idx",0,0,0);
+ SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_client_cert_cb_idx",0,0,0);
ossl_ssl_ex_tmp_dh_callback_idx =
- SSL_get_ex_new_index(0,"ossl_ssl_ex_tmp_dh_callback_idx",0,0,0);
+ SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_tmp_dh_callback_idx",0,0,0);
mSSL = rb_define_module_under(mOSSL, "SSL");
eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError);