Skip to content

Commit

Permalink
Merge pull request #481 from rhenium/ky/openssl-3.0.0-part2
Browse files Browse the repository at this point in the history
Miscellaneous changes for OpenSSL 3.0 support (part 2)
  • Loading branch information
rhenium authored Dec 20, 2021
2 parents 5d0df40 + fd4dd6d commit 4beb383
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 65 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ jobs:
- openssl-1.0.2u # EOL
- openssl-1.1.0l # EOL
- openssl-1.1.1l
- openssl-3.0.1
- libressl-3.1.5 # EOL
- libressl-3.2.6
- libressl-3.3.4
Expand All @@ -89,7 +90,7 @@ jobs:
curl -OL https://ftp.openssl.org/source/${{ matrix.openssl }}.tar.gz
tar xf ${{ matrix.openssl }}.tar.gz && cd ${{ matrix.openssl }}
# shared is required for 1.0.x.
./Configure --prefix=$HOME/.openssl/${{ matrix.openssl }} \
./Configure --prefix=$HOME/.openssl/${{ matrix.openssl }} --libdir=lib \
shared linux-x86_64
make depend
;;
Expand Down
3 changes: 0 additions & 3 deletions ext/openssl/openssl_missing.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
#include RUBY_EXTCONF_H

#include <string.h> /* memcpy() */
#if !defined(OPENSSL_NO_ENGINE)
# include <openssl/engine.h>
#endif
#include <openssl/x509_vfy.h>

#include "openssl_missing.h"
Expand Down
8 changes: 5 additions & 3 deletions ext/openssl/ossl.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <ruby/io.h>
#include <ruby/thread.h>
#include <openssl/opensslv.h>

#include <openssl/err.h>
#include <openssl/asn1.h>
#include <openssl/x509v3.h>
Expand All @@ -30,9 +31,6 @@
#include <openssl/ts.h>
#endif
#include <openssl/crypto.h>
#if !defined(OPENSSL_NO_ENGINE)
# include <openssl/engine.h>
#endif
#if !defined(OPENSSL_NO_OCSP)
# include <openssl/ocsp.h>
#endif
Expand All @@ -54,6 +52,10 @@
(LIBRESSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12))
#endif

#if !defined(OPENSSL_NO_ENGINE) && !OSSL_OPENSSL_PREREQ(3, 0, 0)
# define OSSL_USE_ENGINE
#endif

/*
* Common Module
*/
Expand Down
3 changes: 2 additions & 1 deletion ext/openssl/ossl_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
*/
#include "ossl.h"

#if !defined(OPENSSL_NO_ENGINE)
#ifdef OSSL_USE_ENGINE
# include <openssl/engine.h>

#define NewEngine(klass) \
TypedData_Wrap_Struct((klass), &ossl_engine_type, 0)
Expand Down
4 changes: 2 additions & 2 deletions ext/openssl/ossl_hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ static VALUE
ossl_hmac_digest(VALUE self)
{
EVP_MD_CTX *ctx;
size_t buf_len;
size_t buf_len = EVP_MAX_MD_SIZE;
VALUE ret;

GetHMAC(self, ctx);
Expand All @@ -200,7 +200,7 @@ ossl_hmac_hexdigest(VALUE self)
{
EVP_MD_CTX *ctx;
unsigned char buf[EVP_MAX_MD_SIZE];
size_t buf_len;
size_t buf_len = EVP_MAX_MD_SIZE;
VALUE ret;

GetHMAC(self, ctx);
Expand Down
21 changes: 21 additions & 0 deletions ext/openssl/ossl_pkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
*/
#include "ossl.h"

#ifdef OSSL_USE_ENGINE
# include <openssl/engine.h>
#endif

/*
* Classes
*/
Expand Down Expand Up @@ -312,6 +316,11 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
}
else {
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
ctx = EVP_PKEY_CTX_new_from_name(NULL, StringValueCStr(alg), NULL);
if (!ctx)
ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_from_name");
#else
const EVP_PKEY_ASN1_METHOD *ameth;
ENGINE *tmpeng;
int pkey_id;
Expand All @@ -330,6 +339,7 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */);
if (!ctx)
ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id");
#endif
}

