Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LibreSSL 3.5.0 has PEM_write_bio_PrivateKey_traditional #499

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ jobs:
- openssl-1.1.1l
- openssl-3.0.1
- libressl-3.1.5 # EOL
- libressl-3.2.6
- libressl-3.3.4
- libressl-3.2.7
- libressl-3.3.5
- libressl-3.4.2
- libressl-3.5.0
steps:
- name: repo checkout
uses: actions/checkout@v2
Expand Down
34 changes: 0 additions & 34 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,38 +26,4 @@ task :debug do
ruby "-I./lib -ropenssl -ve'puts OpenSSL::OPENSSL_VERSION, OpenSSL::OPENSSL_LIBRARY_VERSION'"
end

namespace :sync do
task :from_ruby do
sh "./tool/sync-with-trunk"
end

task :to_ruby do
trunk_path = ENV.fetch("RUBY_TRUNK_PATH", "../ruby")

rsync = "rsync -av --delete"
excludes = %w{Makefile extconf.h mkmf.log depend *.o *.so *.bundle}
excludes.each { |name| rsync << " --exclude #{name}" }

paths = [
["ext/openssl/", "ext/openssl/"],
["lib/", "ext/openssl/lib/"],
["sample/", "sample/openssl/"],
["test/fixtures/", "test/openssl/fixtures/"],
["test/utils.rb", "test/openssl/"],
["test/ut_eof.rb", "test/openssl/"],
["test/test_*", "test/openssl/"],
["History.md", "ext/openssl/"],
]
paths.each do |src, dst|
sh "#{rsync} #{src} #{trunk_path}/#{dst}"
end

gemspec_file = File.expand_path("../openssl.gemspec", __FILE__)
gemspec = eval(File.read(gemspec_file), binding, gemspec_file)
File.write("#{trunk_path}/ext/openssl/openssl.gemspec", gemspec.to_ruby)

puts "Don't forget to update ext/openssl/depend"
end
end

task :default => :test
1 change: 1 addition & 0 deletions ext/openssl/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ def find_openssl_library

# added in 1.1.1
have_func("EVP_PKEY_check")
have_func("SSL_CTX_set_ciphersuites")

# added in 3.0.0
have_func("SSL_set0_tmp_dh_pkey")
Expand Down
11 changes: 6 additions & 5 deletions ext/openssl/ossl_pkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -670,11 +670,8 @@ ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
}
}
else {
#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
ossl_pem_passwd_cb,
(void *)pass)) {
#else
#if OPENSSL_VERSION_NUMBER < 0x10100000 || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x30500000)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can now use OSSL_OPENSSL_PREREQ() and OSSL_LIBRESSL_PREREQ() macro.

char pem_str[80];
const char *aname;

Expand All @@ -683,6 +680,10 @@ ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
if (!PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, pem_str, bio,
pkey, enc, NULL, 0, ossl_pem_passwd_cb,
(void *)pass)) {
#else
if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
ossl_pem_passwd_cb,
(void *)pass)) {
#endif
BIO_free(bio);
ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
Expand Down
78 changes: 60 additions & 18 deletions ext/openssl/ossl_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -959,27 +959,13 @@ ossl_sslctx_get_ciphers(VALUE self)
return ary;
}

/*
* call-seq:
* ctx.ciphers = "cipher1:cipher2:..."
* ctx.ciphers = [name, ...]
* ctx.ciphers = [[name, version, bits, alg_bits], ...]
*
* Sets the list of available cipher suites for this context. Note in a server
* context some ciphers require the appropriate certificates. For example, an
* RSA cipher suite can only be chosen when an RSA certificate is available.
*/
static VALUE
ossl_sslctx_set_ciphers(VALUE self, VALUE v)
build_cipher_string(VALUE v)
{
SSL_CTX *ctx;
VALUE str, elem;
int i;

rb_check_frozen(self);
if (NIL_P(v))
return v;
else if (RB_TYPE_P(v, T_ARRAY)) {
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);
Expand All @@ -993,14 +979,67 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v)
StringValue(str);
}

return str;
}

/*
* call-seq:
* ctx.ciphers = "cipher1:cipher2:..."
* ctx.ciphers = [name, ...]
* ctx.ciphers = [[name, version, bits, alg_bits], ...]
*
* Sets the list of available cipher suites for this context. Note in a server
* context some ciphers require the appropriate certificates. For example, an
* RSA cipher suite can only be chosen when an RSA certificate is available.
*/
static VALUE
ossl_sslctx_set_ciphers(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_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:
Expand Down Expand Up @@ -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
Expand Down
89 changes: 89 additions & 0 deletions test/openssl/test_ssl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1569,6 +1569,95 @@ def test_tmp_dh_callback
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
Expand Down
106 changes: 0 additions & 106 deletions tool/sync-with-trunk

This file was deleted.