[ruby/openssl] ssl: fix potential exception in servername_cb
ssl_servername_cb() is a callback function called from OpenSSL and Ruby exceptions must not be raised from it. Allocate the Array within rb_protect(). https://github.com/ruby/openssl/commit/3a2bf74d35
This commit is contained in:
parent
8ad6860ff7
commit
19acb3af2e
@ -557,52 +557,42 @@ ossl_sslctx_add_extra_chain_cert_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))
|
|||||||
static VALUE ossl_sslctx_setup(VALUE self);
|
static VALUE ossl_sslctx_setup(VALUE self);
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
ossl_call_servername_cb(VALUE ary)
|
ossl_call_servername_cb(VALUE arg)
|
||||||
{
|
{
|
||||||
VALUE ssl_obj, sslctx_obj, cb, ret_obj;
|
SSL *ssl = (void *)arg;
|
||||||
|
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||||
|
if (!servername)
|
||||||
|
return Qnil;
|
||||||
|
|
||||||
Check_Type(ary, T_ARRAY);
|
VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
|
||||||
ssl_obj = rb_ary_entry(ary, 0);
|
VALUE sslctx_obj = rb_attr_get(ssl_obj, id_i_context);
|
||||||
|
VALUE cb = rb_attr_get(sslctx_obj, id_i_servername_cb);
|
||||||
|
VALUE ary = rb_assoc_new(ssl_obj, rb_str_new_cstr(servername));
|
||||||
|
|
||||||
sslctx_obj = rb_attr_get(ssl_obj, id_i_context);
|
VALUE ret_obj = rb_funcallv(cb, id_call, 1, &ary);
|
||||||
cb = rb_attr_get(sslctx_obj, id_i_servername_cb);
|
|
||||||
if (NIL_P(cb)) return Qnil;
|
|
||||||
|
|
||||||
ret_obj = rb_funcallv(cb, id_call, 1, &ary);
|
|
||||||
if (rb_obj_is_kind_of(ret_obj, cSSLContext)) {
|
if (rb_obj_is_kind_of(ret_obj, cSSLContext)) {
|
||||||
SSL *ssl;
|
|
||||||
SSL_CTX *ctx2;
|
SSL_CTX *ctx2;
|
||||||
|
|
||||||
ossl_sslctx_setup(ret_obj);
|
ossl_sslctx_setup(ret_obj);
|
||||||
GetSSL(ssl_obj, ssl);
|
|
||||||
GetSSLCTX(ret_obj, ctx2);
|
GetSSLCTX(ret_obj, ctx2);
|
||||||
SSL_set_SSL_CTX(ssl, ctx2);
|
if (!SSL_set_SSL_CTX(ssl, ctx2))
|
||||||
|
ossl_raise(eSSLError, "SSL_set_SSL_CTX");
|
||||||
rb_ivar_set(ssl_obj, id_i_context, ret_obj);
|
rb_ivar_set(ssl_obj, id_i_context, ret_obj);
|
||||||
} else if (!NIL_P(ret_obj)) {
|
} else if (!NIL_P(ret_obj)) {
|
||||||
ossl_raise(rb_eArgError, "servername_cb must return an "
|
ossl_raise(rb_eArgError, "servername_cb must return an "
|
||||||
"OpenSSL::SSL::SSLContext object or nil");
|
"OpenSSL::SSL::SSLContext object or nil");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret_obj;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ssl_servername_cb(SSL *ssl, int *ad, void *arg)
|
ssl_servername_cb(SSL *ssl, int *ad, void *arg)
|
||||||
{
|
{
|
||||||
VALUE ary, ssl_obj;
|
int state;
|
||||||
int state = 0;
|
|
||||||
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
|
||||||
|
|
||||||
if (!servername)
|
rb_protect(ossl_call_servername_cb, (VALUE)ssl, &state);
|
||||||
return SSL_TLSEXT_ERR_OK;
|
|
||||||
|
|
||||||
ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
|
|
||||||
ary = rb_ary_new2(2);
|
|
||||||
rb_ary_push(ary, ssl_obj);
|
|
||||||
rb_ary_push(ary, rb_str_new2(servername));
|
|
||||||
|
|
||||||
rb_protect(ossl_call_servername_cb, ary, &state);
|
|
||||||
if (state) {
|
if (state) {
|
||||||
|
VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
|
||||||
rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
|
rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
|
||||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user