diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index 8d2eac026..011c49f65 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -195,6 +195,7 @@ def find_openssl_library have_func("EVP_PKEY_check(NULL)", evp_h) have_func("EVP_PKEY_new_raw_private_key(0, NULL, (unsigned char *)\"\", 0)", evp_h) have_func("SSL_CTX_set_ciphersuites(NULL, \"\")", ssl_h) +have_func("SSL_CTX_set1_sigalgs(NULL, NULL, 0L)", ssl_h) # added in 3.0.0 have_func("SSL_set0_tmp_dh_pkey(NULL, NULL)", ssl_h) diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 457630ddc..cd7f4878f 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -1103,6 +1103,36 @@ ossl_sslctx_set_ciphersuites(VALUE self, VALUE v) } #endif +#ifdef HAVE_SSL_CTX_SET1_SIGALGS +/* + * call-seq: + * ctx.sigalgs = sigalgs_list -> sigalgs_list + * + * Sets the list of "supported signature algorithms" for this context. + * + * For a TLS client, the list is directly used in the supported + * signature algorithm list in the client hello message. For a server, + * the list is used by OpenSSL to determine the set of shared signature + * algorithms. OpenSSL will pick the most appropriate one from it. + */ +static VALUE +ossl_sslctx_set_sigalgs(VALUE self, VALUE v) +{ + SSL_CTX *ctx; + + if (NIL_P(v)) + return v; + + rb_check_frozen(self); + GetSSLCTX(self, ctx); + + if (!SSL_CTX_set1_sigalgs_list(ctx, StringValueCStr(v))) + ossl_raise(eSSLError, "SSL_CTX_set1_sigalgs_list"); + + return v; +} +#endif + #ifndef OPENSSL_NO_DH /* * call-seq: @@ -2898,6 +2928,9 @@ Init_ossl_ssl(void) #ifdef HAVE_SSL_CTX_SET_CIPHERSUITES rb_define_method(cSSLContext, "ciphersuites=", ossl_sslctx_set_ciphersuites, 1); #endif +#ifdef HAVE_SSL_CTX_SET1_SIGALGS + rb_define_method(cSSLContext, "sigalgs=", ossl_sslctx_set_sigalgs, 1); +#endif #ifndef OPENSSL_NO_DH rb_define_method(cSSLContext, "tmp_dh=", ossl_sslctx_set_tmp_dh, 1); #endif diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index 1471b0cb3..b9d86f332 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -1755,6 +1755,36 @@ def test_ciphers_method_tls_connection end end + def test_sigalgs_method_nil_argument + ssl_ctx = OpenSSL::SSL::SSLContext.new + pend 'sigalgs= method is missing' unless ssl_ctx.respond_to?(:sigalgs=) + + assert_nothing_raised { ssl_ctx.sigalgs = nil } + end + + def test_sigalgs_method_frozen_object + ssl_ctx = OpenSSL::SSL::SSLContext.new + pend 'sigalgs= method is missing' unless ssl_ctx.respond_to?(:sigalgs=) + + ssl_ctx.freeze + assert_raise(FrozenError) { ssl_ctx.sigalgs = '"ECDSA+SHA256:RSA+SHA256"' } + end + + def test_sigalgs_method_valid_sigalgs + ssl_ctx = OpenSSL::SSL::SSLContext.new + pend 'sigalgs= method is missing' unless ssl_ctx.respond_to?(:sigalgs=) + + ssl_ctx.freeze + assert_raise(FrozenError) { ssl_ctx.sigalgs = '"ECDSA+SHA256:RSA+SHA256"' } + end + + def test_sigalgs_method_bogus_sigalgs + ssl_ctx = OpenSSL::SSL::SSLContext.new + pend 'sigalgs= method is missing' unless ssl_ctx.respond_to?(:sigalgs=) + + assert_raise(OpenSSL::SSL::SSLError) { ssl_ctx.sigalgs = 'BOGUS' } + end + def test_ciphers_method_nil_argument ssl_ctx = OpenSSL::SSL::SSLContext.new assert_nothing_raised { ssl_ctx.ciphers = nil }