[ruby/openssl] Add 'ciphersuites=' method to allow setting of TLSv1.3 cipher suites along with some unit tests (https://github.com/ruby/openssl/pull/493)
Add OpenSSL::SSL::SSLContext#ciphersuites= method along with unit tests. https://github.com/ruby/openssl/commit/12250c7cef
This commit is contained in:
parent
0bf2dfa6ac
commit
09daf78fb5
@ -169,6 +169,7 @@ have_func("SSL_CTX_set_post_handshake_auth")
|
||||
|
||||
# added in 1.1.1
|
||||
have_func("EVP_PKEY_check")
|
||||
have_func("SSL_CTX_set_ciphersuites")
|
||||
|
||||
# added in 3.0.0
|
||||
openssl_3 =
|
||||
|
@ -959,6 +959,29 @@ ossl_sslctx_get_ciphers(VALUE self)
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
build_cipher_string(VALUE v)
|
||||
{
|
||||
VALUE str, elem;
|
||||
int i;
|
||||
|
||||
if (RB_TYPE_P(v, T_ARRAY)) {
|
||||
str = rb_str_new(0, 0);
|
||||
for (i = 0; i < RARRAY_LEN(v); i++) {
|
||||
elem = rb_ary_entry(v, i);
|
||||
if (RB_TYPE_P(elem, T_ARRAY)) elem = rb_ary_entry(elem, 0);
|
||||
elem = rb_String(elem);
|
||||
rb_str_append(str, elem);
|
||||
if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":");
|
||||
}
|
||||
} else {
|
||||
str = v;
|
||||
StringValue(str);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* ctx.ciphers = "cipher1:cipher2:..."
|
||||
@ -973,34 +996,50 @@ static VALUE
|
||||
ossl_sslctx_set_ciphers(VALUE self, VALUE v)
|
||||
{
|
||||
SSL_CTX *ctx;
|
||||
VALUE str, elem;
|
||||
int i;
|
||||
VALUE str;
|
||||
|
||||
rb_check_frozen(self);
|
||||
if (NIL_P(v))
|
||||
return v;
|
||||
else if (RB_TYPE_P(v, T_ARRAY)) {
|
||||
str = rb_str_new(0, 0);
|
||||
for (i = 0; i < RARRAY_LEN(v); i++) {
|
||||
elem = rb_ary_entry(v, i);
|
||||
if (RB_TYPE_P(elem, T_ARRAY)) elem = rb_ary_entry(elem, 0);
|
||||
elem = rb_String(elem);
|
||||
rb_str_append(str, elem);
|
||||
if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":");
|
||||
}
|
||||
} else {
|
||||
str = v;
|
||||
StringValue(str);
|
||||
}
|
||||
return v;
|
||||
|
||||
str = build_cipher_string(v);
|
||||
|
||||
GetSSLCTX(self, ctx);
|
||||
if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str))) {
|
||||
if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str)))
|
||||
ossl_raise(eSSLError, "SSL_CTX_set_cipher_list");
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
|
||||
/*
|
||||
* call-seq:
|
||||
* ctx.ciphersuites = "cipher1:cipher2:..."
|
||||
* ctx.ciphersuites = [name, ...]
|
||||
* ctx.ciphersuites = [[name, version, bits, alg_bits], ...]
|
||||
*
|
||||
* Sets the list of available TLSv1.3 cipher suites for this context.
|
||||
*/
|
||||
static VALUE
|
||||
ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
|
||||
{
|
||||
SSL_CTX *ctx;
|
||||
VALUE str;
|
||||
|
||||
rb_check_frozen(self);
|
||||
if (NIL_P(v))
|
||||
return v;
|
||||
|
||||
str = build_cipher_string(v);
|
||||
|
||||
GetSSLCTX(self, ctx);
|
||||
if (!SSL_CTX_set_ciphersuites(ctx, StringValueCStr(str)))
|
||||
ossl_raise(eSSLError, "SSL_CTX_set_ciphersuites");
|
||||
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_DH
|
||||
/*
|
||||
* call-seq:
|
||||
@ -2703,6 +2742,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);
|
||||
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
|
||||
rb_define_method(cSSLContext, "ciphersuites=", ossl_sslctx_set_ciphersuites, 1);
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_DH
|
||||
rb_define_method(cSSLContext, "tmp_dh=", ossl_sslctx_set_tmp_dh, 1);
|
||||
#endif
|
||||
|
@ -1569,6 +1569,95 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
|
||||
end
|
||||
end
|
||||
|
||||
def test_ciphersuites_method_tls_connection
|
||||
ssl_ctx = OpenSSL::SSL::SSLContext.new
|
||||
if !tls13_supported? || !ssl_ctx.respond_to?(:ciphersuites=)
|
||||
pend 'TLS 1.3 not supported'
|
||||
end
|
||||
|
||||
csuite = ['TLS_AES_128_GCM_SHA256', 'TLSv1.3', 128, 128]
|
||||
inputs = [csuite[0], [csuite[0]], [csuite]]
|
||||
|
||||
start_server do |port|
|
||||
inputs.each do |input|
|
||||
cli_ctx = OpenSSL::SSL::SSLContext.new
|
||||
cli_ctx.min_version = cli_ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION
|
||||
cli_ctx.ciphersuites = input
|
||||
|
||||
server_connect(port, cli_ctx) do |ssl|
|
||||
assert_equal('TLSv1.3', ssl.ssl_version)
|
||||
assert_equal(csuite[0], ssl.cipher[0])
|
||||
ssl.puts('abc'); assert_equal("abc\n", ssl.gets)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_ciphersuites_method_nil_argument
|
||||
ssl_ctx = OpenSSL::SSL::SSLContext.new
|
||||
pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=)
|
||||
|
||||
assert_nothing_raised { ssl_ctx.ciphersuites = nil }
|
||||
end
|
||||
|
||||
def test_ciphersuites_method_frozen_object
|
||||
ssl_ctx = OpenSSL::SSL::SSLContext.new
|
||||
pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=)
|
||||
|
||||
ssl_ctx.freeze
|
||||
assert_raise(FrozenError) { ssl_ctx.ciphersuites = 'TLS_AES_256_GCM_SHA384' }
|
||||
end
|
||||
|
||||
def test_ciphersuites_method_bogus_csuite
|
||||
ssl_ctx = OpenSSL::SSL::SSLContext.new
|
||||
pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=)
|
||||
|
||||
assert_raise_with_message(
|
||||
OpenSSL::SSL::SSLError,
|
||||
/SSL_CTX_set_ciphersuites: no cipher match/i
|
||||
) { ssl_ctx.ciphersuites = 'BOGUS' }
|
||||
end
|
||||
|
||||
def test_ciphers_method_tls_connection
|
||||
csuite = ['ECDHE-RSA-AES256-GCM-SHA384', 'TLSv1.2', 256, 256]
|
||||
inputs = [csuite[0], [csuite[0]], [csuite]]
|
||||
|
||||
start_server do |port|
|
||||
inputs.each do |input|
|
||||
cli_ctx = OpenSSL::SSL::SSLContext.new
|
||||
cli_ctx.min_version = cli_ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
|
||||
cli_ctx.ciphers = input
|
||||
|
||||
server_connect(port, cli_ctx) do |ssl|
|
||||
assert_equal('TLSv1.2', ssl.ssl_version)
|
||||
assert_equal(csuite[0], ssl.cipher[0])
|
||||
ssl.puts('abc'); assert_equal("abc\n", ssl.gets)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_ciphers_method_nil_argument
|
||||
ssl_ctx = OpenSSL::SSL::SSLContext.new
|
||||
assert_nothing_raised { ssl_ctx.ciphers = nil }
|
||||
end
|
||||
|
||||
def test_ciphers_method_frozen_object
|
||||
ssl_ctx = OpenSSL::SSL::SSLContext.new
|
||||
|
||||
ssl_ctx.freeze
|
||||
assert_raise(FrozenError) { ssl_ctx.ciphers = 'ECDHE-RSA-AES128-SHA' }
|
||||
end
|
||||
|
||||
def test_ciphers_method_bogus_csuite
|
||||
ssl_ctx = OpenSSL::SSL::SSLContext.new
|
||||
|
||||
assert_raise_with_message(
|
||||
OpenSSL::SSL::SSLError,
|
||||
/SSL_CTX_set_cipher_list: no cipher match/i
|
||||
) { ssl_ctx.ciphers = 'BOGUS' }
|
||||
end
|
||||
|
||||
def test_connect_works_when_setting_dh_callback_to_nil
|
||||
ctx_proc = -> ctx {
|
||||
ctx.max_version = :TLS1_2
|
||||
|
Loading…
x
Reference in New Issue
Block a user