From 79543b9a530d85f0487583d96ad412f5e7683ffa Mon Sep 17 00:00:00 2001 From: madblobfish <-> Date: Wed, 3 Aug 2022 23:24:28 +0200 Subject: [PATCH] [ruby/openssl] ssl: enable generating keying material from SSL sessions Add OpenSSL::SSL::SSLSocket#export_keying_material to support RFC 5705 https://github.com/ruby/openssl/commit/65530b887e --- ext/openssl/ossl_ssl.c | 44 ++++++++++++++++++++++++++++++++++++++++ test/openssl/test_ssl.rb | 13 ++++++++++++ 2 files changed, 57 insertions(+) diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 319ba5840e67ac..593a6aa7580711 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -2433,6 +2433,49 @@ ossl_ssl_alpn_protocol(VALUE self) return rb_str_new((const char *) out, outlen); } +/* + * call-seq: + * session.export_keying_material(label, length) -> String + * + * Enables use of shared session key material in accordance with RFC 5705. + */ +static VALUE +ossl_ssl_export_keying_material(int argc, VALUE *argv, VALUE self) +{ + SSL *ssl; + VALUE str; + VALUE label; + VALUE length; + VALUE context; + unsigned char *p; + size_t len; + int use_ctx = 0; + unsigned char *ctx; + size_t ctx_len = 0; + int ret; + + rb_scan_args(argc, argv, "21", &label, &length, &context); + StringValue(label); + + GetSSL(self, ssl); + + len = (size_t)NUM2LONG(length); + str = rb_str_new(0, len); + p = (unsigned char *)RSTRING_PTR(str); + if (!NIL_P(context)) { + use_ctx = 1; + StringValue(context); + ctx = (unsigned char *)RSTRING_PTR(context); + ctx_len = RSTRING_LEN(context); + } + ret = SSL_export_keying_material(ssl, p, len, (char *)RSTRING_PTR(label), + RSTRING_LENINT(label), ctx, ctx_len, use_ctx); + if (ret == 0 || ret == -1) { + ossl_raise(eSSLError, "SSL_export_keying_material"); + } + return str; +} + /* * call-seq: * ssl.tmp_key => PKey or nil @@ -2860,6 +2903,7 @@ Init_ossl_ssl(void) rb_define_method(cSSLSocket, "peer_finished_message", ossl_ssl_get_peer_finished, 0); rb_define_method(cSSLSocket, "tmp_key", ossl_ssl_tmp_key, 0); rb_define_method(cSSLSocket, "alpn_protocol", ossl_ssl_alpn_protocol, 0); + rb_define_method(cSSLSocket, "export_keying_material", ossl_ssl_export_keying_material, -1); # ifndef OPENSSL_NO_NEXTPROTONEG rb_define_method(cSSLSocket, "npn_protocol", ossl_ssl_npn_protocol, 0); # endif diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index 5679ae77d781d3..9f5a27ea9fcdb5 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -1817,6 +1817,19 @@ def test_fileno sock2.close end + def test_export_keying_material + start_server do |port| + cli_ctx = OpenSSL::SSL::SSLContext.new + server_connect(port, cli_ctx) do |ssl| + assert_instance_of(String, ssl.export_keying_material('ttls keying material', 64)) + assert_operator(64, :==, ssl.export_keying_material('ttls keying material', 64).b.length) + assert_operator(8, :==, ssl.export_keying_material('ttls keying material', 8).b.length) + assert_operator(5, :==, ssl.export_keying_material('test', 5, 'context').b.length) + ssl.puts "abc"; ssl.gets # workaround to make tests work on windows + end + end + end + private def start_server_version(version, ctx_proc = nil,