if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) {
Expand Down Expand Up @@ -425,9 +435,19 @@ ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
return pkey_generate(argc, argv, self, 0);
}

/*
* TODO: There is no convenient way to check the presence of public key
* components on OpenSSL 3.0. But since keys are immutable on 3.0, pkeys without
* these should only be created by OpenSSL::PKey.generate_parameters or by
* parsing DER-/PEM-encoded string. We would need another flag for that.
*/
void
ossl_pkey_check_public_key(const EVP_PKEY *pkey)
{
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
if (EVP_PKEY_missing_parameters(pkey))
ossl_raise(ePKeyError, "parameters missing");
#else
void *ptr;
const BIGNUM *n, *e, *pubkey;

Expand Down Expand Up @@ -463,6 +483,7 @@ ossl_pkey_check_public_key(const EVP_PKEY *pkey)
return;
}
ossl_raise(ePKeyError, "public key missing");
#endif
}

EVP_PKEY *
Expand Down
35 changes: 29 additions & 6 deletions ext/openssl/ossl_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2825,9 +2825,24 @@ Init_ossl_ssl(void)
rb_define_const(mSSL, "VERIFY_CLIENT_ONCE", INT2NUM(SSL_VERIFY_CLIENT_ONCE));

rb_define_const(mSSL, "OP_ALL", ULONG2NUM(SSL_OP_ALL));
#ifdef SSL_OP_CLEANSE_PLAINTEXT /* OpenSSL 3.0 */
rb_define_const(mSSL, "OP_CLEANSE_PLAINTEXT", ULONG2NUM(SSL_OP_CLEANSE_PLAINTEXT));
#endif
rb_define_const(mSSL, "OP_LEGACY_SERVER_CONNECT", ULONG2NUM(SSL_OP_LEGACY_SERVER_CONNECT));
#ifdef SSL_OP_ENABLE_KTLS /* OpenSSL 3.0 */
rb_define_const(mSSL, "OP_ENABLE_KTLS", ULONG2NUM(SSL_OP_ENABLE_KTLS));
#endif
rb_define_const(mSSL, "OP_TLSEXT_PADDING", ULONG2NUM(SSL_OP_TLSEXT_PADDING));
rb_define_const(mSSL, "OP_SAFARI_ECDHE_ECDSA_BUG", ULONG2NUM(SSL_OP_SAFARI_ECDHE_ECDSA_BUG));
#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF /* OpenSSL 3.0 */
rb_define_const(mSSL, "OP_IGNORE_UNEXPECTED_EOF", ULONG2NUM(SSL_OP_IGNORE_UNEXPECTED_EOF));
#endif
#ifdef SSL_OP_ALLOW_CLIENT_RENEGOTIATION /* OpenSSL 3.0 */
rb_define_const(mSSL, "OP_ALLOW_CLIENT_RENEGOTIATION", ULONG2NUM(SSL_OP_ALLOW_CLIENT_RENEGOTIATION));
#endif
#ifdef SSL_OP_DISABLE_TLSEXT_CA_NAMES /* OpenSSL 3.0 */
rb_define_const(mSSL, "OP_DISABLE_TLSEXT_CA_NAMES", ULONG2NUM(SSL_OP_DISABLE_TLSEXT_CA_NAMES));
#endif
#ifdef SSL_OP_ALLOW_NO_DHE_KEX /* OpenSSL 1.1.1 */
rb_define_const(mSSL, "OP_ALLOW_NO_DHE_KEX", ULONG2NUM(SSL_OP_ALLOW_NO_DHE_KEX));
#endif
Expand All @@ -2839,20 +2854,28 @@ Init_ossl_ssl(void)
#ifdef SSL_OP_NO_ENCRYPT_THEN_MAC /* OpenSSL 1.1.1 */
rb_define_const(mSSL, "OP_NO_ENCRYPT_THEN_MAC", ULONG2NUM(SSL_OP_NO_ENCRYPT_THEN_MAC));
#endif
rb_define_const(mSSL, "OP_CIPHER_SERVER_PREFERENCE", ULONG2NUM(SSL_OP_CIPHER_SERVER_PREFERENCE));
rb_define_const(mSSL, "OP_TLS_ROLLBACK_BUG", ULONG2NUM(SSL_OP_TLS_ROLLBACK_BUG));
#ifdef SSL_OP_NO_RENEGOTIATION /* OpenSSL 1.1.1 */
rb_define_const(mSSL, "OP_NO_RENEGOTIATION", ULONG2NUM(SSL_OP_NO_RENEGOTIATION));
#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT /* OpenSSL 1.1.1 */
rb_define_const(mSSL, "OP_ENABLE_MIDDLEBOX_COMPAT", ULONG2NUM(SSL_OP_ENABLE_MIDDLEBOX_COMPAT));
#endif
#ifdef SSL_OP_PRIORITIZE_CHACHA /* OpenSSL 1.1.1 */
rb_define_const(mSSL, "OP_PRIORITIZE_CHACHA", ULONG2NUM(SSL_OP_PRIORITIZE_CHACHA));
#endif
#ifdef SSL_OP_NO_ANTI_REPLAY /* OpenSSL 1.1.1 */
rb_define_const(mSSL, "OP_NO_ANTI_REPLAY", ULONG2NUM(SSL_OP_NO_ANTI_REPLAY));
#endif
rb_define_const(mSSL, "OP_CRYPTOPRO_TLSEXT_BUG", ULONG2NUM(SSL_OP_CRYPTOPRO_TLSEXT_BUG));

