mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[ruby/openssl] Add support to SSL_CTX_set_keylog_callback
- This callback is invoked when TLS key material is generated or
received, in order to allow applications to store this keying material
for debugging purposes.
- It is invoked with an `SSLSocket` and a string containing the key
material in the format used by NSS for its SSLKEYLOGFILE debugging
output.
- This commit adds the Ruby binding `keylog_cb` and the related tests
- It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements
`SSL_CTX_set_keylog_callback()` from v3.4.2, it does nothing (see
648d39f0f0
)
https://github.com/ruby/openssl/commit/3b63232cf1
This commit is contained in:
parent
e4b1627983
commit
17998ad3bb
2 changed files with 133 additions and 1 deletions
|
@ -49,7 +49,7 @@ static ID id_i_cert_store, id_i_ca_file, id_i_ca_path, id_i_verify_mode,
|
|||
id_i_session_id_context, id_i_session_get_cb, id_i_session_new_cb,
|
||||
id_i_session_remove_cb, id_i_npn_select_cb, id_i_npn_protocols,
|
||||
id_i_alpn_select_cb, id_i_alpn_protocols, id_i_servername_cb,
|
||||
id_i_verify_hostname;
|
||||
id_i_verify_hostname, id_i_keylog_cb;
|
||||
static ID id_i_io, id_i_context, id_i_hostname;
|
||||
|
||||
static int ossl_ssl_ex_vcb_idx;
|
||||
|
@ -441,6 +441,54 @@ ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
/*
|
||||
* It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements
|
||||
* SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see
|
||||
* https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6).
|
||||
*/
|
||||
|
||||
struct ossl_call_keylog_cb_args {
|
||||
VALUE ssl_obj;
|
||||
const char * line;
|
||||
};
|
||||
|
||||
static VALUE
|
||||
ossl_call_keylog_cb(VALUE args_v)
|
||||
{
|
||||
VALUE sslctx_obj, cb, line_v;
|
||||
struct ossl_call_keylog_cb_args *args = (struct ossl_call_keylog_cb_args *) args_v;
|
||||
|
||||
sslctx_obj = rb_attr_get(args->ssl_obj, id_i_context);
|
||||
|
||||
cb = rb_attr_get(sslctx_obj, id_i_keylog_cb);
|
||||
if (NIL_P(cb)) return Qnil;
|
||||
|
||||
line_v = rb_str_new_cstr(args->line);
|
||||
|
||||
return rb_funcall(cb, id_call, 2, args->ssl_obj, line_v);
|
||||
}
|
||||
|
||||
static void
|
||||
ossl_sslctx_keylog_cb(const SSL *ssl, const char *line)
|
||||
{
|
||||
VALUE ssl_obj;
|
||||
struct ossl_call_keylog_cb_args args;
|
||||
int state = 0;
|
||||
|
||||
OSSL_Debug("SSL keylog callback entered");
|
||||
|
||||
ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
|
||||
args.ssl_obj = ssl_obj;
|
||||
args.line = line;
|
||||
|
||||
rb_protect(ossl_call_keylog_cb, (VALUE)&args, &state);
|
||||
if (state) {
|
||||
rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static VALUE
|
||||
ossl_call_session_remove_cb(VALUE ary)
|
||||
{
|
||||
|
@ -911,6 +959,18 @@ ossl_sslctx_setup(VALUE self)
|
|||
OSSL_Debug("SSL TLSEXT servername callback added");
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
/*
|
||||
* It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements
|
||||
* SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see
|
||||
* https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6).
|
||||
*/
|
||||
if (RTEST(rb_attr_get(self, id_i_keylog_cb))) {
|
||||
SSL_CTX_set_keylog_callback(ctx, ossl_sslctx_keylog_cb);
|
||||
OSSL_Debug("SSL keylog callback added");
|
||||
}
|
||||
#endif
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
|
@ -2783,6 +2843,29 @@ Init_ossl_ssl(void)
|
|||
*/
|
||||
rb_attr(cSSLContext, rb_intern_const("alpn_select_cb"), 1, 1, Qfalse);
|
||||
|
||||
/*
|
||||
* A callback invoked when TLS key material is generated or received, in
|
||||
* order to allow applications to store this keying material for debugging
|
||||
* purposes.
|
||||
*
|
||||
* The callback is invoked with an SSLSocket and a string containing the
|
||||
* key material in the format used by NSS for its SSLKEYLOGFILE debugging
|
||||
* output.
|
||||
*
|
||||
* It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements
|
||||
* SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see
|
||||
* https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6).
|
||||
*
|
||||
* === Example
|
||||
*
|
||||
* context.keylog_cb = proc do |_sock, line|
|
||||
* File.open('ssl_keylog_file', "a") do |f|
|
||||
* f.write("#{line}\n")
|
||||
* end
|
||||
* end
|
||||
*/
|
||||
rb_attr(cSSLContext, rb_intern_const("keylog_cb"), 1, 1, Qfalse);
|
||||
|
||||
rb_define_alias(cSSLContext, "ssl_timeout", "timeout");
|
||||
rb_define_alias(cSSLContext, "ssl_timeout=", "timeout=");
|
||||
rb_define_private_method(cSSLContext, "set_minmax_proto_version",
|
||||
|
@ -3064,6 +3147,7 @@ Init_ossl_ssl(void)
|
|||
DefIVarID(alpn_select_cb);
|
||||
DefIVarID(servername_cb);
|
||||
DefIVarID(verify_hostname);
|
||||
DefIVarID(keylog_cb);
|
||||
|
||||
DefIVarID(io);
|
||||
DefIVarID(context);
|
||||
|
|
|
@ -804,6 +804,54 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_keylog_cb
|
||||
pend "Keylog callback is not supported" if !openssl?(1, 1, 1) || libressl?
|
||||
|
||||
prefix = 'CLIENT_RANDOM'
|
||||
context = OpenSSL::SSL::SSLContext.new
|
||||
context.min_version = context.max_version = OpenSSL::SSL::TLS1_2_VERSION
|
||||
|
||||
cb_called = false
|
||||
context.keylog_cb = proc do |_sock, line|
|
||||
cb_called = true
|
||||
assert_equal(prefix, line.split.first)
|
||||
end
|
||||
|
||||
start_server do |port|
|
||||
server_connect(port, context) do |ssl|
|
||||
ssl.puts "abc"
|
||||
assert_equal("abc\n", ssl.gets)
|
||||
assert_equal(true, cb_called)
|
||||
end
|
||||
end
|
||||
|
||||
if tls13_supported?
|
||||
prefixes = [
|
||||
'SERVER_HANDSHAKE_TRAFFIC_SECRET',
|
||||
'EXPORTER_SECRET',
|
||||
'SERVER_TRAFFIC_SECRET_0',
|
||||
'CLIENT_HANDSHAKE_TRAFFIC_SECRET',
|
||||
'CLIENT_TRAFFIC_SECRET_0',
|
||||
]
|
||||
context = OpenSSL::SSL::SSLContext.new
|
||||
context.min_version = context.max_version = OpenSSL::SSL::TLS1_3_VERSION
|
||||
cb_called = false
|
||||
context.keylog_cb = proc do |_sock, line|
|
||||
cb_called = true
|
||||
assert_not_nil(prefixes.delete(line.split.first))
|
||||
end
|
||||
|
||||
start_server do |port|
|
||||
server_connect(port, context) do |ssl|
|
||||
ssl.puts "abc"
|
||||
assert_equal("abc\n", ssl.gets)
|
||||
assert_equal(true, cb_called)
|
||||
end
|
||||
assert_equal(0, prefixes.size)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_tlsext_hostname
|
||||
fooctx = OpenSSL::SSL::SSLContext.new
|
||||
fooctx.cert = @cli_cert
|
||||
|
|
Loading…
Reference in a new issue