aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2021-09-27 13:56:30 +0900
committerGitHub <noreply@github.com>2021-09-27 13:56:30 +0900
commite3a40937ac2b18ac02203e3539c4e90c539a36f9 (patch)
tree3cc4cbff4359144af07555d91ac71ea885b6fbf9
parent5c85b4385f114400d901ed7dd89ce43489b9bceb (diff)
parentaa43da4f0459308e8767bcaa2ad1fec9b5bcf45f (diff)
downloadruby-openssl-e3a40937ac2b18ac02203e3539c4e90c539a36f9.tar.gz
Merge pull request #459 from rhenium/ky/ssl-set-tmp-dh
ssl: add SSLContext#tmp_dh=
-rw-r--r--ext/openssl/extconf.rb3
-rw-r--r--ext/openssl/ossl_ssl.c49
-rw-r--r--lib/openssl/ssl.rb12
-rw-r--r--test/openssl/test_ssl.rb24
4 files changed, 74 insertions, 14 deletions
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index aa4eae82..9a822f60 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -170,6 +170,9 @@ have_func("SSL_CTX_set_post_handshake_auth")
# added in 1.1.1
have_func("EVP_PKEY_check")
+# added in 3.0.0
+have_func("SSL_set0_tmp_dh_pkey")
+
Logging::message "=== Checking done. ===\n"
create_header
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index a32e1dcd..8ebfac52 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -987,6 +987,52 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v)
return v;
}
+#ifndef OPENSSL_NO_DH
+/*
+ * call-seq:
+ * ctx.tmp_dh = pkey
+ *
+ * Sets DH parameters used for ephemeral DH key exchange. This is relevant for
+ * servers only.
+ *
+ * +pkey+ is an instance of OpenSSL::PKey::DH. Note that key components
+ * contained in the key object, if any, are ignored. The server will always
+ * generate a new key pair for each handshake.
+ *
+ * Added in version 3.0. See also the man page SSL_set0_tmp_dh_pkey(3).
+ *
+ * Example:
+ * ctx = OpenSSL::SSL::SSLContext.new
+ * ctx.tmp_dh = OpenSSL::DH.generate(2048)
+ * svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx)
+ * Thread.new { svr.accept }
+ */
+static VALUE
+ossl_sslctx_set_tmp_dh(VALUE self, VALUE arg)
+{
+ SSL_CTX *ctx;
+ EVP_PKEY *pkey;
+
+ rb_check_frozen(self);
+ GetSSLCTX(self, ctx);
+ pkey = GetPKeyPtr(arg);
+
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH)
+ rb_raise(eSSLError, "invalid pkey type %s (expected DH)",
+ OBJ_nid2sn(EVP_PKEY_base_id(pkey)));
+#ifdef HAVE_SSL_SET0_TMP_DH_PKEY
+ if (!SSL_CTX_set0_tmp_dh_pkey(ctx, pkey))
+ ossl_raise(eSSLError, "SSL_CTX_set0_tmp_dh_pkey");
+ EVP_PKEY_up_ref(pkey);
+#else
+ if (!SSL_CTX_set_tmp_dh(ctx, EVP_PKEY_get0_DH(pkey)))
+ ossl_raise(eSSLError, "SSL_CTX_set_tmp_dh");
+#endif
+
+ return arg;
+}
+#endif
+
#if !defined(OPENSSL_NO_EC)
/*
* call-seq:
@@ -2670,6 +2716,9 @@ Init_ossl_ssl(void)
ossl_sslctx_set_minmax_proto_version, 2);
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0);
rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1);
+#ifndef OPENSSL_NO_DH
+ rb_define_method(cSSLContext, "tmp_dh=", ossl_sslctx_set_tmp_dh, 1);
+#endif
rb_define_method(cSSLContext, "ecdh_curves=", ossl_sslctx_set_ecdh_curves, 1);
rb_define_method(cSSLContext, "security_level", ossl_sslctx_get_security_level, 0);
rb_define_method(cSSLContext, "security_level=", ossl_sslctx_set_security_level, 1);
diff --git a/lib/openssl/ssl.rb b/lib/openssl/ssl.rb
index 0930a530..a9103ecd 100644
--- a/lib/openssl/ssl.rb
+++ b/lib/openssl/ssl.rb
@@ -91,15 +91,17 @@ YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
DEFAULT_CERT_STORE.set_default_paths
DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
- # A callback invoked when DH parameters are required.
+ # A callback invoked when DH parameters are required for ephemeral DH key
+ # exchange.
#
- # The callback is invoked with the Session for the key exchange, an
+ # The callback is invoked with the SSLSocket, a
# flag indicating the use of an export cipher and the keylength
# required.
#
# The callback must return an OpenSSL::PKey::DH instance of the correct
# key length.
-
+ #
+ # <b>Deprecated in version 3.0.</b> Use #tmp_dh= instead.
attr_accessor :tmp_dh_callback
# A callback invoked at connect time to distinguish between multiple
@@ -432,10 +434,6 @@ YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
@context.tmp_dh_callback || OpenSSL::SSL::SSLContext::DEFAULT_TMP_DH_CALLBACK
end
- def tmp_ecdh_callback
- @context.tmp_ecdh_callback
- end
-
def session_new_cb
@context.session_new_cb
end
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index 5dccac5f..0337205c 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -1583,13 +1583,11 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
end
- def test_dh_callback
- pend "TLS 1.2 is not supported" unless tls12_supported?
-
+ def test_tmp_dh_callback
dh = Fixtures.pkey("dh-1")
called = false
ctx_proc = -> ctx {
- ctx.ssl_version = :TLSv1_2
+ ctx.max_version = :TLS1_2
ctx.ciphers = "DH:!NULL"
ctx.tmp_dh_callback = ->(*args) {
called = true
@@ -1605,10 +1603,8 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
def test_connect_works_when_setting_dh_callback_to_nil
- pend "TLS 1.2 is not supported" unless tls12_supported?
-
ctx_proc = -> ctx {
- ctx.ssl_version = :TLSv1_2
+ ctx.max_version = :TLS1_2
ctx.ciphers = "DH:!NULL" # use DH
ctx.tmp_dh_callback = nil
}
@@ -1621,6 +1617,20 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
end
+ def test_tmp_dh
+ dh = Fixtures.pkey("dh-1")
+ ctx_proc = -> ctx {
+ ctx.max_version = :TLS1_2
+ ctx.ciphers = "DH:!NULL" # use DH
+ ctx.tmp_dh = dh
+ }
+ start_server(ctx_proc: ctx_proc) do |port|
+ server_connect(port) { |ssl|
+ assert_equal dh.to_der, ssl.tmp_key.to_der
+ }
+ end
+ end
+
def test_ecdh_curves_tls12
pend "EC is disabled" unless defined?(OpenSSL::PKey::EC)