rb_define_const(mSSL, "OP_NO_SSLv3", ULONG2NUM(SSL_OP_NO_SSLv3));
rb_define_const(mSSL, "OP_NO_TLSv1", ULONG2NUM(SSL_OP_NO_TLSv1));
rb_define_const(mSSL, "OP_NO_TLSv1_1", ULONG2NUM(SSL_OP_NO_TLSv1_1));
rb_define_const(mSSL, "OP_NO_TLSv1_2", ULONG2NUM(SSL_OP_NO_TLSv1_2));
#ifdef SSL_OP_NO_TLSv1_3 /* OpenSSL 1.1.1 */
rb_define_const(mSSL, "OP_NO_TLSv1_3", ULONG2NUM(SSL_OP_NO_TLSv1_3));
#endif
rb_define_const(mSSL, "OP_CIPHER_SERVER_PREFERENCE", ULONG2NUM(SSL_OP_CIPHER_SERVER_PREFERENCE));
rb_define_const(mSSL, "OP_TLS_ROLLBACK_BUG", ULONG2NUM(SSL_OP_TLS_ROLLBACK_BUG));
#ifdef SSL_OP_NO_RENEGOTIATION /* OpenSSL 1.1.1 */
rb_define_const(mSSL, "OP_NO_RENEGOTIATION", ULONG2NUM(SSL_OP_NO_RENEGOTIATION));
#endif
rb_define_const(mSSL, "OP_CRYPTOPRO_TLSEXT_BUG", ULONG2NUM(SSL_OP_CRYPTOPRO_TLSEXT_BUG));

/* SSL_OP_* flags for DTLS */
#if 0
Expand Down
13 changes: 5 additions & 8 deletions test/openssl/test_cipher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,11 @@ def test_ctr_if_exists
end

def test_ciphers
OpenSSL::Cipher.ciphers.each{|name|
next if /netbsd/ =~ RUBY_PLATFORM && /idea|rc5/i =~ name
begin
assert_kind_of(OpenSSL::Cipher, OpenSSL::Cipher.new(name))
rescue OpenSSL::Cipher::CipherError => e
raise unless /wrap/ =~ name and /wrap mode not allowed/ =~ e.message
end
}
ciphers = OpenSSL::Cipher.ciphers
assert_kind_of Array, ciphers
assert_include ciphers, "aes-128-cbc"
assert_include ciphers, "aes128" # alias of aes-128-cbc
assert_include ciphers, "aes-128-gcm"
end

def test_AES
Expand Down
1 change: 1 addition & 0 deletions test/openssl/test_hmac.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def test_hmac
end

def test_dup
pend "HMAC#initialize_copy is currently broken on OpenSSL 3.0.0" if openssl?(3, 0, 0)
h1 = OpenSSL::HMAC.new("KEY", "MD5")
h1.update("DATA")
h = h1.dup
Expand Down
85 changes: 44 additions & 41 deletions test/openssl/test_ssl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -893,14 +893,12 @@ def test_accept_errors_include_peeraddr
end
end

begin
sock = TCPSocket.new("127.0.0.1", port)
sock.puts "abc"
ensure
sock&.close
end
sock = TCPSocket.new("127.0.0.1", port)
sock << "\x00" * 1024

assert t.join
ensure
sock&.close
server.close
end

Expand Down Expand Up @@ -1210,46 +1208,51 @@ def test_minmax_version
end

def test_options_disable_versions
# Note: Use of these OP_* flags has been deprecated since OpenSSL 1.1.0.
# It's recommended to use SSLContext#{min,max}_version= instead in real
# applications. The purpose of this test case is to check that SSL options
# are properly propagated to OpenSSL library.
supported = check_supported_protocol_versions
if !defined?(OpenSSL::SSL::TLS1_3_VERSION) ||
!supported.include?(OpenSSL::SSL::TLS1_2_VERSION) ||
!supported.include?(OpenSSL::SSL::TLS1_3_VERSION) ||
!defined?(OpenSSL::SSL::OP_NO_TLSv1_3) # LibreSSL < 3.4
pend "this test case requires both TLS 1.2 and TLS 1.3 to be supported " \
"and enabled by default"
end

if supported.include?(OpenSSL::SSL::TLS1_1_VERSION) &&
supported.include?(OpenSSL::SSL::TLS1_2_VERSION)
# Server disables ~ TLS 1.1
ctx_proc = proc { |ctx|
ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 |
OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1
}
start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|
# Client only supports TLS 1.1
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_1_VERSION
assert_handshake_error { server_connect(port, ctx1) { } }
# Server disables TLS 1.2 and earlier
ctx_proc = proc { |ctx|
ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 |
OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 |
OpenSSL::SSL::OP_NO_TLSv1_2
}
start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|
# Client only supports TLS 1.2
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_2_VERSION
assert_handshake_error { server_connect(port, ctx1) { } }

# Client only supports TLS 1.2
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_2_VERSION
assert_nothing_raised { server_connect(port, ctx2) { } }
}
# Client only supports TLS 1.3
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_3_VERSION
assert_nothing_raised { server_connect(port, ctx2) { } }
}

# Server only supports TLS 1.1
ctx_proc = proc { |ctx|
ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION
}
start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|
# Client disables TLS 1.1
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_1
assert_handshake_error { server_connect(port, ctx1) { } }
# Server only supports TLS 1.2
ctx_proc = proc { |ctx|
ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
}
start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|
# Client doesn't support TLS 1.2
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_2
assert_handshake_error { server_connect(port, ctx1) { } }

# Client disables TLS 1.2
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_2
assert_nothing_raised { server_connect(port, ctx2) { } }
}
else
pend "TLS 1.1 and TLS 1.2 must be supported; skipping"
end
# Client supports TLS 1.2 by default
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_3
assert_nothing_raised { server_connect(port, ctx2) { } }
}
end

def test_ssl_methods_constant
Expand Down

0 comments on commit 4beb383

Please sign in to comment.