Compare commits

...

No commits in common. 'c9' and 'i8-stream-2.5' have entirely different histories.

2
.gitignore vendored

@ -1 +1 @@
SOURCES/ruby-3.0.7.tar.xz
SOURCES/ruby-2.5.9.tar.xz

@ -1 +1 @@
efc97e609868a19f89653068c4915c162117b721 SOURCES/ruby-3.0.7.tar.xz
7be8dc2e6e534eb36bfdf9f017af512996ec99a6 SOURCES/ruby-2.5.9.tar.xz

@ -0,0 +1,151 @@
From 005f3b31f9520e22605a359e8a5b36d9855621a5 Mon Sep 17 00:00:00 2001
From: tigro <tigro@msvsphere-os.ru>
Date: Fri, 12 Apr 2024 13:58:34 +0300
Subject: [PATCH] Skip some SSL tests
---
test/net/ftp/test_ftp.rb | 6 ++++++
test/net/http/test_https.rb | 6 ++++++
test/net/imap/test_imap.rb | 2 ++
test/openssl/test_ssl.rb | 1 +
4 files changed, 15 insertions(+)
diff --git a/test/net/ftp/test_ftp.rb b/test/net/ftp/test_ftp.rb
index 8e0a688..889a702 100644
--- a/test/net/ftp/test_ftp.rb
+++ b/test/net/ftp/test_ftp.rb
@@ -1716,6 +1716,7 @@ EOF
end
def test_tls_with_ca_file
+ skip "Old Certs"
assert_nothing_raised do
tls_test do |port|
begin
@@ -1752,6 +1753,7 @@ EOF
end
def test_active_private_data_connection
+ skip "Old Certs"
server = TCPServer.new(SERVER_ADDR, 0)
port = server.addr[1]
commands = []
@@ -1836,6 +1838,7 @@ EOF
end
def test_passive_private_data_connection
+ skip "Old Certs"
server = TCPServer.new(SERVER_ADDR, 0)
port = server.addr[1]
commands = []
@@ -1919,6 +1922,7 @@ EOF
end
def test_active_clear_data_connection
+ skip "Old Certs"
server = TCPServer.new(SERVER_ADDR, 0)
port = server.addr[1]
commands = []
@@ -1988,6 +1992,7 @@ EOF
end
def test_passive_clear_data_connection
+ skip "Old Certs"
server = TCPServer.new(SERVER_ADDR, 0)
port = server.addr[1]
commands = []
@@ -2083,6 +2088,7 @@ EOF
end
def test_abort_tls
+ skip "Old Certs"
return unless defined?(OpenSSL)
commands = []
diff --git a/test/net/http/test_https.rb b/test/net/http/test_https.rb
index 3a23410..59d327d 100644
--- a/test/net/http/test_https.rb
+++ b/test/net/http/test_https.rb
@@ -33,6 +33,7 @@ class TestNetHTTPS < Test::Unit::TestCase
}
def test_get
+ skip "Old Certs"
http = Net::HTTP.new("localhost", config("port"))
http.use_ssl = true
http.cert_store = TEST_STORE
@@ -53,6 +54,7 @@ class TestNetHTTPS < Test::Unit::TestCase
end
def test_post
+ skip "Old Certs"
http = Net::HTTP.new("localhost", config("port"))
http.use_ssl = true
http.cert_store = TEST_STORE
@@ -65,6 +67,7 @@ class TestNetHTTPS < Test::Unit::TestCase
end
def test_session_reuse
+ skip "Old Certs"
# FIXME: The new_session_cb is known broken for clients in OpenSSL 1.1.0h.
# See https://github.com/openssl/openssl/pull/5967 for details.
skip if OpenSSL::OPENSSL_LIBRARY_VERSION =~ /OpenSSL 1.1.0h/
@@ -89,6 +92,7 @@ class TestNetHTTPS < Test::Unit::TestCase
end
def test_session_reuse_but_expire
+ skip "Old Certs"
# FIXME: The new_session_cb is known broken for clients in OpenSSL 1.1.0h.
skip if OpenSSL::OPENSSL_LIBRARY_VERSION =~ /OpenSSL 1.1.0h/
@@ -190,6 +194,7 @@ class TestNetHTTPS < Test::Unit::TestCase
end
def test_min_version
+ skip "Old Certs"
http = Net::HTTP.new("localhost", config("port"))
http.use_ssl = true
http.min_version = :TLS1
@@ -200,6 +205,7 @@ class TestNetHTTPS < Test::Unit::TestCase
end
def test_max_version
+ skip "Old Certs"
http = Net::HTTP.new("127.0.0.1", config("port"))
http.use_ssl = true
http.max_version = :SSL2
diff --git a/test/net/imap/test_imap.rb b/test/net/imap/test_imap.rb
index 41f25fe..066bed0 100644
--- a/test/net/imap/test_imap.rb
+++ b/test/net/imap/test_imap.rb
@@ -76,6 +76,7 @@ class IMAPTest < Test::Unit::TestCase
end
def test_imaps_with_ca_file
+ skip "Old Certs"
assert_nothing_raised do
imaps_test do |port|
begin
@@ -114,6 +115,7 @@ class IMAPTest < Test::Unit::TestCase
if defined?(OpenSSL::SSL)
def test_starttls
+ skip "Old Certs"
imap = nil
starttls_test do |port|
imap = Net::IMAP.new("localhost", :port => port)
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index 060c1f1..71e573c 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -291,6 +291,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
def test_starttls
+ skip "Old Certs"
server_proc = -> (ctx, ssl) {
while line = ssl.gets
if line =~ /^STARTTLS$/
--
2.44.0

@ -0,0 +1,8 @@
if defined?(Gem)
require 'rubygems.rb'
begin
require 'abrt'
rescue LoadError
end
end

@ -9,7 +9,6 @@
%gem_cache %{gem_dir}/cache/%{gem_name}-%{version}%{?prerelease}.gem
%gem_spec %{gem_dir}/specifications/%{gem_name}-%{version}%{?prerelease}.gemspec
%gem_docdir %{gem_dir}/doc/%{gem_name}-%{version}%{?prerelease}
%gem_plugin %{gem_dir}/plugins/%{gem_name}_plugin.rb
# %gem_install - Install gem into appropriate directory.
@ -22,7 +21,7 @@
%gem_install(d:n:) \
mkdir -p %{-d*}%{!?-d:.%{gem_dir}} \
\
CONFIGURE_ARGS="--with-cflags='%{optflags}' --with-cxxflags='%{optflags}' --with-ldflags='%{build_ldflags}' $CONFIGURE_ARGS" \\\
CONFIGURE_ARGS="--with-cflags='%{optflags}' $CONFIGURE_ARGS" \\\
gem install \\\
-V \\\
--local \\\
@ -33,6 +32,16 @@ gem install \\\
%{nil}
# For rubygems packages we want to filter out any provides caused by private
# libs in %%{gem_archdir}.
#
# Note that this must be invoked in the spec file, preferably as
# "%{?rubygems_default_filter}", before any %description block.
%rubygems_default_filter %{expand: \
%global __provides_exclude_from %{?__provides_exclude_from:%{__provides_exclude_from}|}^%{gem_extdir_mri}/.*\\\\.so$ \
}
# The 'read' command in %%gemspec_* macros is not essential, but it is usefull
# to make the sript appear in build log.

@ -11,7 +11,7 @@ diff --git a/lib/mkmf.rb b/lib/mkmf.rb
index 682eb46..e6b1445 100644
--- a/lib/mkmf.rb
+++ b/lib/mkmf.rb
@@ -1930,7 +1930,7 @@ def configuration(srcdir)
@@ -1900,7 +1900,7 @@ def configuration(srcdir)
SHELL = /bin/sh
# V=0 quiet, V=1 verbose. other values don't work.

@ -0,0 +1,58 @@
From 996012f6abe0ce4d68a2de9f249935c6d5b467bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADt=20Ondruch?= <vondruch@redhat.com>
Date: Fri, 4 Oct 2013 22:13:11 +0200
Subject: [PATCH] Allow to specify addition preludes by configuration option.
---
Makefile.in | 2 ++
common.mk | 2 +-
configure.ac | 7 +++++++
3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/Makefile.in b/Makefile.in
index 7e8ed82..7916993 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -119,6 +119,8 @@ XRUBY_RUBYLIBDIR = @XRUBY_RUBYLIBDIR@
XRUBY_RUBYHDRDIR = @XRUBY_RUBYHDRDIR@
BOOTSTRAPRUBY = @BOOTSTRAPRUBY@
+OPTIONAL_PRELUDES = @OPTIONAL_PRELUDES@
+
#### End of system configuration section. ####
MAJOR= @MAJOR@
diff --git a/common.mk b/common.mk
index 5cfbc3d..3f0a82e 100644
--- a/common.mk
+++ b/common.mk
@@ -147,7 +147,7 @@ ALLOBJS = $(NORMALMAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(INITOBJS)
GOLFOBJS = goruby.$(OBJEXT) golf_prelude.$(OBJEXT)
DEFAULT_PRELUDES = $(GEM_PRELUDE)
-PRELUDE_SCRIPTS = $(srcdir)/prelude.rb $(DEFAULT_PRELUDES)
+PRELUDE_SCRIPTS = $(srcdir)/prelude.rb $(DEFAULT_PRELUDES) $(OPTIONAL_PRELUDES)
GEM_PRELUDE = $(srcdir)/gem_prelude.rb
PRELUDES = {$(srcdir)}prelude.c {$(srcdir)}miniprelude.c
GOLFPRELUDES = {$(srcdir)}golf_prelude.c
diff --git a/configure.ac b/configure.ac
index 028ef7ca3e..cdeff87871 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4397,6 +4397,13 @@ AC_SUBST(rubyarchhdrdir)dnl
AC_SUBST(sitearchhdrdir)dnl
AC_SUBST(vendorarchhdrdir)dnl
+AC_ARG_WITH(prelude,
+ AS_HELP_STRING([--with-prelude=FILE-LIST], [specify additional preludes separated by space]),
+ [prelude=$withval])
+if test "$prelude" != ""; then
+ AC_SUBST(OPTIONAL_PRELUDES, $prelude)
+fi
+
AC_ARG_WITH(mantype,
AS_HELP_STRING([--with-mantype=TYPE], [specify man page type; TYPE is one of man and doc]),
[
--
1.8.3.1

@ -8,10 +8,10 @@ Subject: [PATCH] Allow to configure libruby.so placement.
1 file changed, 5 insertions(+)
diff --git a/configure.ac b/configure.ac
index d261ea57b5..3c13076b82 100644
index 11fc237552..b77e88fc37 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3267,6 +3267,11 @@ AS_IF([test ${multiarch+set}], [
@@ -3642,6 +3642,11 @@ AS_IF([test ${multiarch+set}], [
])
archlibdir='${libdir}/${arch}'
@ -24,5 +24,5 @@ index d261ea57b5..3c13076b82 100644
archincludedir='${includedir}/${arch}'
sitearchincludedir='${includedir}/${sitearch}'
--
2.22.0
1.8.3.1

@ -11,10 +11,10 @@ Subject: [PATCH] Prevent duplicated paths when empty version string is
3 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index c42436c23d..d261ea57b5 100644
index 999e2d6d5d..11fc237552 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3913,7 +3913,8 @@ AS_CASE(["$ruby_version_dir_name"],
@@ -4252,7 +4252,8 @@ AS_CASE(["$ruby_version_dir_name"],
ruby_version_dir=/'${ruby_version_dir_name}'
if test -z "${ruby_version_dir_name}"; then
@ -66,7 +66,7 @@ diff --git a/tool/mkconfig.rb b/tool/mkconfig.rb
index 07076d4..35e6c3c 100755
--- a/tool/mkconfig.rb
+++ b/tool/mkconfig.rb
@@ -114,7 +114,7 @@
@@ -111,7 +111,7 @@
val = val.gsub(/\$(?:\$|\{?(\w+)\}?)/) {$1 ? "$(#{$1})" : $&}.dump
case name
when /^prefix$/

@ -8,10 +8,10 @@ Subject: [PATCH] Always use i386.
1 file changed, 2 insertions(+)
diff --git a/configure.ac b/configure.ac
index 3c13076b82..93af30321d 100644
index b77e88fc37..6bba453e3c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3977,6 +3977,8 @@ AC_SUBST(vendorarchdir)dnl
@@ -4316,6 +4316,8 @@ AC_SUBST(vendorarchdir)dnl
AC_SUBST(CONFIGURE, "`echo $0 | sed 's|.*/||'`")dnl
AC_SUBST(configure_args, "`echo "${ac_configure_args}" | sed 's/\\$/$$/g'`")dnl

@ -5,17 +5,17 @@ Subject: [PATCH] Allow to install RubyGems into custom location, outside of
Ruby tree.
---
configure.ac | 5 +++++
loadpath.c | 4 ++++
template/verconf.h.tmpl | 3 +++
tool/rbinstall.rb | 10 ++++++++++
4 files changed, 22 insertions(+)
configure.ac | 5 +++++
loadpath.c | 4 ++++
template/verconf.h.tmpl | 3 +++
tool/rbinstall.rb | 7 +++++++
4 files changed, 19 insertions(+)
diff --git a/configure.ac b/configure.ac
index 93af30321d..bc13397e0e 100644
index 6bba453e3c..028ef7ca3e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3949,6 +3949,10 @@ AC_ARG_WITH(vendorarchdir,
@@ -4288,6 +4288,10 @@ AC_ARG_WITH(vendorarchdir,
[vendorarchdir=$withval],
[vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby'${ruby_version_dir}}${multiarch-'${vendorlibdir}/${sitearch}'}])
@ -26,7 +26,7 @@ index 93af30321d..bc13397e0e 100644
AS_IF([test "${LOAD_RELATIVE+set}"], [
AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE)
RUBY_EXEC_PREFIX=''
@@ -3973,6 +3977,7 @@ AC_SUBST(sitearchdir)dnl
@@ -4312,6 +4316,7 @@ AC_SUBST(sitearchdir)dnl
AC_SUBST(vendordir)dnl
AC_SUBST(vendorlibdir)dnl
AC_SUBST(vendorarchdir)dnl
@ -64,30 +64,27 @@ index 79c003e..34f2382 100644
% R = {}
% R["ruby_version"] = '"RUBY_LIB_VERSION"'
diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb
index e9110a17ca..76a1f0a315 100755
index b47b6e1..0b99408 100755
--- a/tool/rbinstall.rb
+++ b/tool/rbinstall.rb
@@ -349,6 +349,7 @@ def CONFIG.[](name, mandatory = false)
@@ -335,6 +335,7 @@ def CONFIG.[](name, mandatory = false)
vendorlibdir = CONFIG["vendorlibdir"]
vendorarchlibdir = CONFIG["vendorarchdir"]
end
+rubygemsdir = CONFIG["rubygemsdir"]
mandir = CONFIG["mandir", true]
docdir = CONFIG["docdir", true]
enable_shared = CONFIG["ENABLE_SHARED"] == 'yes'
@@ -581,7 +582,16 @@ def stub
configure_args = Shellwords.shellwords(CONFIG["configure_args"])
@@ -541,7 +542,13 @@ def install(src, cmd)
install?(:local, :comm, :lib) do
prepare "library scripts", rubylibdir
noinst = %w[*.txt *.rdoc *.gemspec]
+ # Bundler carries "rubygems.rb" file, so it must be specialcased :/
+ noinst += %w[rubygems.rb rubygems/ bundler.rb bundler/] if rubygemsdir
+ noinst += %w[rubygems.rb rubygems/ datadir.rb] if rubygemsdir
install_recursive(File.join(srcdir, "lib"), rubylibdir, :no_install => noinst, :mode => $data_mode)
+ if rubygemsdir
+ noinst = %w[*.txt *.rdoc *.gemspec]
+ install_recursive(File.join(srcdir, "lib", "rubygems"), File.join(rubygemsdir, "rubygems"), :no_install => noinst, :mode => $data_mode)
+ noinst = %w[obsolete.rb]
+ install_recursive(File.join(srcdir, "lib", "rubygems"), File.join(rubygemsdir, "rubygems"), :mode => $data_mode)
+ install(File.join(srcdir, "lib", "rubygems.rb"), File.join(rubygemsdir, "rubygems.rb"), :mode => $data_mode)
+ install_recursive(File.join(srcdir, "lib", "bundler"), File.join(rubylibdir, "bundler"), :no_install => noinst, :mode => $data_mode)
+ install(File.join(srcdir, "lib", "bundler.rb"), rubylibdir, :mode => $data_mode)
+ end
end

@ -0,0 +1,28 @@
From 07eb5f5e775dec01a92a8b13910eaced9e8ee0cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADt=20Ondruch?= <vondruch@redhat.com>
Date: Tue, 2 Dec 2014 10:56:58 +0100
Subject: [PATCH] Generate preludes using miniruby.
---
common.mk | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/common.mk b/common.mk
index 168dc52..20c218a 100644
--- a/common.mk
+++ b/common.mk
@@ -962,9 +962,9 @@ $(MINIPRELUDE_C): $(COMPILE_PRELUDE)
$(srcdir)/template/prelude.c.tmpl
$(PRELUDE_C): $(COMPILE_PRELUDE) \
- $(PRELUDE_SCRIPTS)
+ $(PRELUDE_SCRIPTS) $(PREP)
$(ECHO) generating $@
- $(Q) $(BASERUBY) $(srcdir)/tool/generic_erb.rb -I$(srcdir) -c -o $@ \
+ $(Q) $(MINIRUBY) $(srcdir)/tool/generic_erb.rb -I$(srcdir) -c -o $@ \
$(srcdir)/template/prelude.c.tmpl $(PRELUDE_SCRIPTS)
{$(VPATH)}golf_prelude.c: $(COMPILE_PRELUDE) {$(srcdir)}golf_prelude.rb
--
2.6.3

@ -12,15 +12,15 @@ ruby_version_dir_name now specifies custom version string for versioned
directories, e.g. instead of default X.Y.Z, you can specify whatever
string.
---
configure.ac | 64 ++++++++++++++++++++++++---------------------
configure.ac | 64 ++++++++++++++++++++++++++++-------------------------
template/ruby.pc.in | 1 +
2 files changed, 35 insertions(+), 30 deletions(-)
diff --git a/configure.ac b/configure.ac
index 80b137e380..63cd3b4f8b 100644
index 8ea969412f..a00f2b6776 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3864,9 +3864,6 @@ AS_CASE(["$target_os"],
@@ -4203,9 +4203,6 @@ AS_CASE(["$target_os"],
rubyw_install_name='$(RUBYW_INSTALL_NAME)'
])
@ -30,7 +30,7 @@ index 80b137e380..63cd3b4f8b 100644
rubyarchprefix=${multiarch+'${archlibdir}/${RUBY_BASE_NAME}'}${multiarch-'${rubylibprefix}/${arch}'}
AC_ARG_WITH(rubyarchprefix,
AS_HELP_STRING([--with-rubyarchprefix=DIR],
@@ -3889,56 +3886,62 @@ AC_ARG_WITH(ridir,
@@ -4228,56 +4225,62 @@ AC_ARG_WITH(ridir,
AC_SUBST(ridir)
AC_SUBST(RI_BASE_NAME)
@ -120,7 +120,7 @@ index 80b137e380..63cd3b4f8b 100644
AS_IF([test "${LOAD_RELATIVE+set}"], [
AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE)
@@ -3955,6 +3958,7 @@ AC_SUBST(sitearchincludedir)dnl
@@ -4294,6 +4297,7 @@ AC_SUBST(sitearchincludedir)dnl
AC_SUBST(arch)dnl
AC_SUBST(sitearch)dnl
AC_SUBST(ruby_version)dnl
@ -165,66 +165,74 @@ index 970cb91..5bf8230 100644
- version = RbConfig::CONFIG['ruby_version']
+ version = RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version']
BASE = File.join RbConfig::CONFIG['ridir'], version
BASE = if RbConfig::CONFIG.key? 'ridir' then
File.join RbConfig::CONFIG['ridir'], version
diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb
index d4c110e..d39c9a6 100755
--- a/tool/rbinstall.rb
+++ b/tool/rbinstall.rb
@@ -439,7 +439,7 @@ def CONFIG.[](name, mandatory = false)
@@ -421,7 +421,7 @@ def CONFIG.[](name, mandatory = false)
install?(:doc, :rdoc) do
if $rdocdir
- ridatadir = File.join(CONFIG['ridir'], CONFIG['ruby_version'], "system")
+ ridatadir = File.join(CONFIG['ridir'], CONFIG['ruby_version_dir_name'] || CONFIG['ruby_version'], "system")
prepare "rdoc", ridatadir
install_recursive($rdocdir, ridatadir, :no_install => rdoc_noinst, :mode => $data_mode)
install_recursive($rdocdir, ridatadir, :mode => $data_mode)
end
--
2.23.0
2.1.0
From 9f0ec0233f618cbb862629816b22491c3df79578 Mon Sep 17 00:00:00 2001
From f8d136f9a46d1fe87eba622ab9665935d05e981b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADt=20Ondruch?= <vondruch@redhat.com>
Date: Tue, 31 Mar 2015 16:37:44 +0200
Subject: [PATCH 3/4] Add ruby_version_dir_name support for RubyGems.
---
lib/rubygems/defaults.rb | 9 +++++----
test/rubygems/test_gem.rb | 5 +++--
2 files changed, 8 insertions(+), 6 deletions(-)
lib/rubygems/defaults.rb | 11 ++++++-----
test/rubygems/test_gem.rb | 5 +++--
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb
index d4ff4a262c..3f9a5bf590 100644
index 55ca080..75eea2b 100644
--- a/lib/rubygems/defaults.rb
+++ b/lib/rubygems/defaults.rb
@@ -38,13 +38,13 @@ def self.default_dir
@@ -32,20 +32,20 @@ def self.default_dir
[
File.dirname(RbConfig::CONFIG['sitedir']),
'Gems',
- RbConfig::CONFIG['ruby_version'],
- RbConfig::CONFIG['ruby_version']
+ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version']
]
elsif RbConfig::CONFIG['rubylibprefix'] then
[
RbConfig::CONFIG['rubylibprefix'],
'gems',
- RbConfig::CONFIG['ruby_version']
+ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version']
]
else
[
RbConfig::CONFIG['rubylibprefix'],
RbConfig::CONFIG['libdir'],
ruby_engine,
'gems',
- RbConfig::CONFIG['ruby_version'],
- RbConfig::CONFIG['ruby_version']
+ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version']
]
end
@@ -117,7 +117,8 @@ def self.user_dir
gem_dir = File.join(Gem.user_home, ".gem")
gem_dir = File.join(Gem.data_home, "gem") unless File.exist?(gem_dir)
parts = [gem_dir, ruby_engine]
@@ -75,7 +75,8 @@ def self.default_rubygems_dirs
def self.user_dir
parts = [Gem.user_home, '.gem', ruby_engine]
- parts << RbConfig::CONFIG['ruby_version'] unless RbConfig::CONFIG['ruby_version'].empty?
+ ruby_version_dir_name = RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version']
+ parts << ruby_version_dir_name unless ruby_version_dir_name.empty?
File.join parts
end
@@ -252,7 +253,7 @@ def self.vendor_dir # :nodoc:
@@ -172,7 +173,7 @@ def self.vendor_dir # :nodoc:
return nil unless RbConfig::CONFIG.key? 'vendordir'
File.join RbConfig::CONFIG['vendordir'], 'gems',
@ -234,10 +242,10 @@ index d4ff4a262c..3f9a5bf590 100644
##
diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb
index b25068405d..e9fef4a311 100644
index 0428bea..b6e090e 100644
--- a/test/rubygems/test_gem.rb
+++ b/test/rubygems/test_gem.rb
@@ -1440,7 +1440,8 @@ def test_self_use_paths
@@ -1191,7 +1191,8 @@ def test_self_use_paths
def test_self_user_dir
parts = [@userhome, '.gem', Gem.ruby_engine]
@ -245,17 +253,17 @@ index b25068405d..e9fef4a311 100644
+ ruby_version_dir_name = RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version']
+ parts << ruby_version_dir_name unless ruby_version_dir_name.empty?
FileUtils.mkdir_p File.join(parts)
@@ -1516,7 +1517,7 @@ def test_self_vendor_dir
vendordir(File.join(@tempdir, 'vendor')) do
expected =
File.join RbConfig::CONFIG['vendordir'], 'gems',
- RbConfig::CONFIG['ruby_version']
+ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version']
assert_equal expected, Gem.vendor_dir
end
assert_equal File.join(parts), Gem.user_dir
end
@@ -1318,7 +1319,7 @@ def test_self_user_home_user_drive_and_path
def test_self_vendor_dir
expected =
File.join RbConfig::CONFIG['vendordir'], 'gems',
- RbConfig::CONFIG['ruby_version']
+ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version']
assert_equal expected, Gem.vendor_dir
end
--
2.1.0
@ -274,15 +282,15 @@ diff --git a/configure.ac b/configure.ac
index a00f2b6776..999e2d6d5d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -107,7 +107,7 @@ RUBY_BASE_NAME=`echo ruby | sed "$program_transform_name"`
@@ -164,7 +164,7 @@ RUBY_BASE_NAME=`echo ruby | sed "$program_transform_name"`
RUBYW_BASE_NAME=`echo rubyw | sed "$program_transform_name"`
AC_SUBST(RUBY_BASE_NAME)
AC_SUBST(RUBYW_BASE_NAME)
-AC_SUBST(RUBY_VERSION_NAME, '${RUBY_BASE_NAME}-${ruby_version}')
+AC_SUBST(RUBY_VERSION_NAME, '${RUBY_BASE_NAME}-${ruby_version_dir_name}')
dnl checks for alternative programs
AC_CANONICAL_BUILD
AC_CANONICAL_TARGET
test x"$target_alias" = x &&
--
2.1.0

@ -0,0 +1,80 @@
From 60eb961c25f801ee43ca1be9393ab2f0a0546677 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADt=20Ondruch?= <vondruch@redhat.com>
Date: Tue, 19 Dec 2017 14:00:20 +0100
Subject: [PATCH] Add Gem.operating_system_defaults to allow packagers to
override defaults.
This change allows Ruby packagers to override defaults and lazily query
them.
This is very much the same change as #1644 to treat the
operating_system defaults the same way as platform defaults.
---
lib/rubygems/config_file.rb | 2 +-
lib/rubygems/defaults.rb | 21 ++++++++++++++++++++-
test/rubygems/test_gem.rb | 7 +++++++
3 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb
index a4efed0f5a..deee38e6d9 100644
--- a/lib/rubygems/config_file.rb
+++ b/lib/rubygems/config_file.rb
@@ -48,7 +48,7 @@ class Gem::ConfigFile
# For Ruby packagers to set configuration defaults. Set in
# rubygems/defaults/operating_system.rb
- OPERATING_SYSTEM_DEFAULTS = {}
+ OPERATING_SYSTEM_DEFAULTS = Gem.operating_system_defaults
##
# For Ruby implementers to set configuration defaults. Set in
diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb
index 43d57fc808..b8222877ae 100644
--- a/lib/rubygems/defaults.rb
+++ b/lib/rubygems/defaults.rb
@@ -177,7 +177,26 @@ def self.vendor_dir # :nodoc:
end
##
- # Default options for gem commands.
+ # Default options for gem commands for Ruby packagers.
+ #
+ # The options here should be structured as an array of string "gem"
+ # command names as keys and a string of the default options as values.
+ #
+ # Example:
+ #
+ # def self.operating_system_defaults
+ # {
+ # 'install' => '--no-rdoc --no-ri --env-shebang',
+ # 'update' => '--no-rdoc --no-ri --env-shebang'
+ # }
+ # end
+
+ def self.operating_system_defaults
+ {}
+ end
+
+ ##
+ # Default options for gem commands for Ruby implementers.
#
# The options here should be structured as an array of string "gem"
# command names as keys and a string of the default options as values.
diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb
index 3225a05c6b..62b80c4945 100644
--- a/test/rubygems/test_gem.rb
+++ b/test/rubygems/test_gem.rb
@@ -1837,6 +1837,13 @@ def test_use_gemdeps_specific
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
end
+ def test_operating_system_defaults
+ operating_system_defaults = Gem.operating_system_defaults
+
+ assert operating_system_defaults != nil
+ assert operating_system_defaults.is_a? Hash
+ end
+
def test_platform_defaults
platform_defaults = Gem.platform_defaults

@ -0,0 +1,35 @@
From 51e2c91412a511196e58efea5b87c460b4fa6a20 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADt=20Ondruch?= <vondruch@redhat.com>
Date: Thu, 26 Jul 2018 13:17:52 +0200
Subject: [PATCH] Avoid need of C++ compiler to pass the test suite.
The test suite fails when C++ compiler is not available on the system:
~~~
TestGemExtCmakeBuilder#test_self_build:
Gem::InstallError: cmake failed, exit code 1
/builddir/build/BUILD/ruby-2.5.1/lib/rubygems/ext/builder.rb:92:in `run'
/builddir/build/BUILD/ruby-2.5.1/lib/rubygems/ext/cmake_builder.rb:10:in `build'
/builddir/build/BUILD/ruby-2.5.1/test/rubygems/test_gem_ext_cmake_builder.rb:37:in `block in test_self_build'
/builddir/build/BUILD/ruby-2.5.1/test/rubygems/test_gem_ext_cmake_builder.rb:36:in `chdir'
/builddir/build/BUILD/ruby-2.5.1/test/rubygems/test_gem_ext_cmake_builder.rb:36:in `test_self_build'
~~~
But there is nothing which would realy required C++. It is just CMake
default to check for C++.
---
test/rubygems/test_gem_ext_cmake_builder.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/rubygems/test_gem_ext_cmake_builder.rb b/test/rubygems/test_gem_ext_cmake_builder.rb
index 76d3cb2afe..2d449fc2fd 100644
--- a/test/rubygems/test_gem_ext_cmake_builder.rb
+++ b/test/rubygems/test_gem_ext_cmake_builder.rb
@@ -25,6 +25,7 @@ def test_self_build
File.open File.join(@ext, 'CMakeLists.txt'), 'w' do |cmakelists|
cmakelists.write <<-eo_cmake
cmake_minimum_required(VERSION 2.6)
+project(self_build LANGUAGES NONE)
install (FILES test.txt DESTINATION bin)
eo_cmake
end

@ -0,0 +1,46 @@
From 93e6364a848f00b34647b13063dceb854dfaa11e Mon Sep 17 00:00:00 2001
From: usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Wed, 28 Oct 2020 13:12:06 +0000
Subject: [PATCH] merge revision(s): 07786ed
* test/net/http/test_https.rb: Stop the error due to openssl 1.1.1h
On some environments that uses OpenSSL 1.1.1h, the two tests now fail.
http://rubyci.s3.amazonaws.com/android29-x86_64/ruby-master/log/20200924T062352Z.fail.html.gz
https://github.com/ruby/ruby/runs/1159288773?check_suite_focus=true
```
1) Failure:
TestNetHTTPS#test_get [/data/data/com.termux/files/home/cb/tmp/build/202 00924T062352Z/ruby/test/net/http/test_https.rb:47]:
<"0\x82\x03\xED0\x82\x02\xD5\xA0\x03..."> expected but was
<"0\x82\x03\xE30\x82\x02\xCB\xA0\x03...">.
```
Not sure why, but verify_callback now seems to receive only SERVER_CERT
but not CA_CERT.
It would be good to investigate the issue furthermore, but tentatively,
I want to stop the failures.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_5@67887 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
---
test/net/http/test_https.rb | 6 ++++--
diff --git a/test/net/http/test_https.rb b/test/net/http/test_https.rb
index c1d486470ae2..3a2341024121 100644
--- a/test/net/http/test_https.rb
+++ b/test/net/http/test_https.rb
@@ -44,8 +44,10 @@ def test_get
http.request_get("/") {|res|
assert_equal($test_net_http_data, res.body)
}
- assert_equal(CA_CERT.to_der, certs[0].to_der)
- assert_equal(SERVER_CERT.to_der, certs[1].to_der)
+ # TODO: OpenSSL 1.1.1h seems to yield only SERVER_CERT; need to check the incompatibility
+ certs.zip([SERVER_CERT, CA_CERT]) do |actual, expected|
+ assert_equal(expected.to_der, actual.to_der)
+ end
rescue SystemCallError
skip $!
end

@ -0,0 +1,78 @@
From 893949167bdb911c7db9fd59de85f288c09741e1 Mon Sep 17 00:00:00 2001
From: nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Sat, 15 Sep 2018 09:59:14 +0000
Subject: [PATCH] Fix issues detected by code analysis tool (mainly Coverity).
* Fix leaked storage in addr2line.c.
* Fix for "top_root" leaking the resource.
[Fix GH-1956]
From: Jun Aruga <jaruga@redhat.com>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64750 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
---
addr2line.c | 8 ++++++--
regcomp.c | 3 +++
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/addr2line.c b/addr2line.c
index 2c422cc1697a..b266e44d5d4b 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -593,11 +593,12 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
h = dlopen(NULL, RTLD_NOW|RTLD_LOCAL);
if (!h) continue;
s = dlsym(h, strtab + sym->st_name);
- if (!s) continue;
- if (dladdr(s, &info)) {
+ if (s && dladdr(s, &info)) {
dladdr_fbase = (uintptr_t)info.dli_fbase;
+ dlclose(h);
break;
}
+ dlclose(h);
}
if (ehdr->e_type == ET_EXEC) {
obj->base_addr = 0;
@@ -655,6 +656,9 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
finish:
return dladdr_fbase;
fail:
+ if (file != NULL) {
+ munmap(file, (size_t)filesize);
+ }
return (uintptr_t)-1;
}
diff --git a/regcomp.c b/regcomp.c
index 0f6bee60d576..df7f73bac501 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -3596,6 +3596,7 @@ expand_case_fold_string(Node* node, regex_t* reg)
if (n == 0 || varlen == 0) {
if (IS_NULL(snode)) {
if (IS_NULL(root) && IS_NOT_NULL(prev_node)) {
+ onig_node_free(top_root);
top_root = root = onig_node_list_add(NULL_NODE, prev_node);
if (IS_NULL(root)) {
onig_node_free(prev_node);
@@ -3627,6 +3628,7 @@ expand_case_fold_string(Node* node, regex_t* reg)
}
}
if (IS_NULL(root) && IS_NOT_NULL(prev_node)) {
+ onig_node_free(top_root);
top_root = root = onig_node_list_add(NULL_NODE, prev_node);
if (IS_NULL(root)) {
onig_node_free(prev_node);
@@ -3677,6 +3679,7 @@ expand_case_fold_string(Node* node, regex_t* reg)
if (r != 0) goto mem_err;
if (IS_NOT_NULL(prev_node) && IS_NULL(root)) {
+ onig_node_free(top_root);
top_root = root = onig_node_list_add(NULL_NODE, prev_node);
if (IS_NULL(root)) {
onig_node_free(srem);
--
2.21.0

@ -0,0 +1,182 @@
From f46bac1f3e8634e24c747d06b28e11b874f1e488 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Thu, 16 Aug 2018 19:40:48 +0900
Subject: [PATCH] config: support .include directive
OpenSSL 1.1.1 introduces a new '.include' directive. Update our config
parser to support that.
As mentioned in the referenced GitHub issue, we should use the OpenSSL
API instead of implementing the parsing logic ourselves, but it will
need backwards-incompatible changes which we can't backport to stable
versions. So continue to use the Ruby implementation for now.
Reference: https://github.com/ruby/openssl/issues/208
---
ext/openssl/lib/openssl/config.rb | 54 ++++++++++++++++++++++++++++---------------
test/openssl/test_config.rb | 54 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 90 insertions(+), 18 deletions(-)
diff --git a/ext/openssl/lib/openssl/config.rb b/ext/openssl/lib/openssl/config.rb
index 88225451..ba3a54c8 100644
--- a/ext/openssl/lib/openssl/config.rb
+++ b/ext/openssl/lib/openssl/config.rb
@@ -77,29 +77,44 @@ def get_key_string(data, section, key) # :nodoc:
def parse_config_lines(io)
section = 'default'
data = {section => {}}
- while definition = get_definition(io)
+ io_stack = [io]
+ while definition = get_definition(io_stack)
definition = clear_comments(definition)
next if definition.empty?
- if definition[0] == ?[
+ case definition
+ when /\A\[/
if /\[([^\]]*)\]/ =~ definition
section = $1.strip
data[section] ||= {}
else
raise ConfigError, "missing close square bracket"
end
- else
- if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
- if $2
- section = $1
- key = $2
- else
- key = $1
+ when /\A\.include (.+)\z/
+ path = $1
+ if File.directory?(path)
+ files = Dir.glob(File.join(path, "*.{cnf,conf}"), File::FNM_EXTGLOB)
+ else
+ files = [path]
+ end
+
+ files.each do |filename|
+ begin
+ io_stack << StringIO.new(File.read(filename))
+ rescue
+ raise ConfigError, "could not include file '%s'" % filename
end
- value = unescape_value(data, section, $3)
- (data[section] ||= {})[key] = value.strip
+ end
+ when /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/
+ if $2
+ section = $1
+ key = $2
else
- raise ConfigError, "missing equal sign"
+ key = $1
end
+ value = unescape_value(data, section, $3)
+ (data[section] ||= {})[key] = value.strip
+ else
+ raise ConfigError, "missing equal sign"
end
end
data
@@ -212,10 +227,10 @@ def clear_comments(line)
scanned.join
end
- def get_definition(io)
- if line = get_line(io)
+ def get_definition(io_stack)
+ if line = get_line(io_stack)
while /[^\\]\\\z/ =~ line
- if extra = get_line(io)
+ if extra = get_line(io_stack)
line += extra
else
break
@@ -225,9 +240,12 @@ def get_definition(io)
end
end
- def get_line(io)
- if line = io.gets
- line.gsub(/[\r\n]*/, '')
+ def get_line(io_stack)
+ while io = io_stack.last
+ if line = io.gets
+ return line.gsub(/[\r\n]*/, '')
+ end
+ io_stack.pop
end
end
end
diff --git a/test/openssl/test_config.rb b/test/openssl/test_config.rb
index 99dcc497..5653b5d0 100644
--- a/test/openssl/test_config.rb
+++ b/test/openssl/test_config.rb
@@ -120,6 +120,49 @@ def test_s_parse_format
assert_equal("error in line 7: missing close square bracket", excn.message)
end
+ def test_s_parse_include
+ in_tmpdir("ossl-config-include-test") do |dir|
+ Dir.mkdir("child")
+ File.write("child/a.conf", <<~__EOC__)
+ [default]
+ file-a = a.conf
+ [sec-a]
+ a = 123
+ __EOC__
+ File.write("child/b.cnf", <<~__EOC__)
+ [default]
+ file-b = b.cnf
+ [sec-b]
+ b = 123
+ __EOC__
+ File.write("include-child.conf", <<~__EOC__)
+ key_outside_section = value_a
+ .include child
+ __EOC__
+
+ include_file = <<~__EOC__
+ [default]
+ file-main = unnamed
+ [sec-main]
+ main = 123
+ .include include-child.conf
+ __EOC__
+
+ # Include a file by relative path
+ c1 = OpenSSL::Config.parse(include_file)
+ assert_equal(["default", "sec-a", "sec-b", "sec-main"], c1.sections.sort)
+ assert_equal(["file-main", "file-a", "file-b"], c1["default"].keys)
+ assert_equal({"a" => "123"}, c1["sec-a"])
+ assert_equal({"b" => "123"}, c1["sec-b"])
+ assert_equal({"main" => "123", "key_outside_section" => "value_a"}, c1["sec-main"])
+
+ # Relative paths are from the working directory
+ assert_raise(OpenSSL::ConfigError) do
+ Dir.chdir("child") { OpenSSL::Config.parse(include_file) }
+ end
+ end
+ end
+
def test_s_load
# alias of new
c = OpenSSL::Config.load
@@ -299,6 +342,17 @@ def test_clone
@it['newsection'] = {'a' => 'b'}
assert_not_equal(@it.sections.sort, c.sections.sort)
end
+
+ private
+
+ def in_tmpdir(*args)
+ Dir.mktmpdir(*args) do |dir|
+ dir = File.realpath(dir)
+ Dir.chdir(dir) do
+ yield dir
+ end
+ end
+ end
end
end

@ -0,0 +1,43 @@
From c8ccdbfe1e45cb3b832109d644296c0a3b3e0b59 Mon Sep 17 00:00:00 2001
From: nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Sun, 2 Sep 2018 03:49:31 +0000
Subject: [PATCH] configure.ac: -fstack-protector-strong
* configure.ac: use -fstack-protector-strong if available instead of
-fstack-protector conditionally. [ruby-core:88788] [Misc #15053]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64614 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
---
configure.ac | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/configure.ac b/configure.ac
index 9328fa532de0..b8ee57239215 100644
--- a/configure.ac
+++ b/configure.ac
@@ -837,15 +837,18 @@ AS_IF([test "$GCC" = yes], [
stack_protector=no
])
AS_IF([test -z "${stack_protector+set}"], [
- RUBY_TRY_CFLAGS(-fstack-protector, [stack_protector=yes], [stack_protector=no])
- AS_IF([test "x$stack_protector" = xyes], [
- RUBY_TRY_LDFLAGS(-fstack-protector, [], [stack_protector=broken])
+ AS_FOR(option, opt, [-fstack-protector-strong -fstack-protector], [
+ RUBY_TRY_CFLAGS(option, [stack_protector=yes])
+ AS_IF([test "x$stack_protector" = xyes], [
+ RUBY_TRY_LDFLAGS(option, [], [stack_protector=])
+ ])
+ AS_IF([test "x$stack_protector" = xyes], [stack_protector=option; break])
])
])
- AS_IF([test "x$stack_protector" = xyes], [
- RUBY_APPEND_OPTION(XCFLAGS, -fstack-protector)
- RUBY_APPEND_OPTION(XLDFLAGS, -fstack-protector)
- RUBY_APPEND_OPTION(LDFLAGS, -fstack-protector)
+ AS_CASE(["$stack_protector"], [-*], [
+ RUBY_APPEND_OPTION(XCFLAGS, $stack_protector)
+ RUBY_APPEND_OPTION(XLDFLAGS, $stack_protector)
+ RUBY_APPEND_OPTION(LDFLAGS, $stack_protector)
])
AS_CASE("${compress_debug_sections:-zlib}",

@ -0,0 +1,177 @@
From bb3db69e2a0c210cc3a63940622db96a97eb7947 Mon Sep 17 00:00:00 2001
From: nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Fri, 2 Mar 2018 01:37:53 +0000
Subject: [PATCH] configure.ac: library options to MAINLIBS
* configure.ac (MAINLIBS): moved library options for main program
and static libruby, and append MAINLIBS to LIBRUBYARG_STATIC, as
these libraries are not needed for linking to shared libruby.
[ruby-core:85882] [Bug #14422]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62627 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
---
configure.ac | 33 +++++++++++++++------------------
template/ruby.pc.in | 1 +
win32/Makefile.sub | 6 ++++--
3 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/configure.ac b/configure.ac
index aebbae1969a5..733a0c992fd7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -10,6 +10,7 @@ AC_DISABLE_OPTION_CHECKING
AC_ARG_VAR([cflags], [additional CFLAGS])
AC_ARG_VAR([cppflags], [additional CPPFLAGS])
AC_ARG_VAR([cxxflags], [additional CXXFLAGS])
+ORIG_LIBS=$LIBS
AC_DEFUN([RUBY_RM_RECURSIVE], [
m4_version_prereq([2.70], [-1], [
@@ -2939,13 +2940,11 @@ AS_IF([test x"$enable_pthread" = xyes], [
AC_DEFINE(_THREAD_SAFE)
AC_DEFINE(HAVE_LIBPTHREAD)
AC_CHECK_HEADERS(pthread_np.h, [], [], [@%:@include <pthread.h>])
- AS_CASE([$pthread_lib],
- [c], [],
- [root], [],
- [c_r], [MAINLIBS="-pthread $MAINLIBS"],
- [AS_CASE(["$target_os"],
- [openbsd*|mirbsd*], [LIBS="-pthread $LIBS"],
- [LIBS="-l$pthread_lib $LIBS"])])
+ AS_CASE(["$pthread_lib:$target_os"],
+ [c:*], [],
+ [root:*], [],
+ [c_r:*|*:openbsd*|*:mirbsd*], [LIBS="-pthread $LIBS"],
+ [LIBS="-l$pthread_lib $LIBS"])
], [
AC_MSG_WARN("Don't know how to find pthread library on your system -- thread support disabled")
])
@@ -3624,7 +3623,7 @@ LIBRUBY_A='lib$(RUBY_SO_NAME)-static.a'
LIBRUBY='$(LIBRUBY_A)'
LIBRUBYARG_STATIC='-l$(RUBY_SO_NAME)-static'
LIBRUBYARG='$(LIBRUBYARG_STATIC)'
-SOLIBS=
+SOLIBS='$(MAINLIBS)'
AS_CASE(["$target_os"],
[cygwin*|mingw*|haiku*|darwin*], [
@@ -3690,9 +3689,6 @@ AS_CASE("$enable_shared", [yes], [
LIBRUBY_RELATIVE=no
test -z "$CCDLFLAGS" || CFLAGS="$CFLAGS $CCDLFLAGS"
ENABLE_SHARED=yes
- AS_IF([test "$rb_cv_binary_elf" = yes], [
- SOLIBS='$(LIBS)'
- ])
# libdir can be overridden in config.site file (on OpenSUSE at least).
libdir_basename=lib
@@ -3727,7 +3723,6 @@ AS_CASE("$enable_shared", [yes], [
])
],
[freebsd*|dragonfly*], [
- SOLIBS='$(LIBS)'
LIBRUBY_SO='lib$(RUBY_SO_NAME).$(SOEXT).$(MAJOR)$(MINOR)'
LIBRUBY_SONAME='$(LIBRUBY_SO)'
AS_IF([test "$rb_cv_binary_elf" != "yes" ], [
@@ -3736,7 +3731,6 @@ AS_CASE("$enable_shared", [yes], [
])
],
[netbsd*], [
- SOLIBS='$(LIBS)'
LIBRUBY_SONAME='lib$(RUBY_SO_NAME).$(SOEXT).$(MAJOR)$(MINOR)'
LIBRUBY_SO="${LIBRUBY_SONAME}"'.$(TEENY)'
RUBY_APPEND_OPTIONS(LIBRUBY_DLDFLAGS, ['-Wl,-soname,$(LIBRUBY_SONAME)' "$LDFLAGS_OPTDIR"])
@@ -3747,11 +3741,9 @@ AS_CASE("$enable_shared", [yes], [
])
],
[openbsd*|mirbsd*], [
- SOLIBS='$(LIBS)'
LIBRUBY_SO='lib$(RUBY_SO_NAME).$(SOEXT).$(MAJOR).'`expr ${MINOR} \* 10 + ${TEENY}`
],
[solaris*], [
- SOLIBS='$(LIBS)'
LIBRUBY_SO='lib$(RUBY_SO_NAME).$(SOEXT).$(MAJOR)'
LIBRUBY_SONAME='lib$(RUBY_SO_NAME).$(SOEXT).$(RUBY_PROGRAM_VERSION)'
LIBRUBY_ALIASES='$(LIBRUBY_SONAME) lib$(RUBY_SO_NAME).$(SOEXT)'
@@ -3769,7 +3761,7 @@ AS_CASE("$enable_shared", [yes], [
[aix*], [
RUBY_APPEND_OPTIONS(LIBRUBY_DLDFLAGS, ["${linker_flag}-bnoentry" "$XLDFLAGS" "$LDFLAGS_OPTDIR"])
LIBRUBYARG_SHARED='-L${libdir} -l${RUBY_SO_NAME}'
- SOLIBS='-lm -lc'
+ LIBS="$LIBS -lm -lc"
],
[darwin*], [
LIBRUBY_LDSHARED='$(CC) -dynamiclib'
@@ -3789,7 +3781,6 @@ AS_CASE("$enable_shared", [yes], [
LIBRUBY_SO='lib$(RUBY_SO_NAME).$(SOEXT)'
LIBRUBY_SONAME='lib$(RUBY_BASE_NAME).$(RUBY_API_VERSION).$(SOEXT)'
LIBRUBY_ALIASES='$(LIBRUBY_SONAME) lib$(RUBY_INSTALL_NAME).$(SOEXT)'
- SOLIBS='$(LIBS)'
],
[interix*], [
LIBRUBYARG_SHARED='-L. -L${libdir} -l$(RUBY_SO_NAME)'
@@ -4032,7 +4023,6 @@ AS_CASE(["$target_os"],
])
LIBRUBY_ALIASES=''
FIRSTMAKEFILE=GNUmakefile:cygwin/GNUmakefile.in
- SOLIBS='$(LIBS)'
AS_IF([test x"$enable_shared" = xyes], [
LIBRUBY='lib$(RUBY_SO_NAME).dll.a'
], [
@@ -4132,6 +4122,13 @@ AS_IF([test "${universal_binary-no}" = yes ], [
[rb_cv_architecture_available=yes], [rb_cv_architecture_available=no]))
])
+MAINLIBS="$LIBS"
+LIBS=$ORIG_LIBS
+AS_IF([test -n "${LIBS}"], [
+ libspat=`echo "${LIBS}" | sed 's/[[][|.*$^]]/\\&/g;s/^ */ /;s/^ *$/ /'`
+ MAINFLAGS=`echo " $MAINLIBS " | sed "s|$libspat"'||;s/^ *//;s/ *$//'`
+])
+LIBRUBYARG_STATIC="${LIBRUBYARG_STATIC} \$(MAINLIBS)"
CPPFLAGS="$CPPFLAGS "'$(DEFS)'
test -z "$CPPFLAGS" || CPPFLAGS="$CPPFLAGS "; CPPFLAGS="$CPPFLAGS"'${cppflags}'
AS_IF([test -n "${cflags+set}"], [
diff --git a/template/ruby.pc.in b/template/ruby.pc.in
index d874f92c3b20..7ce4461c05df 100644
--- a/template/ruby.pc.in
+++ b/template/ruby.pc.in
@@ -39,6 +39,7 @@ sitehdrdir=@sitehdrdir@
rubyarchhdrdir=@rubyarchhdrdir@
vendorarchhdrdir=@vendorarchhdrdir@
sitearchhdrdir=@sitearchhdrdir@
+MAINLIBS=@MAINLIBS@
SOEXT=@SOEXT@
LIBPATH=@LIBPATH@
LIBRUBY_A=@LIBRUBY_A@
diff --git a/win32/Makefile.sub b/win32/Makefile.sub
index 8673c121641e..f8316cccb68e 100644
--- a/win32/Makefile.sub
+++ b/win32/Makefile.sub
@@ -279,6 +279,7 @@ MJIT_DEBUGFLAGS = $(DEBUGFLAGS)
CPPFLAGS = $(DEFS) $(ARCHDEFS) $(CPPFLAGS)
DLDFLAGS = $(LDFLAGS) -dll
+MAINLIBS = $(LIBS)
SOLIBS =
RCFILES = $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(RUBY_SO_NAME).rc
!ifndef RCFLAGS
@@ -821,7 +822,8 @@ s,@CPPFLAGS@,$(CPPFLAGS),;t t
s,@CXXFLAGS@,$(CXXFLAGS),;t t
s,@FFLAGS@,$(FFLAGS),;t t
s,@LDFLAGS@,$(LDFLAGS),;t t
-s,@LIBS@,$(LIBS),;t t
+s,@LIBS@,,;t t
+s,@MAINLIBS@,$(MAINLIBS),;t t
s,@exec_prefix@,$${prefix},;t t
s,@prefix@,$(prefix),;t t
s,@program_transform_name@,s,.*,$(PROGRAM_PREFIX)&$(PROGRAM_SUFFIX),,;t t
@@ -909,7 +911,7 @@ s,@LIBRUBY_SO@,$$(RUBY_SO_NAME).dll,;t t
s,@LIBRUBY_ALIASES@,$(LIBRUBY_ALIASES),;t t
s,@LIBRUBY@,$$(RUBY_SO_NAME).lib,;t t
s,@LIBRUBYARG@,$$(LIBRUBYARG_SHARED),;t t
-s,@LIBRUBYARG_STATIC@,$$(LIBRUBY_A),;t t
+s,@LIBRUBYARG_STATIC@,$$(LIBRUBY_A) $$(MAINLIBS),;t t
s,@LIBRUBYARG_SHARED@,$$(LIBRUBY),;t t
s,@SOLIBS@,$(SOLIBS),;t t
s,@DLDLIBS@,$(DLDLIBS),;t t

@ -0,0 +1,69 @@
From 9d98bfe7f1abdeda5aedf9404588104980ee7a86 Mon Sep 17 00:00:00 2001
From: aycabta <aycabta@gmail.com>
Date: Mon, 15 Jan 2018 22:32:56 +0900
Subject: [PATCH] Check nil text token
Sometimes :on_ignored_nl token has nil text. This commit checks and
bypasses the token.
---
lib/rdoc/parser/ripper_state_lex.rb | 4 +++-
test/test_rdoc_parser_ruby.rb | 30 +++++++++++++++++++++++++++++
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/lib/rdoc/parser/ripper_state_lex.rb b/lib/rdoc/parser/ripper_state_lex.rb
index 2a285b97a4..c56cef46ee 100644
--- a/lib/rdoc/parser/ripper_state_lex.rb
+++ b/lib/rdoc/parser/ripper_state_lex.rb
@@ -330,8 +330,10 @@ class RDoc::RipperStateLex
@heredoc_queue << retrieve_heredoc_info(tk)
@inner_lex.lex_state = EXPR_END unless RIPPER_HAS_LEX_STATE
when :on_nl, :on_ignored_nl, :on_comment, :on_heredoc_end then
- unless @heredoc_queue.empty?
+ if !@heredoc_queue.empty?
get_heredoc_tk(*@heredoc_queue.shift)
+ elsif tk[:text].nil? # :on_ignored_nl sometimes gives nil
+ tk[:text] = ''
end
when :on_words_beg then
tk = get_words_tk(tk)
diff --git a/test/rdoc/test_rdoc_parser_ruby.rb b/test/rdoc/test_rdoc_parser_ruby.rb
index 833ed2cc74..c9d57021ce 100644
--- a/test/rdoc/test_rdoc_parser_ruby.rb
+++ b/test/rdoc/test_rdoc_parser_ruby.rb
@@ -306,6 +306,36 @@ def sum(n)
assert_equal @top_level, sum.file
end
+ def test_parse_on_ignored_nl_with_nil_text
+ util_parser <<ruby
+class Foo
+ def meth
+ variable # comment
+ .chain
+ end
+end
+ruby
+
+ expected = <<EXPECTED
+<span class="ruby-keyword">def</span> <span class="ruby-identifier ruby-title">meth</span>
+ <span class="ruby-identifier">variable</span> <span class="ruby-comment"># comment</span>
+ .<span class="ruby-identifier">chain</span>
+<span class="ruby-keyword">end</span>
+EXPECTED
+ expected = expected.rstrip
+
+ @parser.scan
+
+ foo = @store.find_class_named 'Foo'
+ meth = foo.method_list.first
+
+ assert_equal 'meth', meth.name
+ assert_equal @top_level, meth.file
+
+ markup_code = meth.markup_code.sub(/^.*\n/, '')
+ assert_equal expected, markup_code
+ end
+
def test_parse_alias
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level

@ -0,0 +1,214 @@
From 091459248d3ce814e10d50cc4421f0c0454ef61f Mon Sep 17 00:00:00 2001
From: "Bernhard M. Wiedemann" <bwiedemann@suse.de>
Date: Sun, 30 Apr 2017 22:47:40 +0200
Subject: [PATCH 1/4] created.rid: use SOURCE_DATE_EPOCH
use SOURCE_DATE_EPOCH instead of current time in created.rid top line
to enable reproducible builds of ruby docs
See https://reproducible-builds.org/ for why this is good
and https://reproducible-builds.org/specs/source-date-epoch/
for the definition of this variable.
---
lib/rdoc/rdoc.rb | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index 68775c8be1..a2711fbbd1 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -232,6 +232,9 @@ def store= store
def update_output_dir(op_dir, time, last = {})
return if @options.dry_run or not @options.update_output_dir
+ unless ENV['SOURCE_DATE_EPOCH'].nil?
+ time = Time.at(ENV['SOURCE_DATE_EPOCH'].to_i).gmtime
+ end
open output_flag_file(op_dir), "w" do |f|
f.puts time.rfc2822
--
2.21.0
From 73a935e9fa63b056ea0be69c0c923afdfb4d88da Mon Sep 17 00:00:00 2001
From: "Bernhard M. Wiedemann" <bwiedemann@suse.de>
Date: Thu, 14 Dec 2017 10:54:54 +0100
Subject: [PATCH 2/4] Do not store current timestamps in gz headers
to enable reproducible builds of rdoc
Normally, 0 would be the preferred value to indicate "no date"
but that value is handled differently in Zlib::GzipWriter
to put in the current time
---
lib/rdoc/generator/json_index.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/rdoc/generator/json_index.rb b/lib/rdoc/generator/json_index.rb
index e4cfe967c6..a059a5d4d0 100644
--- a/lib/rdoc/generator/json_index.rb
+++ b/lib/rdoc/generator/json_index.rb
@@ -175,7 +175,7 @@ def generate_gzipped
debug_msg "Writing gzipped search index to %s" % outfile
Zlib::GzipWriter.open(outfile) do |gz|
- gz.mtime = File.mtime(search_index_file)
+ gz.mtime = 1 # make output reproducible
gz.orig_name = search_index_file.basename.to_s
gz.write search_index
gz.close
@@ -193,7 +193,7 @@ def generate_gzipped
debug_msg "Writing gzipped file to %s" % outfile
Zlib::GzipWriter.open(outfile) do |gz|
- gz.mtime = File.mtime(dest)
+ gz.mtime = 1 # make output reproducible
gz.orig_name = dest.basename.to_s
gz.write data
gz.close
--
2.21.0
From 1b34b337b72918e83c3b952eed6998ad47974960 Mon Sep 17 00:00:00 2001
From: aycabta <aycabta@gmail.com>
Date: Sat, 27 Jan 2018 14:37:42 +0900
Subject: [PATCH 3/4] Improve reproducible builds for .js and .js.gz files
The mtime for search_index.js.gz should be updated because it's
generated dynamically. So uses SOURCE_DATE_EPOCH after
RDoc::Generator::JsonIndex#generate creates index file.
FileUtils.install in RDoc::Generator::JsonIndex#generate with :preserve
option because the mtime value is based on original .js file.
---
lib/rdoc/generator/json_index.rb | 9 +++++---
test/rdoc/test_rdoc_generator_json_index.rb | 25 ++++++++++++++++++++-
2 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/lib/rdoc/generator/json_index.rb b/lib/rdoc/generator/json_index.rb
index a059a5d4d0..3a1000033d 100644
--- a/lib/rdoc/generator/json_index.rb
+++ b/lib/rdoc/generator/json_index.rb
@@ -147,12 +147,15 @@ def generate
JSON.dump data, io, 0
end
+ unless ENV['SOURCE_DATE_EPOCH'].nil?
+ index_file.utime index_file.atime, Time.at(ENV['SOURCE_DATE_EPOCH'].to_i).gmtime
+ end
Dir.chdir @template_dir do
Dir['**/*.js'].each do |source|
dest = File.join out_dir, source
- FileUtils.install source, dest, :mode => 0644, :verbose => $DEBUG_RDOC
+ FileUtils.install source, dest, :mode => 0644, :preserve => true, :verbose => $DEBUG_RDOC
end
end
end
@@ -175,7 +178,7 @@ def generate_gzipped
debug_msg "Writing gzipped search index to %s" % outfile
Zlib::GzipWriter.open(outfile) do |gz|
- gz.mtime = 1 # make output reproducible
+ gz.mtime = File.mtime(search_index_file)
gz.orig_name = search_index_file.basename.to_s
gz.write search_index
gz.close
@@ -193,7 +196,7 @@ def generate_gzipped
debug_msg "Writing gzipped file to %s" % outfile
Zlib::GzipWriter.open(outfile) do |gz|
- gz.mtime = 1 # make output reproducible
+ gz.mtime = File.mtime(dest)
gz.orig_name = dest.basename.to_s
gz.write data
gz.close
diff --git a/test/rdoc/test_rdoc_generator_json_index.rb b/test/rdoc/test_rdoc_generator_json_index.rb
index 6cb5463d29..65e7f087cc 100644
--- a/test/rdoc/test_rdoc_generator_json_index.rb
+++ b/test/rdoc/test_rdoc_generator_json_index.rb
@@ -8,7 +8,7 @@ class TestRDocGeneratorJsonIndex < RDoc::TestCase
def setup
super
- @tmpdir = File.join Dir.tmpdir, "test_rdoc_generator_darkfish_#{$$}"
+ @tmpdir = Dir.mktmpdir "test_rdoc_generator_darkfish_#{$$}_"
FileUtils.mkdir_p @tmpdir
@options = RDoc::Options.new
@@ -89,12 +89,21 @@ def test_file_dir
end
def test_generate
+ now = Time.now
@g.generate
assert_file 'js/searcher.js'
assert_file 'js/navigation.js'
assert_file 'js/search_index.js'
+ orig_file = Pathname(File.join @pwd, 'lib/rdoc/generator/template/json_index/js/navigation.js')
+ generated_file = Pathname(File.join @tmpdir, 'js/navigation.js')
+ assert_equal orig_file.mtime, generated_file.mtime
+ assert generated_file.mtime < now, '.js files should be the same timestamp'
+
+ generated_search_index = Pathname(File.join @tmpdir, 'js/search_index.js')
+ assert generated_search_index.mtime > (now - 1), 'search_index.js should be generated timestamp'
+
json = File.read 'js/search_index.js'
json =~ /\Avar search_data = /
@@ -137,6 +146,20 @@ def test_generate
assert_equal expected, index
end
+ def test_generate_search_index_with_reproducible_builds
+ backup_epoch = ENV['SOURCE_DATE_EPOCH']
+ ruby_birthday = Time.parse 'Wed, 24 Feb 1993 21:00:00 +0900'
+ ENV['SOURCE_DATE_EPOCH'] = ruby_birthday.to_i.to_s
+
+ @g.generate
+
+ assert_file 'js/search_index.js'
+ generated_search_index = Pathname(File.join @tmpdir, 'js/search_index.js')
+ assert_equal ruby_birthday, generated_search_index.mtime
+
+ ENV['SOURCE_DATE_EPOCH'] = backup_epoch
+ end
+
def test_generate_gzipped
begin
require 'zlib'
--
2.21.0
From 74c1e201f2146e7175e74d6fc0b9386c2e95210f Mon Sep 17 00:00:00 2001
From: aycabta <aycabta@gmail.com>
Date: Sat, 27 Jan 2018 17:54:31 +0900
Subject: [PATCH 4/4] Use dirty hack on JRuby for MiniTest 4
---
test/rdoc/test_rdoc_generator_json_index.rb | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/test/rdoc/test_rdoc_generator_json_index.rb b/test/rdoc/test_rdoc_generator_json_index.rb
index 65e7f087cc..714d496195 100644
--- a/test/rdoc/test_rdoc_generator_json_index.rb
+++ b/test/rdoc/test_rdoc_generator_json_index.rb
@@ -98,7 +98,11 @@ def test_generate
orig_file = Pathname(File.join @pwd, 'lib/rdoc/generator/template/json_index/js/navigation.js')
generated_file = Pathname(File.join @tmpdir, 'js/navigation.js')
- assert_equal orig_file.mtime, generated_file.mtime
+
+ # This is dirty hack on JRuby for MiniTest 4
+ assert orig_file.mtime.inspect == generated_file.mtime.inspect,
+ '.js files should be tha same timestamp of original'
+
assert generated_file.mtime < now, '.js files should be the same timestamp'
generated_search_index = Pathname(File.join @tmpdir, 'js/search_index.js')
--
2.21.0

@ -0,0 +1,486 @@
From b0bcb19cb4f95d260c5993df0aaa3667522fb99d Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Thu, 16 Aug 2018 20:54:47 +0900
Subject: [PATCH 1/2] test/openssl/test_pair: fix deadlock in
test_connect_accept_nonblock
Call IO.select with a timeout value and limit the number of retries to
prevent stacking forever.
Reference: https://github.com/ruby/openssl/issues/214
---
test/openssl/test_pair.rb | 51 ++++++++++++++++++++---------------------------
1 file changed, 22 insertions(+), 29 deletions(-)
diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb
index ea5f0dcf..eac3655e 100644
--- a/test/openssl/test_pair.rb
+++ b/test/openssl/test_pair.rb
@@ -442,7 +442,7 @@ def test_connect_accept_nonblock_no_exception
end
def test_connect_accept_nonblock
- ctx = OpenSSL::SSL::SSLContext.new()
+ ctx = OpenSSL::SSL::SSLContext.new
ctx.cert = @svr_cert
ctx.key = @svr_key
ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") }
@@ -451,45 +451,38 @@ def test_connect_accept_nonblock
th = Thread.new {
s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx)
- s2.sync_close = true
- begin
+ 5.times {
+ begin
+ break s2.accept_nonblock
+ rescue IO::WaitReadable
+ IO.select([s2], nil, nil, 1)
+ rescue IO::WaitWritable
+ IO.select(nil, [s2], nil, 1)
+ end
sleep 0.2
- s2.accept_nonblock
+ }
+ }
+
+ s1 = OpenSSL::SSL::SSLSocket.new(sock1)
+ 5.times {
+ begin
+ break s1.connect_nonblock
rescue IO::WaitReadable
- IO.select([s2])
- retry
+ IO.select([s1], nil, nil, 1)
rescue IO::WaitWritable
- IO.select(nil, [s2])
- retry
+ IO.select(nil, [s1], nil, 1)
end
- s2
- }
-
- sleep 0.1
- ctx = OpenSSL::SSL::SSLContext.new()
- s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx)
- begin
sleep 0.2
- s1.connect_nonblock
- rescue IO::WaitReadable
- IO.select([s1])
- retry
- rescue IO::WaitWritable
- IO.select(nil, [s1])
- retry
- end
- s1.sync_close = true
+ }
s2 = th.value
s1.print "a\ndef"
assert_equal("a\n", s2.gets)
ensure
- th.join if th
- s1.close if s1 && !s1.closed?
- s2.close if s2 && !s2.closed?
- sock1.close if sock1 && !sock1.closed?
- sock2.close if sock2 && !sock2.closed?
+ sock1&.close
+ sock2&.close
+ th&.join
end
end
From 5ba99ad7ae1267ed964f53906530579299f3fcc6 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Thu, 16 Aug 2018 20:04:13 +0900
Subject: [PATCH 2/2] test: use larger keys for SSL tests
Some systems enforce a system-wide policy to restrict key sizes used in
SSL/TLS. Use larger ones if possible so that the test suite runs
successfully.
New PEM files test/openssl/fixtures/pkey/{dh-1,rsa-1,rsa-2,rsa-3}.pem are added
to the tree, and SSL tests now use them instead of the fixed-size keys.
Reference: https://github.com/ruby/openssl/issues/215
---
test/openssl/fixtures/pkey/dh-1.pem | 13 +++++++++
test/openssl/fixtures/pkey/rsa-1.pem | 51 ++++++++++++++++++++++++++++++++++++
test/openssl/fixtures/pkey/rsa-2.pem | 51 ++++++++++++++++++++++++++++++++++++
test/openssl/fixtures/pkey/rsa-3.pem | 51 ++++++++++++++++++++++++++++++++++++
test/openssl/test_pair.rb | 8 +++---
test/openssl/test_pkey_dh.rb | 8 +++---
test/openssl/test_ssl.rb | 11 ++++----
test/openssl/utils.rb | 14 +++++-----
8 files changed, 186 insertions(+), 21 deletions(-)
create mode 100644 test/openssl/fixtures/pkey/dh-1.pem
create mode 100644 test/openssl/fixtures/pkey/rsa-1.pem
create mode 100644 test/openssl/fixtures/pkey/rsa-2.pem
create mode 100644 test/openssl/fixtures/pkey/rsa-3.pem
diff --git a/test/openssl/fixtures/pkey/dh-1.pem b/test/openssl/fixtures/pkey/dh-1.pem
new file mode 100644
index 00000000..3340a6a1
--- /dev/null
+++ b/test/openssl/fixtures/pkey/dh-1.pem
@@ -0,0 +1,13 @@
+-----BEGIN DH PARAMETERS-----
+MIICCAKCAgEAvRzXYxY6L2DjeYmm1eowtMDu1it3j+VwFr6s6PRWzc1apMtztr9G
+xZ2mYndUAJLgNLO3n2fUDCYVMB6ZkcekW8Siocof3xWiMA6wqZ6uw0dsE3q7ZX+6
+TLjgSjaXeGvjutvuEwVrFeaUi83bMgfXN8ToxIQVprIF35sYFt6fpbFATKfW7qqi
+P1pQkjmCskU4tztaWvlLh0qg85wuQGnpJaQT3gS30378i0IGbA0EBvJcSpTHYbLa
+nsdI9bfN/ZVgeolVMNMU9/n8R8vRhNPcHuciFwaqS656q+HavCIyxw/LfjSwwFvR
+TngCn0wytRErkzFIXnRKckh8/BpI4S+0+l1NkOwG4WJ55KJ/9OOdZW5o/QCp2bDi
+E0JN1EP/gkSom/prq8JR/yEqtsy99uc5nUxPmzv0IgdcFHZEfiQU7iRggEbx7qfQ
+Ve55XksmmJInmpCy1bSabAEgIKp8Ckt5KLYZ0RgTXUhcEpsxEo6cuAwoSJT5o4Rp
+yG3xow2ozPcqZkvb+d2CHj1sc54w9BVFAjVANEKmRil/9WKz14bu3wxEhOPqC54n
+QojjLcoXSoT66ZUOQnYxTSiLtzoKGPy8cAVPbkBrXz2u2sj5gcvr1JjoGjdHm9/3
+qnqC8fsTz8UndKNIQC337o4K0833bQMzRGl1/qjbAPit2B7E3b6xTZMCAQI=
+-----END DH PARAMETERS-----
diff --git a/test/openssl/fixtures/pkey/rsa-1.pem b/test/openssl/fixtures/pkey/rsa-1.pem
new file mode 100644
index 00000000..bd5a624f
--- /dev/null
+++ b/test/openssl/fixtures/pkey/rsa-1.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git a/test/openssl/fixtures/pkey/rsa-2.pem b/test/openssl/fixtures/pkey/rsa-2.pem
new file mode 100644
index 00000000..e4fd4f43
--- /dev/null
+++ b/test/openssl/fixtures/pkey/rsa-2.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git a/test/openssl/fixtures/pkey/rsa-3.pem b/test/openssl/fixtures/pkey/rsa-3.pem
new file mode 100644
index 00000000..6c9c9ced
--- /dev/null
+++ b/test/openssl/fixtures/pkey/rsa-3.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb
index eac3655e..8d6ca1e9 100644
--- a/test/openssl/test_pair.rb
+++ b/test/openssl/test_pair.rb
@@ -10,7 +10,7 @@ def setup
ee_exts = [
["keyUsage", "keyEncipherment,digitalSignature", true],
]
- @svr_key = OpenSSL::TestUtils::Fixtures.pkey("rsa1024")
+ @svr_key = OpenSSL::TestUtils::Fixtures.pkey("rsa-1")
@svr_cert = issue_cert(svr_dn, @svr_key, 1, ee_exts, nil, nil)
end
@@ -23,7 +23,7 @@ def ssl_pair
sctx = OpenSSL::SSL::SSLContext.new
sctx.cert = @svr_cert
sctx.key = @svr_key
- sctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") }
+ sctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") }
sctx.options |= OpenSSL::SSL::OP_NO_COMPRESSION
ssls = OpenSSL::SSL::SSLServer.new(tcps, sctx)
ns = ssls.accept
@@ -397,7 +397,7 @@ def test_connect_accept_nonblock_no_exception
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.cert = @svr_cert
ctx2.key = @svr_key
- ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") }
+ ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") }
sock1, sock2 = tcp_pair
@@ -445,7 +445,7 @@ def test_connect_accept_nonblock
ctx = OpenSSL::SSL::SSLContext.new
ctx.cert = @svr_cert
ctx.key = @svr_key
- ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey_dh("dh1024") }
+ ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") }
sock1, sock2 = tcp_pair
diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb
index fb713813..79bf9bb7 100644
--- a/test/openssl/test_pkey_dh.rb
+++ b/test/openssl/test_pkey_dh.rb
@@ -19,7 +19,7 @@ def test_new_break
end
def test_DHparams
- dh1024 = Fixtures.pkey_dh("dh1024")
+ dh1024 = Fixtures.pkey("dh1024")
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Integer(dh1024.p),
OpenSSL::ASN1::Integer(dh1024.g)
@@ -42,7 +42,7 @@ def test_DHparams
end
def test_public_key
- dh = Fixtures.pkey_dh("dh1024")
+ dh = Fixtures.pkey("dh1024")
public_key = dh.public_key
assert_no_key(public_key) #implies public_key.public? is false!
assert_equal(dh.to_der, public_key.to_der)
@@ -50,14 +50,14 @@ def test_public_key
end
def test_generate_key
- dh = Fixtures.pkey_dh("dh1024").public_key # creates a copy
+ dh = Fixtures.pkey("dh1024").public_key # creates a copy
assert_no_key(dh)
dh.generate_key!
assert_key(dh)
end
def test_key_exchange
- dh = Fixtures.pkey_dh("dh1024")
+ dh = Fixtures.pkey("dh1024")
dh2 = dh.public_key
dh.generate_key!
dh2.generate_key!
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index 408c7d82..2633f7c4 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -708,7 +708,7 @@ def socketpair
def test_tlsext_hostname
fooctx = OpenSSL::SSL::SSLContext.new
- fooctx.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") }
+ fooctx.tmp_dh_callback = proc { Fixtures.pkey("dh-1") }
fooctx.cert = @cli_cert
fooctx.key = @cli_key
@@ -760,7 +760,7 @@ def test_servername_cb_raises_an_exception_on_unknown_objects
ctx2 = OpenSSL::SSL::SSLContext.new
ctx2.cert = @svr_cert
ctx2.key = @svr_key
- ctx2.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") }
+ ctx2.tmp_dh_callback = proc { Fixtures.pkey("dh-1") }
ctx2.servername_cb = lambda { |args| Object.new }
sock1, sock2 = socketpair
@@ -1140,7 +1140,7 @@ def test_alpn_protocol_selection_cancel
ctx1 = OpenSSL::SSL::SSLContext.new
ctx1.cert = @svr_cert
ctx1.key = @svr_key
- ctx1.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") }
+ ctx1.tmp_dh_callback = proc { Fixtures.pkey("dh-1") }
ctx1.alpn_select_cb = -> (protocols) { nil }
ssl1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
@@ -1382,20 +1382,21 @@ def test_get_ephemeral_key
def test_dh_callback
pend "TLS 1.2 is not supported" unless tls12_supported?
+ dh = Fixtures.pkey("dh-1")
called = false
ctx_proc = -> ctx {
ctx.ssl_version = :TLSv1_2
ctx.ciphers = "DH:!NULL"
ctx.tmp_dh_callback = ->(*args) {
called = true
- Fixtures.pkey_dh("dh1024")
+ dh
}
}
start_server(ctx_proc: ctx_proc) do |port|
server_connect(port) { |ssl|
assert called, "dh callback should be called"
if ssl.respond_to?(:tmp_key)
- assert_equal Fixtures.pkey_dh("dh1024").to_der, ssl.tmp_key.to_der
+ assert_equal dh.to_der, ssl.tmp_key.to_der
end
}
end
diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb
index b7ddd891..fe626ade 100644
--- a/test/openssl/utils.rb
+++ b/test/openssl/utils.rb
@@ -42,10 +42,8 @@ module Fixtures
def pkey(name)
OpenSSL::PKey.read(read_file("pkey", name))
- end
-
- def pkey_dh(name)
- # DH parameters can be read by OpenSSL::PKey.read atm
+ rescue OpenSSL::PKey::PKeyError
+ # TODO: DH parameters can be read by OpenSSL::PKey.read atm
OpenSSL::PKey::DH.new(read_file("pkey", name))
end
@@ -157,9 +155,9 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase
def setup
super
- @ca_key = Fixtures.pkey("rsa2048")
- @svr_key = Fixtures.pkey("rsa1024")
- @cli_key = Fixtures.pkey("rsa2048")
+ @ca_key = Fixtures.pkey("rsa-1")
+ @svr_key = Fixtures.pkey("rsa-2")
+ @cli_key = Fixtures.pkey("rsa-3")
@ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA")
@svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost")
@cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost")
@@ -200,7 +198,7 @@ def start_server(verify_mode: OpenSSL::SSL::VERIFY_NONE, start_immediately: true
ctx.cert_store = store
ctx.cert = @svr_cert
ctx.key = @svr_key
- ctx.tmp_dh_callback = proc { Fixtures.pkey_dh("dh1024") }
+ ctx.tmp_dh_callback = proc { Fixtures.pkey("dh-1") }
ctx.verify_mode = verify_mode
ctx_proc.call(ctx) if ctx_proc

@ -0,0 +1,73 @@
From 8e2ed0b9d965a526b29f9dc3bff8e9fe33dae98d Mon Sep 17 00:00:00 2001
From: usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Tue, 12 Apr 2022 11:49:45 +0000
Subject: [PATCH] Fix CVE-2022-28739 Buffer overrun in str2float.
CVE-2022-28739: Buffer overrun in String-to-Float conversion
Backported from upstream Ruby 2.6.10,
Git commit:
https://github.com/ruby/ruby/commit/69f9992ed41920389d4185141a14f02f89a4d306
==== Original commit message
Fix dtoa buffer overrun
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_6@67957 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
---
test/ruby/test_float.rb | 18 ++++++++++++++++++
util.c | 3 ++-
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb
index 7fabfd3..78c63c2 100644
--- a/test/ruby/test_float.rb
+++ b/test/ruby/test_float.rb
@@ -171,6 +171,24 @@ class TestFloat < Test::Unit::TestCase
assert_raise(ArgumentError, n += z + "A") {Float(n)}
assert_raise(ArgumentError, n += z + ".0") {Float(n)}
end
+
+ x = nil
+ 2000.times do
+ x = Float("0x"+"0"*30)
+ break unless x == 0.0
+ end
+ assert_equal(0.0, x, ->{"%a" % x})
+ x = nil
+ 2000.times do
+ begin
+ x = Float("0x1."+"0"*270)
+ rescue ArgumentError => e
+ raise unless /"0x1\.0{270}"/ =~ e.message
+ else
+ break
+ end
+ end
+ assert_nil(x, ->{"%a" % x})
end
def test_divmod
diff --git a/util.c b/util.c
index 2222744..f1d910f 100644
--- a/util.c
+++ b/util.c
@@ -2046,6 +2046,7 @@ break2:
if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0;
if (*s == '0') {
while (*++s == '0');
+ if (!*s) goto ret;
s1 = strchr(hexdigit, *s);
}
if (s1 != NULL) {
@@ -2068,7 +2069,7 @@ break2:
for (; *s && (s1 = strchr(hexdigit, *s)); ++s) {
adj += aadj * ((s1 - hexdigit) & 15);
if ((aadj /= 16) == 0.0) {
- while (strchr(hexdigit, *++s));
+ while (*++s && strchr(hexdigit, *s));
break;
}
}
--
2.41.0

@ -0,0 +1,61 @@
diff --git a/ext/fiddle/closure.c b/ext/fiddle/closure.c
index 1a80b2b..b997e23 100644
--- a/ext/fiddle/closure.c
+++ b/ext/fiddle/closure.c
@@ -13,25 +13,11 @@ typedef struct {
ffi_type **argv;
} fiddle_closure;
-#if defined(USE_FFI_CLOSURE_ALLOC)
-#elif defined(__OpenBSD__) || defined(__APPLE__) || defined(__linux__)
-# define USE_FFI_CLOSURE_ALLOC 0
-#elif defined(RUBY_LIBFFI_MODVERSION) && RUBY_LIBFFI_MODVERSION < 3000005 && \
- (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_AMD64))
-# define USE_FFI_CLOSURE_ALLOC 0
-#else
-# define USE_FFI_CLOSURE_ALLOC 1
-#endif
-
static void
dealloc(void * ptr)
{
fiddle_closure * cls = (fiddle_closure *)ptr;
-#if USE_FFI_CLOSURE_ALLOC
ffi_closure_free(cls->pcl);
-#else
- munmap(cls->pcl, sizeof(*cls->pcl));
-#endif
if (cls->argv) xfree(cls->argv);
xfree(cls);
}
@@ -205,12 +191,7 @@ allocate(VALUE klass)
VALUE i = TypedData_Make_Struct(klass, fiddle_closure,
&closure_data_type, closure);
-#if USE_FFI_CLOSURE_ALLOC
closure->pcl = ffi_closure_alloc(sizeof(ffi_closure), &closure->code);
-#else
- closure->pcl = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE,
- MAP_ANON | MAP_PRIVATE, -1, 0);
-#endif
return i;
}
@@ -257,17 +238,8 @@ initialize(int rbargc, VALUE argv[], VALUE self)
if (FFI_OK != result)
rb_raise(rb_eRuntimeError, "error prepping CIF %d", result);
-#if USE_FFI_CLOSURE_ALLOC
result = ffi_prep_closure_loc(pcl, cif, callback,
(void *)self, cl->code);
-#else
- result = ffi_prep_closure(pcl, cif, callback, (void *)self);
- cl->code = (void *)pcl;
- i = mprotect(pcl, sizeof(*pcl), PROT_READ | PROT_EXEC);
- if (i) {
- rb_sys_fail("mprotect");
- }
-#endif
if (FFI_OK != result)
rb_raise(rb_eRuntimeError, "error prepping closure %d", result);

@ -0,0 +1,247 @@
commit be5a83e84a34091f2a4e3c6dfb911b20e78e690c
Author: usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Wed Jul 7 10:34:08 2021 +0000
Ignore IP addresses in PASV responses by default, and add new option use_pasv_ip
This fixes CVE-2021-31810.
Reported by Alexandr Savca.
Co-authored-by: Shugo Maeda <shugo@ruby-lang.org>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_6@67949 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
diff --git a/lib/net/ftp.rb b/lib/net/ftp.rb
index e68d825dcf..c5d669d898 100644
--- a/lib/net/ftp.rb
+++ b/lib/net/ftp.rb
@@ -97,6 +97,10 @@ class FTP < Protocol
# When +true+, the connection is in passive mode. Default: +true+.
attr_accessor :passive
+ # When +true+, use the IP address in PASV responses. Otherwise, it uses
+ # the same IP address for the control connection. Default: +false+.
+ attr_accessor :use_pasv_ip
+
# When +true+, all traffic to and from the server is written
# to +$stdout+. Default: +false+.
attr_accessor :debug_mode
@@ -205,6 +209,9 @@ def FTP.open(host, *args)
# handshake.
# See Net::FTP#ssl_handshake_timeout for
# details. Default: +nil+.
+ # use_pasv_ip:: When +true+, use the IP address in PASV responses.
+ # Otherwise, it uses the same IP address for the control
+ # connection. Default: +false+.
# debug_mode:: When +true+, all traffic to and from the server is
# written to +$stdout+. Default: +false+.
#
@@ -265,6 +272,7 @@ def initialize(host = nil, user_or_options = {}, passwd = nil, acct = nil)
@open_timeout = options[:open_timeout]
@ssl_handshake_timeout = options[:ssl_handshake_timeout]
@read_timeout = options[:read_timeout] || 60
+ @use_pasv_ip = options[:use_pasv_ip] || false
if host
connect(host, options[:port] || FTP_PORT)
if options[:username]
@@ -1330,7 +1338,12 @@ def parse227(resp) # :nodoc:
raise FTPReplyError, resp
end
if m = /\((?<host>\d+(,\d+){3}),(?<port>\d+,\d+)\)/.match(resp)
- return parse_pasv_ipv4_host(m["host"]), parse_pasv_port(m["port"])
+ if @use_pasv_ip
+ host = parse_pasv_ipv4_host(m["host"])
+ else
+ host = @bare_sock.remote_address.ip_address
+ end
+ return host, parse_pasv_port(m["port"])
else
raise FTPProtoError, resp
end
diff --git a/test/net/ftp/test_ftp.rb b/test/net/ftp/test_ftp.rb
index a5219644bb..b3fe7774ed 100644
--- a/test/net/ftp/test_ftp.rb
+++ b/test/net/ftp/test_ftp.rb
@@ -61,7 +61,7 @@ def test_connect_fail
end
def test_parse227
- ftp = Net::FTP.new
+ ftp = Net::FTP.new(nil, use_pasv_ip: true)
host, port = ftp.send(:parse227, "227 Entering Passive Mode (192,168,0,1,12,34)")
assert_equal("192.168.0.1", host)
assert_equal(3106, port)
@@ -80,6 +80,14 @@ def test_parse227
assert_raise(Net::FTPProtoError) do
ftp.send(:parse227, "227 ) foo bar (")
end
+
+ ftp = Net::FTP.new
+ sock = OpenStruct.new
+ sock.remote_address = OpenStruct.new
+ sock.remote_address.ip_address = "10.0.0.1"
+ ftp.instance_variable_set(:@bare_sock, sock)
+ host, port = ftp.send(:parse227, "227 Entering Passive Mode (192,168,0,1,12,34)")
+ assert_equal("10.0.0.1", host)
end
def test_parse228
@@ -2360,10 +2368,155 @@ def test_puttextfile_command_injection
end
end
+ def test_ignore_pasv_ip
+ commands = []
+ binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3
+ server = create_ftp_server(nil, "127.0.0.1") { |sock|
+ sock.print("220 (test_ftp).\r\n")
+ commands.push(sock.gets)
+ sock.print("331 Please specify the password.\r\n")
+ commands.push(sock.gets)
+ sock.print("230 Login successful.\r\n")
+ commands.push(sock.gets)
+ sock.print("200 Switching to Binary mode.\r\n")
+ line = sock.gets
+ commands.push(line)
+ data_server = TCPServer.new("127.0.0.1", 0)
+ port = data_server.local_address.ip_port
+ sock.printf("227 Entering Passive Mode (999,0,0,1,%s).\r\n",
+ port.divmod(256).join(","))
+ commands.push(sock.gets)
+ sock.print("150 Opening BINARY mode data connection for foo (#{binary_data.size} bytes)\r\n")
+ conn = data_server.accept
+ binary_data.scan(/.{1,1024}/nm) do |s|
+ conn.print(s)
+ end
+ conn.shutdown(Socket::SHUT_WR)
+ conn.read
+ conn.close
+ data_server.close
+ sock.print("226 Transfer complete.\r\n")
+ }
+ begin
+ begin
+ ftp = Net::FTP.new
+ ftp.passive = true
+ ftp.read_timeout *= 5 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # for --jit-wait
+ ftp.connect("127.0.0.1", server.port)
+ ftp.login
+ assert_match(/\AUSER /, commands.shift)
+ assert_match(/\APASS /, commands.shift)
+ assert_equal("TYPE I\r\n", commands.shift)
+ buf = ftp.getbinaryfile("foo", nil)
+ assert_equal(binary_data, buf)
+ assert_equal(Encoding::ASCII_8BIT, buf.encoding)
+ assert_equal("PASV\r\n", commands.shift)
+ assert_equal("RETR foo\r\n", commands.shift)
+ assert_equal(nil, commands.shift)
+ ensure
+ ftp.close if ftp
+ end
+ ensure
+ server.close
+ end
+ end
+
+ def test_use_pasv_ip
+ commands = []
+ binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3
+ server = create_ftp_server(nil, "127.0.0.1") { |sock|
+ sock.print("220 (test_ftp).\r\n")
+ commands.push(sock.gets)
+ sock.print("331 Please specify the password.\r\n")
+ commands.push(sock.gets)
+ sock.print("230 Login successful.\r\n")
+ commands.push(sock.gets)
+ sock.print("200 Switching to Binary mode.\r\n")
+ line = sock.gets
+ commands.push(line)
+ data_server = TCPServer.new("127.0.0.1", 0)
+ port = data_server.local_address.ip_port
+ sock.printf("227 Entering Passive Mode (127,0,0,1,%s).\r\n",
+ port.divmod(256).join(","))
+ commands.push(sock.gets)
+ sock.print("150 Opening BINARY mode data connection for foo (#{binary_data.size} bytes)\r\n")
+ conn = data_server.accept
+ binary_data.scan(/.{1,1024}/nm) do |s|
+ conn.print(s)
+ end
+ conn.shutdown(Socket::SHUT_WR)
+ conn.read
+ conn.close
+ data_server.close
+ sock.print("226 Transfer complete.\r\n")
+ }
+ begin
+ begin
+ ftp = Net::FTP.new
+ ftp.passive = true
+ ftp.use_pasv_ip = true
+ ftp.read_timeout *= 5 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # for --jit-wait
+ ftp.connect("127.0.0.1", server.port)
+ ftp.login
+ assert_match(/\AUSER /, commands.shift)
+ assert_match(/\APASS /, commands.shift)
+ assert_equal("TYPE I\r\n", commands.shift)
+ buf = ftp.getbinaryfile("foo", nil)
+ assert_equal(binary_data, buf)
+ assert_equal(Encoding::ASCII_8BIT, buf.encoding)
+ assert_equal("PASV\r\n", commands.shift)
+ assert_equal("RETR foo\r\n", commands.shift)
+ assert_equal(nil, commands.shift)
+ ensure
+ ftp.close if ftp
+ end
+ ensure
+ server.close
+ end
+ end
+
+ def test_use_pasv_invalid_ip
+ commands = []
+ binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3
+ server = create_ftp_server(nil, "127.0.0.1") { |sock|
+ sock.print("220 (test_ftp).\r\n")
+ commands.push(sock.gets)
+ sock.print("331 Please specify the password.\r\n")
+ commands.push(sock.gets)
+ sock.print("230 Login successful.\r\n")
+ commands.push(sock.gets)
+ sock.print("200 Switching to Binary mode.\r\n")
+ line = sock.gets
+ commands.push(line)
+ sock.print("227 Entering Passive Mode (999,0,0,1,48,57).\r\n")
+ commands.push(sock.gets)
+ }
+ begin
+ begin
+ ftp = Net::FTP.new
+ ftp.passive = true
+ ftp.use_pasv_ip = true
+ ftp.read_timeout *= 5 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # for --jit-wait
+ ftp.connect("127.0.0.1", server.port)
+ ftp.login
+ assert_match(/\AUSER /, commands.shift)
+ assert_match(/\APASS /, commands.shift)
+ assert_equal("TYPE I\r\n", commands.shift)
+ assert_raise(SocketError) do
+ ftp.getbinaryfile("foo", nil)
+ end
+ ensure
+ ftp.close if ftp
+ end
+ ensure
+ server.close
+ end
+ end
+
private
- def create_ftp_server(sleep_time = nil)
- server = TCPServer.new(SERVER_ADDR, 0)
+ def create_ftp_server(sleep_time = nil, addr = SERVER_ADDR)
+ server = TCPServer.new(addr, 0)
@thread = Thread.start do
if sleep_time
sleep(sleep_time)

@ -0,0 +1,101 @@
commit 95ba9053e20ad8d113af37b3f1f4cbfff1f6a8f1
Author: usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Wed Jul 7 10:38:10 2021 +0000
Fix StartTLS stripping vulnerability
Reported by Alexandr Savca in https://hackerone.com/reports/1178562
Co-authored-by: Shugo Maeda <shugo@ruby-lang.org>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_6@67950 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
diff --git a/lib/net/imap.rb b/lib/net/imap.rb
index 1c7e89ba14..91df89b79e 100644
--- a/lib/net/imap.rb
+++ b/lib/net/imap.rb
@@ -1213,12 +1213,14 @@ def get_tagged_response(tag, cmd)
end
resp = @tagged_responses.delete(tag)
case resp.name
+ when /\A(?:OK)\z/ni
+ return resp
when /\A(?:NO)\z/ni
raise NoResponseError, resp
when /\A(?:BAD)\z/ni
raise BadResponseError, resp
else
- return resp
+ raise UnknownResponseError, resp
end
end
@@ -3714,6 +3716,10 @@ class BadResponseError < ResponseError
class ByeResponseError < ResponseError
end
+ # Error raised upon an unknown response from the server.
+ class UnknownResponseError < ResponseError
+ end
+
RESPONSE_ERRORS = Hash.new(ResponseError)
RESPONSE_ERRORS["NO"] = NoResponseError
RESPONSE_ERRORS["BAD"] = BadResponseError
diff --git a/test/net/imap/test_imap.rb b/test/net/imap/test_imap.rb
index 936f4e0f42..81928cb8fe 100644
--- a/test/net/imap/test_imap.rb
+++ b/test/net/imap/test_imap.rb
@@ -127,6 +127,24 @@ def test_starttls
imap.disconnect
end
end
+
+ def test_starttls_stripping
+ starttls_stripping_test do |port|
+ imap = Net::IMAP.new("localhost", :port => port)
+ assert_raise(Net::IMAP::UnknownResponseError) do
+ imap.starttls(:ca_file => CA_FILE)
+ end
+ imap
+ end
+ end
+ end
+
+ def start_server
+ th = Thread.new do
+ yield
+ end
+ @threads << th
+ sleep 0.1 until th.stop?
end
def test_unexpected_eof
@@ -760,6 +760,27 @@ def starttls_test
end
end
+ def starttls_stripping_test
+ server = create_tcp_server
+ port = server.addr[1]
+ start_server do
+ sock = server.accept
+ begin
+ sock.print("* OK test server\r\n")
+ sock.gets
+ sock.print("RUBY0001 BUG unhandled command\r\n")
+ ensure
+ sock.close
+ server.close
+ end
+ end
+ begin
+ imap = yield(port)
+ ensure
+ imap.disconnect if imap && !imap.disconnected?
+ end
+ end
+
def create_tcp_server
return TCPServer.new(server_addr, 0)
end

@ -0,0 +1,88 @@
commit fe3c49c9baeeab58304ede915b7edd18ecf360fc
Author: usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Sat Jul 3 17:10:28 2021 +0000
merge revision(s) b1c73f23,c9ab8fe2: [Backport #17877]
[ruby/rdoc] Use File.open to fix the OS Command Injection vulnerability in CVE-2021-31799
https://github.com/ruby/rdoc/commit/a7f5d6ab88
The test for command injection on Unix platforms should be omitted on Windows
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_6@67947 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index ca2c1abefd..46aace7839 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -436,7 +436,7 @@ def remove_unparseable files
files.reject do |file|
file =~ /\.(?:class|eps|erb|scpt\.txt|svg|ttf|yml)$/i or
(file =~ /tags$/i and
- open(file, 'rb') { |io|
+ File.open(file, 'rb') { |io|
io.read(100) =~ /\A(\f\n[^,]+,\d+$|!_TAG_)/
})
end
--- a/lib/rdoc/encoding.rb 2022-02-16 16:51:28.080178281 +0100
+++ b/lib/rdoc/encoding.rb 2022-02-16 16:51:37.108160840 +0100
@@ -18,7 +18,7 @@
# unknown character in the target encoding will be replaced with '?'
def self.read_file filename, encoding, force_transcode = false
- content = open filename, "rb" do |f| f.read end
+ content = File.open filename, "rb" do |f| f.read end
content.gsub!("\r\n", "\n") if RUBY_PLATFORM =~ /mswin|mingw/
utf8 = content.sub!(/\A\xef\xbb\xbf/, '')
--- a/lib/rdoc/parser.rb 2021-04-05 13:46:35.000000000 +0200
+++ b/lib/rdoc/parser.rb 2022-02-16 15:37:17.904822389 +0100
@@ -74,7 +74,12 @@
def self.binary?(file)
return false if file =~ /\.(rdoc|txt)$/
- s = File.read(file, 1024) or return false
+ begin
+ open_file = File.open(file)
+ s = open_file.read(1024) or return false
+ ensure
+ open_file.close if open_file
+ end
return true if s[0, 2] == Marshal.dump('')[0, 2] or s.index("\x00")
@@ -92,7 +97,8 @@
# http://www.garykessler.net/library/file_sigs.html
def self.zip? file
- zip_signature = File.read file, 4
+ zip_signature = ''
+ File.open(file) { |f| zip_signature = f.read(4) }
zip_signature == "PK\x03\x04" or
zip_signature == "PK\x05\x06" or
diff --git a/test/rdoc/test_rdoc_rdoc.rb b/test/rdoc/test_rdoc_rdoc.rb
index 3bce54b243..123b1a4f87 100644
--- a/test/rdoc/test_rdoc_rdoc.rb
+++ b/test/rdoc/test_rdoc_rdoc.rb
@@ -366,6 +366,18 @@ def test_remove_unparseable_tags_vim
end
end
+ def test_remove_unparseable_CVE_2021_31799
+ skip 'for Un*x platforms' if Gem.win_platform?
+ temp_dir do
+ file_list = ['| touch evil.txt && echo tags']
+ file_list.each do |f|
+ FileUtils.touch f
+ end
+ assert_equal file_list, @rdoc.remove_unparseable(file_list)
+ assert_equal file_list, Dir.children('.')
+ end
+ end
+
def test_setup_output_dir
Dir.mktmpdir {|d|
path = File.join d, 'testdir'

@ -0,0 +1,42 @@
From e2c0652dff671dc6e16a80887e781edc0abc8454 Mon Sep 17 00:00:00 2001
From: usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Wed, 24 Nov 2021 11:41:55 +0000
Subject: [PATCH 2/2] When parsing cookies, only decode the values
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_6@67953 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
---
lib/cgi/cookie.rb | 1 -
test/cgi/test_cgi_cookie.rb | 5 +++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb
index a2155edb77..009566bb92 100644
--- a/lib/cgi/cookie.rb
+++ b/lib/cgi/cookie.rb
@@ -165,7 +165,6 @@ def self.parse(raw_cookie)
raw_cookie.split(/;\s?/).each do |pairs|
name, values = pairs.split('=',2)
next unless name and values
- name = CGI.unescape(name)
values ||= ""
values = values.split('&').collect{|v| CGI.unescape(v,@@accept_charset) }
if cookies.has_key?(name)
diff --git a/test/cgi/test_cgi_cookie.rb b/test/cgi/test_cgi_cookie.rb
index 115a57e4a1..985cc0d7a1 100644
--- a/test/cgi/test_cgi_cookie.rb
+++ b/test/cgi/test_cgi_cookie.rb
@@ -101,6 +101,11 @@ def test_cgi_cookie_parse
end
end
+ def test_cgi_cookie_parse_not_decode_name
+ cookie_str = "%66oo=baz;foo=bar"
+ cookies = CGI::Cookie.parse(cookie_str)
+ assert_equal({"%66oo" => ["baz"], "foo" => ["bar"]}, cookies)
+ end
def test_cgi_cookie_arrayinterface
cookie = CGI::Cookie.new('name1', 'a', 'b', 'c')
--
2.36.1

@ -0,0 +1,918 @@
From d5753ec513fa5a4bdcf59fa298642fd0d3a3c364 Mon Sep 17 00:00:00 2001
From: Yusuke Endoh <mame@ruby-lang.org>
Date: Fri, 12 Nov 2021 12:11:13 +0900
Subject: [PATCH 1/2] Add length limit option for methods that parses date
strings
This patch fixes CVE-2021-41817 and created from the commit
<https://github.com/ruby/date/commit/4f9b8e946ba98f0a1774f8e677baa4a45637ebb3>.
We didn't merge the files included in the original commit below, as those are
for rebasing date gem version.
* ext/date/date.gemspec
* ext/date/lib/date.rb
== Original commit message ==
`Date.parse` now raises an ArgumentError when a given date string is
longer than 128. You can configure the limit by giving `limit` keyword
arguments like `Date.parse(str, limit: 1000)`. If you pass `limit: nil`,
the limit is disabled.
Not only `Date.parse` but also the following methods are changed.
* Date._parse
* Date.parse
* DateTime.parse
* Date._iso8601
* Date.iso8601
* DateTime.iso8601
* Date._rfc3339
* Date.rfc3339
* DateTime.rfc3339
* Date._xmlschema
* Date.xmlschema
* DateTime.xmlschema
* Date._rfc2822
* Date.rfc2822
* DateTime.rfc2822
* Date._rfc822
* Date.rfc822
* DateTime.rfc822
* Date._jisx0301
* Date.jisx0301
* DateTime.jisx0301
---
ext/date/date_core.c | 384 +++++++++++++++++++++++++++--------
test/date/test_date_parse.rb | 29 +++
2 files changed, 325 insertions(+), 88 deletions(-)
diff --git a/ext/date/date_core.c b/ext/date/date_core.c
index c250633426..177ea0f6c5 100644
--- a/ext/date/date_core.c
+++ b/ext/date/date_core.c
@@ -4290,12 +4290,37 @@ date_s_strptime(int argc, VALUE *argv, VALUE klass)
VALUE date__parse(VALUE str, VALUE comp);
+static size_t
+get_limit(VALUE opt)
+{
+ if (!NIL_P(opt)) {
+ VALUE limit = rb_hash_aref(opt, ID2SYM(rb_intern("limit")));
+ if (NIL_P(limit)) return SIZE_MAX;
+ return NUM2SIZET(limit);
+ }
+ return 128;
+}
+
+static void
+check_limit(VALUE str, VALUE opt)
+{
+ StringValue(str);
+ size_t slen = RSTRING_LEN(str);
+ size_t limit = get_limit(opt);
+ if (slen > limit) {
+ rb_raise(rb_eArgError,
+ "string length (%"PRI_SIZE_PREFIX"u) exceeds the limit %"PRI_SIZE_PREFIX"u", slen, limit);
+ }
+}
+
static VALUE
date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
{
- VALUE vstr, vcomp, hash;
+ VALUE vstr, vcomp, hash, opt;
- rb_scan_args(argc, argv, "11", &vstr, &vcomp);
+ rb_scan_args(argc, argv, "11:", &vstr, &vcomp, &opt);
+ if (!NIL_P(opt)) argc--;
+ check_limit(vstr, opt);
StringValue(vstr);
if (!rb_enc_str_asciicompat_p(vstr))
rb_raise(rb_eArgError,
@@ -4320,7 +4345,7 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
/*
* call-seq:
- * Date._parse(string[, comp=true]) -> hash
+ * Date._parse(string[, comp=true], limit: 128) -> hash
*
* Parses the given representation of date and time, and returns a
* hash of parsed elements. This method does not function as a
@@ -4331,6 +4356,10 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
* it full.
*
* Date._parse('2001-02-03') #=> {:year=>2001, :mon=>2, :mday=>3}
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
date_s__parse(int argc, VALUE *argv, VALUE klass)
@@ -4340,7 +4369,7 @@ date_s__parse(int argc, VALUE *argv, VALUE klass)
/*
* call-seq:
- * Date.parse(string='-4712-01-01'[, comp=true[, start=Date::ITALY]]) -> date
+ * Date.parse(string='-4712-01-01'[, comp=true[, start=Date::ITALY]], limit: 128) -> date
*
* Parses the given representation of date and time, and creates a
* date object. This method does not function as a validator.
@@ -4352,13 +4381,18 @@ date_s__parse(int argc, VALUE *argv, VALUE klass)
* Date.parse('2001-02-03') #=> #<Date: 2001-02-03 ...>
* Date.parse('20010203') #=> #<Date: 2001-02-03 ...>
* Date.parse('3rd Feb 2001') #=> #<Date: 2001-02-03 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
date_s_parse(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, comp, sg;
+ VALUE str, comp, sg, opt;
- rb_scan_args(argc, argv, "03", &str, &comp, &sg);
+ rb_scan_args(argc, argv, "03:", &str, &comp, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -4370,11 +4404,12 @@ date_s_parse(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE argv2[2], hash;
-
- argv2[0] = str;
- argv2[1] = comp;
- hash = date_s__parse(2, argv2, klass);
+ int argc2 = 2;
+ VALUE argv2[3];
+ argv2[0] = str;
+ argv2[1] = comp;
+ if (!NIL_P(opt)) argv2[argc2++] = opt;
+ VALUE hash = date_s__parse(argc2, argv2, klass);
return d_new_by_frags(klass, hash, sg);
}
}
@@ -4388,19 +4423,28 @@ VALUE date__jisx0301(VALUE);
/*
* call-seq:
- * Date._iso8601(string) -> hash
+ * Date._iso8601(string, limit: 128) -> hash
*
* Returns a hash of parsed elements.
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
-date_s__iso8601(VALUE klass, VALUE str)
+date_s__iso8601(int argc, VALUE *argv, VALUE klass)
{
+ VALUE str, opt;
+
+ rb_scan_args(argc, argv, "1:", &str, &opt);
+ check_limit(str, opt);
+
return date__iso8601(str);
}
/*
* call-seq:
- * Date.iso8601(string='-4712-01-01'[, start=Date::ITALY]) -> date
+ * Date.iso8601(string='-4712-01-01'[, start=Date::ITALY], limit: 128) -> date
*
* Creates a new Date object by parsing from a string according to
* some typical ISO 8601 formats.
@@ -4408,13 +4452,18 @@ date_s__iso8601(VALUE klass, VALUE str)
* Date.iso8601('2001-02-03') #=> #<Date: 2001-02-03 ...>
* Date.iso8601('20010203') #=> #<Date: 2001-02-03 ...>
* Date.iso8601('2001-W05-6') #=> #<Date: 2001-02-03 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
date_s_iso8601(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -4424,38 +4473,56 @@ date_s_iso8601(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__iso8601(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ if (!NIL_P(opt)) argv2[argc2++] = opt;
+ VALUE hash = date_s__iso8601(argc2, argv2, klass);
return d_new_by_frags(klass, hash, sg);
}
}
/*
* call-seq:
- * Date._rfc3339(string) -> hash
+ * Date._rfc3339(string, limit: 128) -> hash
*
* Returns a hash of parsed elements.
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
-date_s__rfc3339(VALUE klass, VALUE str)
+date_s__rfc3339(int argc, VALUE *argv, VALUE klass)
{
+ VALUE str, opt;
+
+ rb_scan_args(argc, argv, "1:", &str, &opt);
+ check_limit(str, opt);
+
return date__rfc3339(str);
}
/*
* call-seq:
- * Date.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY]) -> date
+ * Date.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> date
*
* Creates a new Date object by parsing from a string according to
* some typical RFC 3339 formats.
*
* Date.rfc3339('2001-02-03T04:05:06+07:00') #=> #<Date: 2001-02-03 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
date_s_rfc3339(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -4465,38 +4532,56 @@ date_s_rfc3339(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__rfc3339(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ if (!NIL_P(opt)) argv2[argc2++] = opt;
+ VALUE hash = date_s__rfc3339(argc2, argv2, klass);
return d_new_by_frags(klass, hash, sg);
}
}
/*
* call-seq:
- * Date._xmlschema(string) -> hash
+ * Date._xmlschema(string, limit: 128) -> hash
*
* Returns a hash of parsed elements.
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
-date_s__xmlschema(VALUE klass, VALUE str)
+date_s__xmlschema(int argc, VALUE *argv, VALUE klass)
{
+ VALUE str, opt;
+
+ rb_scan_args(argc, argv, "1:", &str, &opt);
+ check_limit(str, opt);
+
return date__xmlschema(str);
}
/*
* call-seq:
- * Date.xmlschema(string='-4712-01-01'[, start=Date::ITALY]) -> date
+ * Date.xmlschema(string='-4712-01-01'[, start=Date::ITALY], limit: 128) -> date
*
* Creates a new Date object by parsing from a string according to
* some typical XML Schema formats.
*
* Date.xmlschema('2001-02-03') #=> #<Date: 2001-02-03 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
date_s_xmlschema(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -4506,41 +4591,58 @@ date_s_xmlschema(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__xmlschema(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ if (!NIL_P(opt)) argv2[argc2++] = opt;
+ VALUE hash = date_s__xmlschema(argc2, argv2, klass);
return d_new_by_frags(klass, hash, sg);
}
}
/*
* call-seq:
- * Date._rfc2822(string) -> hash
- * Date._rfc822(string) -> hash
+ * Date._rfc2822(string, limit: 128) -> hash
+ * Date._rfc822(string, limit: 128) -> hash
*
* Returns a hash of parsed elements.
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
-date_s__rfc2822(VALUE klass, VALUE str)
+date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
{
+ VALUE str, opt;
+
+ rb_scan_args(argc, argv, "1:", &str, &opt);
+ check_limit(str, opt);
+
return date__rfc2822(str);
}
/*
* call-seq:
- * Date.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY]) -> date
- * Date.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY]) -> date
+ * Date.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY], limit: 128) -> date
+ * Date.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY], limit: 128) -> date
*
* Creates a new Date object by parsing from a string according to
* some typical RFC 2822 formats.
*
* Date.rfc2822('Sat, 3 Feb 2001 00:00:00 +0000')
* #=> #<Date: 2001-02-03 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
date_s_rfc2822(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
switch (argc) {
case 0:
@@ -4550,39 +4652,56 @@ date_s_rfc2822(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__rfc2822(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ if (!NIL_P(opt)) argv2[argc2++] = opt;
+ VALUE hash = date_s__rfc2822(argc2, argv2, klass);
return d_new_by_frags(klass, hash, sg);
}
}
/*
* call-seq:
- * Date._httpdate(string) -> hash
+ * Date._httpdate(string, limit: 128) -> hash
*
* Returns a hash of parsed elements.
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
-date_s__httpdate(VALUE klass, VALUE str)
+date_s__httpdate(int argc, VALUE *argv, VALUE klass)
{
+ VALUE str, opt;
+
+ rb_scan_args(argc, argv, "1:", &str, &opt);
+ check_limit(str, opt);
+
return date__httpdate(str);
}
/*
* call-seq:
- * Date.httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=Date::ITALY]) -> date
+ * Date.httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=Date::ITALY], limit: 128) -> date
*
* Creates a new Date object by parsing from a string according to
* some RFC 2616 format.
*
* Date.httpdate('Sat, 03 Feb 2001 00:00:00 GMT')
* #=> #<Date: 2001-02-03 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
date_s_httpdate(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
switch (argc) {
case 0:
@@ -4592,38 +4711,56 @@ date_s_httpdate(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__httpdate(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ if (!NIL_P(opt)) argv2[argc2++] = opt;
+ VALUE hash = date_s__httpdate(argc2, argv2, klass);
return d_new_by_frags(klass, hash, sg);
}
}
/*
* call-seq:
- * Date._jisx0301(string) -> hash
+ * Date._jisx0301(string, limit: 128) -> hash
*
* Returns a hash of parsed elements.
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
-date_s__jisx0301(VALUE klass, VALUE str)
+date_s__jisx0301(int argc, VALUE *argv, VALUE klass)
{
+ VALUE str, opt;
+
+ rb_scan_args(argc, argv, "1:", &str, &opt);
+ check_limit(str, opt);
+
return date__jisx0301(str);
}
/*
* call-seq:
- * Date.jisx0301(string='-4712-01-01'[, start=Date::ITALY]) -> date
+ * Date.jisx0301(string='-4712-01-01'[, start=Date::ITALY], limit: 128) -> date
*
* Creates a new Date object by parsing from a string according to
* some typical JIS X 0301 formats.
*
* Date.jisx0301('H13.02.03') #=> #<Date: 2001-02-03 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
date_s_jisx0301(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -4633,7 +4770,11 @@ date_s_jisx0301(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__jisx0301(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ if (!NIL_P(opt)) argv2[argc2++] = opt;
+ VALUE hash = date_s__jisx0301(argc2, argv2, klass);
return d_new_by_frags(klass, hash, sg);
}
}
@@ -7925,7 +8066,7 @@ datetime_s_strptime(int argc, VALUE *argv, VALUE klass)
/*
* call-seq:
- * DateTime.parse(string='-4712-01-01T00:00:00+00:00'[, comp=true[, start=Date::ITALY]]) -> datetime
+ * DateTime.parse(string='-4712-01-01T00:00:00+00:00'[, comp=true[, start=Date::ITALY]], limit: 128) -> datetime
*
* Parses the given representation of date and time, and creates a
* DateTime object. This method does not function as a validator.
@@ -7939,13 +8080,18 @@ datetime_s_strptime(int argc, VALUE *argv, VALUE klass)
* #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
* DateTime.parse('3rd Feb 2001 04:05:06 PM')
* #=> #<DateTime: 2001-02-03T16:05:06+00:00 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
datetime_s_parse(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, comp, sg;
+ VALUE str, comp, sg, opt;
- rb_scan_args(argc, argv, "03", &str, &comp, &sg);
+ rb_scan_args(argc, argv, "03:", &str, &comp, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -7957,18 +8103,20 @@ datetime_s_parse(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE argv2[2], hash;
-
- argv2[0] = str;
- argv2[1] = comp;
- hash = date_s__parse(2, argv2, klass);
+ int argc2 = 2;
+ VALUE argv2[3];
+ argv2[0] = str;
+ argv2[1] = comp;
+ argv2[2] = opt;
+ if (!NIL_P(opt)) argc2++;
+ VALUE hash = date_s__parse(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
}
/*
* call-seq:
- * DateTime.iso8601(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY]) -> datetime
+ * DateTime.iso8601(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime
*
* Creates a new DateTime object by parsing from a string according to
* some typical ISO 8601 formats.
@@ -7979,13 +8127,18 @@ datetime_s_parse(int argc, VALUE *argv, VALUE klass)
* #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
* DateTime.iso8601('2001-W05-6T04:05:06+07:00')
* #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
datetime_s_iso8601(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -7995,27 +8148,37 @@ datetime_s_iso8601(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__iso8601(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ argv2[1] = opt;
+ if (!NIL_P(opt)) argc2--;
+ VALUE hash = date_s__iso8601(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
}
/*
* call-seq:
- * DateTime.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY]) -> datetime
+ * DateTime.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime
*
* Creates a new DateTime object by parsing from a string according to
* some typical RFC 3339 formats.
*
* DateTime.rfc3339('2001-02-03T04:05:06+07:00')
* #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -8025,27 +8188,37 @@ datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__rfc3339(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ argv2[1] = opt;
+ if (!NIL_P(opt)) argc2++;
+ VALUE hash = date_s__rfc3339(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
}
/*
* call-seq:
- * DateTime.xmlschema(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY]) -> datetime
+ * DateTime.xmlschema(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime
*
* Creates a new DateTime object by parsing from a string according to
* some typical XML Schema formats.
*
* DateTime.xmlschema('2001-02-03T04:05:06+07:00')
* #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -8055,28 +8228,38 @@ datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__xmlschema(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ argv2[1] = opt;
+ if (!NIL_P(opt)) argc2++;
+ VALUE hash = date_s__xmlschema(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
}
/*
* call-seq:
- * DateTime.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY]) -> datetime
- * DateTime.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY]) -> datetime
+ * DateTime.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY], limit: 128) -> datetime
+ * DateTime.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY], limit: 128) -> datetime
*
* Creates a new DateTime object by parsing from a string according to
* some typical RFC 2822 formats.
*
* DateTime.rfc2822('Sat, 3 Feb 2001 04:05:06 +0700')
* #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -8086,7 +8269,12 @@ datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__rfc2822(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ argv2[1] = opt;
+ if (!NIL_P(opt)) argc2++;
+ VALUE hash = date_s__rfc2822(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
}
@@ -8100,13 +8288,18 @@ datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass)
*
* DateTime.httpdate('Sat, 03 Feb 2001 04:05:06 GMT')
* #=> #<DateTime: 2001-02-03T04:05:06+00:00 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
datetime_s_httpdate(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -8116,27 +8309,37 @@ datetime_s_httpdate(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__httpdate(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ argv2[1] = opt;
+ if (!NIL_P(opt)) argc2++;
+ VALUE hash = date_s__httpdate(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
}
/*
* call-seq:
- * DateTime.jisx0301(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY]) -> datetime
+ * DateTime.jisx0301(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime
*
* Creates a new DateTime object by parsing from a string according to
* some typical JIS X 0301 formats.
*
* DateTime.jisx0301('H13.02.03T04:05:06+07:00')
* #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
+ *
+ * Raise an ArgumentError when the string length is longer than _limit_.
+ * You can stop this check by passing `limit: nil`, but note that
+ * it may take a long time to parse.
*/
static VALUE
datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass)
{
- VALUE str, sg;
+ VALUE str, sg, opt;
- rb_scan_args(argc, argv, "02", &str, &sg);
+ rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
+ if (!NIL_P(opt)) argc--;
switch (argc) {
case 0:
@@ -8146,7 +8349,12 @@ datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass)
}
{
- VALUE hash = date_s__jisx0301(klass, str);
+ int argc2 = 1;
+ VALUE argv2[2];
+ argv2[0] = str;
+ argv2[1] = opt;
+ if (!NIL_P(opt)) argc2++;
+ VALUE hash = date_s__jisx0301(argc2, argv2, klass);
return dt_new_by_frags(klass, hash, sg);
}
}
@@ -9297,19 +9505,19 @@ Init_date_core(void)
rb_define_singleton_method(cDate, "strptime", date_s_strptime, -1);
rb_define_singleton_method(cDate, "_parse", date_s__parse, -1);
rb_define_singleton_method(cDate, "parse", date_s_parse, -1);
- rb_define_singleton_method(cDate, "_iso8601", date_s__iso8601, 1);
+ rb_define_singleton_method(cDate, "_iso8601", date_s__iso8601, -1);
rb_define_singleton_method(cDate, "iso8601", date_s_iso8601, -1);
- rb_define_singleton_method(cDate, "_rfc3339", date_s__rfc3339, 1);
+ rb_define_singleton_method(cDate, "_rfc3339", date_s__rfc3339, -1);
rb_define_singleton_method(cDate, "rfc3339", date_s_rfc3339, -1);
- rb_define_singleton_method(cDate, "_xmlschema", date_s__xmlschema, 1);
+ rb_define_singleton_method(cDate, "_xmlschema", date_s__xmlschema, -1);
rb_define_singleton_method(cDate, "xmlschema", date_s_xmlschema, -1);
- rb_define_singleton_method(cDate, "_rfc2822", date_s__rfc2822, 1);
- rb_define_singleton_method(cDate, "_rfc822", date_s__rfc2822, 1);
+ rb_define_singleton_method(cDate, "_rfc2822", date_s__rfc2822, -1);
+ rb_define_singleton_method(cDate, "_rfc822", date_s__rfc2822, -1);
rb_define_singleton_method(cDate, "rfc2822", date_s_rfc2822, -1);
rb_define_singleton_method(cDate, "rfc822", date_s_rfc2822, -1);
- rb_define_singleton_method(cDate, "_httpdate", date_s__httpdate, 1);
+ rb_define_singleton_method(cDate, "_httpdate", date_s__httpdate, -1);
rb_define_singleton_method(cDate, "httpdate", date_s_httpdate, -1);
- rb_define_singleton_method(cDate, "_jisx0301", date_s__jisx0301, 1);
+ rb_define_singleton_method(cDate, "_jisx0301", date_s__jisx0301, -1);
rb_define_singleton_method(cDate, "jisx0301", date_s_jisx0301, -1);
#ifndef NDEBUG
diff --git a/test/date/test_date_parse.rb b/test/date/test_date_parse.rb
index ac0eb85ca7..f9b160ee8c 100644
--- a/test/date/test_date_parse.rb
+++ b/test/date/test_date_parse.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'test/unit'
require 'date'
+require 'timeout'
class TestDateParse < Test::Unit::TestCase
@@ -1122,4 +1123,32 @@ def test_given_string
assert_equal(s0, s)
end
+ def test_length_limit
+ assert_raise(ArgumentError) { Date._parse("1" * 1000) }
+ assert_raise(ArgumentError) { Date._iso8601("1" * 1000) }
+ assert_raise(ArgumentError) { Date._rfc3339("1" * 1000) }
+ assert_raise(ArgumentError) { Date._xmlschema("1" * 1000) }
+ assert_raise(ArgumentError) { Date._rfc2822("1" * 1000) }
+ assert_raise(ArgumentError) { Date._rfc822("1" * 1000) }
+ assert_raise(ArgumentError) { Date._jisx0301("1" * 1000) }
+
+ assert_raise(ArgumentError) { Date.parse("1" * 1000) }
+ assert_raise(ArgumentError) { Date.iso8601("1" * 1000) }
+ assert_raise(ArgumentError) { Date.rfc3339("1" * 1000) }
+ assert_raise(ArgumentError) { Date.xmlschema("1" * 1000) }
+ assert_raise(ArgumentError) { Date.rfc2822("1" * 1000) }
+ assert_raise(ArgumentError) { Date.rfc822("1" * 1000) }
+ assert_raise(ArgumentError) { Date.jisx0301("1" * 1000) }
+
+ assert_raise(ArgumentError) { DateTime.parse("1" * 1000) }
+ assert_raise(ArgumentError) { DateTime.iso8601("1" * 1000) }
+ assert_raise(ArgumentError) { DateTime.rfc3339("1" * 1000) }
+ assert_raise(ArgumentError) { DateTime.xmlschema("1" * 1000) }
+ assert_raise(ArgumentError) { DateTime.rfc2822("1" * 1000) }
+ assert_raise(ArgumentError) { DateTime.rfc822("1" * 1000) }
+ assert_raise(ArgumentError) { DateTime.jisx0301("1" * 1000) }
+
+ assert_raise(ArgumentError) { Date._parse("Jan " + "9" * 1000000) }
+ assert_raise(Timeout::Error) { Timeout.timeout(1) { Date._parse("Jan " + "9" * 1000000, limit: nil) } }
+ end
end
--
2.36.1

@ -1,77 +0,0 @@
From eca084e4079c77c061045df9c21b219175b05228 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADt=20Ondruch?= <vondruch@redhat.com>
Date: Mon, 6 Jan 2020 13:56:04 +0100
Subject: [PATCH] Initialize ABRT hook.
The ABRT hook used to be initialized by preludes via patches [[1], [2]].
Unfortunately, due to [[3]] and especially since [[4]], this would
require boostrapping [[5]].
To keep the things simple for now, load the ABRT hook via C.
[1]: https://bugs.ruby-lang.org/issues/8566
[2]: https://bugs.ruby-lang.org/issues/15306
[3]: https://bugs.ruby-lang.org/issues/16254
[4]: https://github.com/ruby/ruby/pull/2735
[5]: https://lists.fedoraproject.org/archives/list/ruby-sig@lists.fedoraproject.org/message/LH6L6YJOYQT4Y5ZNOO4SLIPTUWZ5V45Q/
---
abrt.c | 12 ++++++++++++
common.mk | 3 ++-
ruby.c | 4 ++++
3 files changed, 18 insertions(+), 1 deletion(-)
create mode 100644 abrt.c
diff --git a/abrt.c b/abrt.c
new file mode 100644
index 0000000000..74b0bd5c0f
--- /dev/null
+++ b/abrt.c
@@ -0,0 +1,12 @@
+#include "internal.h"
+
+void
+Init_abrt(void)
+{
+ rb_eval_string(
+ " begin\n"
+ " require 'abrt'\n"
+ " rescue LoadError\n"
+ " end\n"
+ );
+}
diff --git a/common.mk b/common.mk
index b2e5b2b6d0..f39f81da5c 100644
--- a/common.mk
+++ b/common.mk
@@ -81,7 +81,8 @@ ENC_MK = enc.mk
MAKE_ENC = -f $(ENC_MK) V="$(V)" UNICODE_HDR_DIR="$(UNICODE_HDR_DIR)" \
RUBY="$(MINIRUBY)" MINIRUBY="$(MINIRUBY)" $(mflags)
-COMMONOBJS = array.$(OBJEXT) \
+COMMONOBJS = abrt.$(OBJEXT) \
+ array.$(OBJEXT) \
ast.$(OBJEXT) \
bignum.$(OBJEXT) \
class.$(OBJEXT) \
diff --git a/ruby.c b/ruby.c
index 60c57d6259..1eec16f2c8 100644
--- a/ruby.c
+++ b/ruby.c
@@ -1501,10 +1501,14 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
void Init_builtin_features(void);
+/* abrt.c */
+void Init_abrt(void);
+
static void
ruby_init_prelude(void)
{
Init_builtin_features();
+ Init_abrt();
rb_const_remove(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"));
}
--
2.24.1

@ -1,34 +0,0 @@
From 9b42fce32bff25e0569581f76f532b9d57865aef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADt=20Ondruch?= <vondruch@redhat.com>
Date: Mon, 27 Jul 2020 14:56:05 +0200
Subject: [PATCH] Timeout the test_bug_reporter_add witout raising error.
While timeouting the threads might be still good idea, it does not seems
the timeout impacts the TestBugReporter#test_bug_reporter_add result,
because the output of the child process has been already collected
earlier.
It seems that when the system is under heavy load, the thread might not
be sheduled to finish its processing. Even finishing the child process
might take tens of seconds and therefore the test case finish might take
a while.
---
test/-ext-/bug_reporter/test_bug_reporter.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/-ext-/bug_reporter/test_bug_reporter.rb b/test/-ext-/bug_reporter/test_bug_reporter.rb
index 628fcd0340..2c677cc8a7 100644
--- a/test/-ext-/bug_reporter/test_bug_reporter.rb
+++ b/test/-ext-/bug_reporter/test_bug_reporter.rb
@@ -21,7 +21,7 @@ def test_bug_reporter_add
args = ["--disable-gems", "-r-test-/bug_reporter",
"-C", tmpdir]
stdin = "register_sample_bug_reporter(12345); Process.kill :SEGV, $$"
- assert_in_out_err(args, stdin, [], expected_stderr, encoding: "ASCII-8BIT")
+ assert_in_out_err(args, stdin, [], expected_stderr, encoding: "ASCII-8BIT", timeout_error: nil)
ensure
FileUtils.rm_rf(tmpdir) if tmpdir
end
--
2.27.0

@ -0,0 +1,328 @@
From 8fc4b4792919c627183f4ddb6dc256aae49eb738 Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Date: Tue, 22 Nov 2022 13:48:18 +0900
Subject: [PATCH] Fix CVE-2021-33621 HTTP response splitting in CGI.
Backported from upstream Ruby, commit:
https://github.com/ruby/ruby/commit/7cf697179dab52b0d024543304f4d3ab5fa5e847
Test "CGICookieTest#test_cgi_cookie_new_with_domain" was adjusted to
deal with Ruby 2.5 not allowing String with double splat operator.
==== Original commit message
Merge CGI-0.1.0.2
---
lib/cgi/cookie.rb | 51 ++++++++++++++++-------
lib/cgi/core.rb | 45 ++++++++++++--------
test/cgi/test_cgi_cookie.rb | 82 +++++++++++++++++++++++++++++++++++++
test/cgi/test_cgi_header.rb | 8 ++++
4 files changed, 154 insertions(+), 32 deletions(-)
diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb
index 009566b..f26f015 100644
--- a/lib/cgi/cookie.rb
+++ b/lib/cgi/cookie.rb
@@ -40,6 +40,10 @@ class CGI
class Cookie < Array
@@accept_charset="UTF-8" unless defined?(@@accept_charset)
+ TOKEN_RE = %r"\A[[!-~]&&[^()<>@,;:\\\"/?=\[\]{}]]+\z"
+ PATH_VALUE_RE = %r"\A[[ -~]&&[^;]]*\z"
+ DOMAIN_VALUE_RE = %r"\A(?<label>(?!-)[-A-Za-z0-9]+(?<!-))(?:\.\g<label>)*\z"
+
# Create a new CGI::Cookie object.
#
# :call-seq:
@@ -72,9 +76,8 @@ class CGI
@domain = nil
@expires = nil
if name.kind_of?(String)
- @name = name
- %r|^(.*/)|.match(ENV["SCRIPT_NAME"])
- @path = ($1 or "")
+ self.name = name
+ self.path = (%r|\A(.*/)| =~ ENV["SCRIPT_NAME"] ? $1 : "")
@secure = false
@httponly = false
return super(value)
@@ -85,16 +88,11 @@ class CGI
raise ArgumentError, "`name' required"
end
- @name = options["name"]
+ self.name = options["name"]
value = Array(options["value"])
# simple support for IE
- if options["path"]
- @path = options["path"]
- else
- %r|^(.*/)|.match(ENV["SCRIPT_NAME"])
- @path = ($1 or "")
- end
- @domain = options["domain"]
+ self.path = options["path"] || (%r|\A(.*/)| =~ ENV["SCRIPT_NAME"] ? $1 : "")
+ self.domain = options["domain"]
@expires = options["expires"]
@secure = options["secure"] == true
@httponly = options["httponly"] == true
@@ -102,12 +100,35 @@ class CGI
super(value)
end
- # Name of this cookie, as a +String+
- attr_accessor :name
+ attr_reader :name
+ # Set name of this cookie
+ def name=(str)
+ if str and !TOKEN_RE.match?(str)
+ raise ArgumentError, "invalid name: #{str.dump}"
+ end
+ @name = str
+ end
+
# Path for which this cookie applies, as a +String+
- attr_accessor :path
+ attr_reader :path
+ # Set path for which this cookie applies
+ def path=(str)
+ if str and !PATH_VALUE_RE.match?(str)
+ raise ArgumentError, "invalid path: #{str.dump}"
+ end
+ @path = str
+ end
+
# Domain for which this cookie applies, as a +String+
- attr_accessor :domain
+ attr_reader :domain
+ # Set domain for which this cookie applies
+ def domain=(str)
+ if str and ((str = str.b).bytesize > 255 or !DOMAIN_VALUE_RE.match?(str))
+ raise ArgumentError, "invalid domain: #{str.dump}"
+ end
+ @domain = str
+ end
+
# Time at which this cookie expires, as a +Time+
attr_accessor :expires
# True if this cookie is secure; false otherwise
diff --git a/lib/cgi/core.rb b/lib/cgi/core.rb
index 9bd7798..7d8b223 100644
--- a/lib/cgi/core.rb
+++ b/lib/cgi/core.rb
@@ -188,17 +188,28 @@ class CGI
# Using #header with the HTML5 tag maker will create a <header> element.
alias :header :http_header
+ def _no_crlf_check(str)
+ if str
+ str = str.to_s
+ raise "A HTTP status or header field must not include CR and LF" if str =~ /[\r\n]/
+ str
+ else
+ nil
+ end
+ end
+ private :_no_crlf_check
+
def _header_for_string(content_type) #:nodoc:
buf = ''.dup
if nph?()
- buf << "#{$CGI_ENV['SERVER_PROTOCOL'] || 'HTTP/1.0'} 200 OK#{EOL}"
+ buf << "#{_no_crlf_check($CGI_ENV['SERVER_PROTOCOL']) || 'HTTP/1.0'} 200 OK#{EOL}"
buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}"
- buf << "Server: #{$CGI_ENV['SERVER_SOFTWARE']}#{EOL}"
+ buf << "Server: #{_no_crlf_check($CGI_ENV['SERVER_SOFTWARE'])}#{EOL}"
buf << "Connection: close#{EOL}"
end
- buf << "Content-Type: #{content_type}#{EOL}"
+ buf << "Content-Type: #{_no_crlf_check(content_type)}#{EOL}"
if @output_cookies
- @output_cookies.each {|cookie| buf << "Set-Cookie: #{cookie}#{EOL}" }
+ @output_cookies.each {|cookie| buf << "Set-Cookie: #{_no_crlf_check(cookie)}#{EOL}" }
end
return buf
end # _header_for_string
@@ -213,9 +224,9 @@ class CGI
## NPH
options.delete('nph') if defined?(MOD_RUBY)
if options.delete('nph') || nph?()
- protocol = $CGI_ENV['SERVER_PROTOCOL'] || 'HTTP/1.0'
+ protocol = _no_crlf_check($CGI_ENV['SERVER_PROTOCOL']) || 'HTTP/1.0'
status = options.delete('status')
- status = HTTP_STATUS[status] || status || '200 OK'
+ status = HTTP_STATUS[status] || _no_crlf_check(status) || '200 OK'
buf << "#{protocol} #{status}#{EOL}"
buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}"
options['server'] ||= $CGI_ENV['SERVER_SOFTWARE'] || ''
@@ -223,38 +234,38 @@ class CGI
end
## common headers
status = options.delete('status')
- buf << "Status: #{HTTP_STATUS[status] || status}#{EOL}" if status
+ buf << "Status: #{HTTP_STATUS[status] || _no_crlf_check(status)}#{EOL}" if status
server = options.delete('server')
- buf << "Server: #{server}#{EOL}" if server
+ buf << "Server: #{_no_crlf_check(server)}#{EOL}" if server
connection = options.delete('connection')
- buf << "Connection: #{connection}#{EOL}" if connection
+ buf << "Connection: #{_no_crlf_check(connection)}#{EOL}" if connection
type = options.delete('type')
- buf << "Content-Type: #{type}#{EOL}" #if type
+ buf << "Content-Type: #{_no_crlf_check(type)}#{EOL}" #if type
length = options.delete('length')
- buf << "Content-Length: #{length}#{EOL}" if length
+ buf << "Content-Length: #{_no_crlf_check(length)}#{EOL}" if length
language = options.delete('language')
- buf << "Content-Language: #{language}#{EOL}" if language
+ buf << "Content-Language: #{_no_crlf_check(language)}#{EOL}" if language
expires = options.delete('expires')
buf << "Expires: #{CGI.rfc1123_date(expires)}#{EOL}" if expires
## cookie
if cookie = options.delete('cookie')
case cookie
when String, Cookie
- buf << "Set-Cookie: #{cookie}#{EOL}"
+ buf << "Set-Cookie: #{_no_crlf_check(cookie)}#{EOL}"
when Array
arr = cookie
- arr.each {|c| buf << "Set-Cookie: #{c}#{EOL}" }
+ arr.each {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" }
when Hash
hash = cookie
- hash.each_value {|c| buf << "Set-Cookie: #{c}#{EOL}" }
+ hash.each_value {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" }
end
end
if @output_cookies
- @output_cookies.each {|c| buf << "Set-Cookie: #{c}#{EOL}" }
+ @output_cookies.each {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" }
end
## other headers
options.each do |key, value|
- buf << "#{key}: #{value}#{EOL}"
+ buf << "#{_no_crlf_check(key)}: #{_no_crlf_check(value)}#{EOL}"
end
return buf
end # _header_for_hash
diff --git a/test/cgi/test_cgi_cookie.rb b/test/cgi/test_cgi_cookie.rb
index 985cc0d..7afff5e 100644
--- a/test/cgi/test_cgi_cookie.rb
+++ b/test/cgi/test_cgi_cookie.rb
@@ -60,6 +60,24 @@ class CGICookieTest < Test::Unit::TestCase
end
+ def test_cgi_cookie_new_with_domain
+ h = {'name'=>'name1', 'value'=>'value1'}
+ cookie = CGI::Cookie.new({'domain' => 'a.example.com'}.merge(h))
+ assert_equal('a.example.com', cookie.domain)
+
+ cookie = CGI::Cookie.new({'domain'=>'1.example.com'}.merge(h))
+ assert_equal('1.example.com', cookie.domain, 'enhanced by RFC 1123')
+
+ assert_raise(ArgumentError) {
+ CGI::Cookie.new({'domain'=>'-a.example.com'}.merge(h))
+ }
+
+ assert_raise(ArgumentError) {
+ CGI::Cookie.new({'domain'=>'a-.example.com'}.merge(h))
+ }
+ end
+
+
def test_cgi_cookie_scriptname
cookie = CGI::Cookie.new('name1', 'value1')
assert_equal('', cookie.path)
@@ -118,6 +136,70 @@ class CGICookieTest < Test::Unit::TestCase
end
+ def test_cgi_cookie_domain_injection_into_name
+ name = "a=b; domain=example.com;"
+ path = "/"
+ domain = "example.jp"
+ assert_raise(ArgumentError) do
+ CGI::Cookie.new('name' => name,
+ 'value' => "value",
+ 'domain' => domain,
+ 'path' => path)
+ end
+ end
+
+
+ def test_cgi_cookie_newline_injection_into_name
+ name = "a=b;\r\nLocation: http://example.com#"
+ path = "/"
+ domain = "example.jp"
+ assert_raise(ArgumentError) do
+ CGI::Cookie.new('name' => name,
+ 'value' => "value",
+ 'domain' => domain,
+ 'path' => path)
+ end
+ end
+
+
+ def test_cgi_cookie_multibyte_injection_into_name
+ name = "a=b;\u3042"
+ path = "/"
+ domain = "example.jp"
+ assert_raise(ArgumentError) do
+ CGI::Cookie.new('name' => name,
+ 'value' => "value",
+ 'domain' => domain,
+ 'path' => path)
+ end
+ end
+
+
+ def test_cgi_cookie_injection_into_path
+ name = "name"
+ path = "/; samesite=none"
+ domain = "example.jp"
+ assert_raise(ArgumentError) do
+ CGI::Cookie.new('name' => name,
+ 'value' => "value",
+ 'domain' => domain,
+ 'path' => path)
+ end
+ end
+
+
+ def test_cgi_cookie_injection_into_domain
+ name = "name"
+ path = "/"
+ domain = "example.jp; samesite=none"
+ assert_raise(ArgumentError) do
+ CGI::Cookie.new('name' => name,
+ 'value' => "value",
+ 'domain' => domain,
+ 'path' => path)
+ end
+ end
+
instance_methods.each do |method|
private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
diff --git a/test/cgi/test_cgi_header.rb b/test/cgi/test_cgi_header.rb
index bab2d03..ec2f4de 100644
--- a/test/cgi/test_cgi_header.rb
+++ b/test/cgi/test_cgi_header.rb
@@ -176,6 +176,14 @@ class CGIHeaderTest < Test::Unit::TestCase
end
+ def test_cgi_http_header_crlf_injection
+ cgi = CGI.new
+ assert_raise(RuntimeError) { cgi.http_header("text/xhtml\r\nBOO") }
+ assert_raise(RuntimeError) { cgi.http_header("type" => "text/xhtml\r\nBOO") }
+ assert_raise(RuntimeError) { cgi.http_header("status" => "200 OK\r\nBOO") }
+ assert_raise(RuntimeError) { cgi.http_header("location" => "text/xhtml\r\nBOO") }
+ end
+
instance_methods.each do |method|
private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
--
2.41.0

@ -0,0 +1,52 @@
From 61fb466ea0b492c990fcd2d681c08f2001d7a659 Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Date: Tue, 28 Mar 2023 17:33:19 +0900
Subject: [PATCH] Fix CVE-2023-28755 ReDos vulnerability in URI.
This patch was backported from Ruby 2.7.8
Backported from upstream Ruby, commit:
https://github.com/ruby/ruby/commit/6855779d580358a6a0b4c9ee06f20e7cae72955a
===== Original commit message
Merge URI-0.10.0.2
---
lib/uri/rfc3986_parser.rb | 4 ++--
test/uri/test_parser.rb | 7 +++++++
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/lib/uri/rfc3986_parser.rb b/lib/uri/rfc3986_parser.rb
index 8712800..ad32368 100644
--- a/lib/uri/rfc3986_parser.rb
+++ b/lib/uri/rfc3986_parser.rb
@@ -3,8 +3,8 @@ module URI
class RFC3986_Parser # :nodoc:
# URI defined in RFC3986
# this regexp is modified not to host is not empty string
- RFC3986_URI = /\A(?<URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
- RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+)\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])+)(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
+ RFC3986_URI = /\A(?<URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*+):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])++))?(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
+ RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])++))?(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])++)(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
attr_reader :regexp
def initialize
diff --git a/test/uri/test_parser.rb b/test/uri/test_parser.rb
index 757ac86..2f70559 100644
--- a/test/uri/test_parser.rb
+++ b/test/uri/test_parser.rb
@@ -45,4 +45,11 @@ class URI::TestParser < Test::Unit::TestCase
URI.parse(1)
end
end
+
+ def test_split
+ assert_equal(["http", nil, "example.com", nil, nil, "", nil, nil, nil], URI.split("http://example.com"))
+ assert_equal(["http", nil, "[0::0]", nil, nil, "", nil, nil, nil], URI.split("http://[0::0]"))
+ assert_equal([nil, nil, "example.com", nil, nil, "", nil, nil, nil], URI.split("//example.com"))
+ assert_equal([nil, nil, "[0::0]", nil, nil, "", nil, nil, nil], URI.split("//[0::0]"))
+ end
end
--
2.41.0

@ -0,0 +1,41 @@
From 71c37c29defeab2c98ad4291807efe12427a209f Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@ruby-lang.org>
Date: Tue, 29 Nov 2022 16:22:15 +0900
Subject: [PATCH] Fix CVE-2023-28756 ReDoS vulnerability in Time.
Backported from: Ruby 2.7.8
Backported from the following commits:
https://github.com/ruby/ruby/commit/2cb830602f52e7e76c6781115e7938b21f881c4f
https://github.com/ruby/ruby/commit/e3f18f7d2e034f20053d7bf2fc7a50f8b7e1a27a
Do not include the test case, as assert_linear_time was introduced in Ruby 2.7.
==== Original commit message(s)
Fix quadratic backtracking on invalid time
Make RFC2822 regexp linear
https://hackerone.com/reports/1485501
---
lib/time.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/time.rb b/lib/time.rb
index eb46a03..cb6f1e4 100644
--- a/lib/time.rb
+++ b/lib/time.rb
@@ -474,8 +474,8 @@ class Time
(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+
(\d{2,})\s+
(\d{2})\s*
- :\s*(\d{2})\s*
- (?::\s*(\d{2}))?\s+
+ :\s*(\d{2})
+ (?:\s*:\s*(\d\d))?\s+
([+-]\d{4}|
UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[A-IK-Z])/ix =~ date
# Since RFC 2822 permit comments, the regexp has no right anchor.
--
2.41.0

@ -0,0 +1,26 @@
From 2becb920e431110c4afc4fa069b051c5940c2096 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@jeremyevans.net>
Date: Fri, 29 May 2020 14:13:30 -0700
Subject: [PATCH] Convert ip addresses to canonical form in
Resolv::DNS::Requester::UnconnectedUDP#sender
Otherwise, if the IP address given is not in canonical form, it
won't match, and Resolv will ignore it.
Fixes [Bug #16439]
---
lib/resolv.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/resolv.rb b/lib/resolv.rb
index e7b45e785a85..d78531e174fd 100644
--- a/lib/resolv.rb
+++ b/lib/resolv.rb
@@ -774,6 +774,7 @@ def recv_reply(readable_socks)
end
def sender(msg, data, host, port=Port)
+ host = Addrinfo.ip(host).ip_address
lazy_initialize
sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
return nil if !sock

@ -0,0 +1,25 @@
From a267a40be7844224c5f000530bd3e8e906f1acea Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@jeremyevans.net>
Date: Wed, 10 Mar 2021 13:48:00 -0800
Subject: [PATCH] Do not use a libdir for glibc, it breaks Linux PPC64 (#70)
Fixes [Bug #12666]
---
test/fiddle/helper.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/fiddle/helper.rb b/test/fiddle/helper.rb
index f38f903..a6e2019 100644
--- a/test/fiddle/helper.rb
+++ b/test/fiddle/helper.rb
@@ -20,8 +20,8 @@
# 64-bit ruby
libdir = '/lib64' if File.directory? '/lib64'
end
- libc_so = File.join(libdir, "libc.so.6")
- libm_so = File.join(libdir, "libm.so.6")
+ libc_so = "libc.so.6"
+ libm_so = "libm.so.6"
when /mingw/, /mswin/
require "rbconfig"
crtname = RbConfig::CONFIG["RUBY_SO_NAME"][/msvc\w+/] || 'ucrtbase'

@ -0,0 +1,44 @@
From 5d08bbb0415c2ecc10037837b81e6a27d40ee7be Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Date: Thu, 29 Jun 2023 22:25:17 +0900
Subject: [PATCH] CVE-2023-36617 for Ruby 3.0 (#7997)
* Merge URI-0.10.3
---
Backport note, bundler is not distributed the same as RubyGems in Ruby
2.5, therefore we do not use backport for Bundler.
---
lib/uri/rfc2396_parser.rb | 4 ++--
lib/uri/rfc3986_parser.rb | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/uri/rfc2396_parser.rb b/lib/uri/rfc2396_parser.rb
index b9e7b2b26e..c7c3ecd96d 100644
--- a/lib/uri/rfc2396_parser.rb
+++ b/lib/uri/rfc2396_parser.rb
@@ -502,8 +502,8 @@ def initialize_regexp(pattern)
ret = {}
# for URI::split
- ret[:ABS_URI] = Regexp.new('\A\s*' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
- ret[:REL_URI] = Regexp.new('\A\s*' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
+ ret[:ABS_URI] = Regexp.new('\A\s*+' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
+ ret[:REL_URI] = Regexp.new('\A\s*+' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
# for URI::extract
ret[:URI_REF] = Regexp.new(pattern[:URI_REF])
diff --git a/lib/uri/rfc3986_parser.rb b/lib/uri/rfc3986_parser.rb
index ad32368cfa..1accd03376 100644
--- a/lib/uri/rfc3986_parser.rb
+++ b/lib/uri/rfc3986_parser.rb
@@ -106,7 +106,7 @@ def default_regexp # :nodoc:
QUERY: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
FRAGMENT: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
OPAQUE: /\A(?:[^\/].*)?\z/,
- PORT: /\A[\x09\x0a\x0c\x0d ]*\d*[\x09\x0a\x0c\x0d ]*\z/,
+ PORT: /\A[\x09\x0a\x0c\x0d ]*+\d*[\x09\x0a\x0c\x0d ]*\z/,
}
end

@ -0,0 +1,81 @@
From 740289bf02c9bea54f75b702f62862c62c62672b Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Date: Thu, 21 Mar 2024 15:55:48 +0900
Subject: [PATCH] Merge StringIO 3.0.1.1
---
ext/stringio/stringio.c | 2 +-
test/stringio/test_stringio.rb | 27 ++++++++++++++++++++++-----
2 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c
index f537054b5d..946ae06da4 100644
--- a/ext/stringio/stringio.c
+++ b/ext/stringio/stringio.c
@@ -833,7 +833,7 @@ strio_unget_bytes(struct StringIO *ptr, const char *cp, long cl)
len = RSTRING_LEN(str);
rest = pos - len;
if (cl > pos) {
- long ex = (rest < 0 ? cl-pos : cl+rest);
+ long ex = cl - (rest < 0 ? pos : len);
rb_str_modify_expand(str, ex);
rb_str_set_len(str, len + ex);
s = RSTRING_PTR(str);
diff --git a/test/stringio/test_stringio.rb b/test/stringio/test_stringio.rb
index f5169f641a..c055b901e3 100644
--- a/test/stringio/test_stringio.rb
+++ b/test/stringio/test_stringio.rb
@@ -693,6 +693,15 @@ def test_ungetc_padding
assert_equal("b""\0""a", s.string)
end
+ def test_ungetc_fill
+ count = 100
+ s = StringIO.new
+ s.print 'a' * count
+ s.ungetc('b' * (count * 5))
+ assert_equal((count * 5), s.string.size)
+ assert_match(/\Ab+\z/, s.string)
+ end
+
def test_ungetbyte_pos
b = '\\b00010001 \\B00010001 \\b1 \\B1 \\b000100011'
s = StringIO.new( b )
@@ -718,6 +727,15 @@ def test_ungetbyte_padding
assert_equal("b""\0""a", s.string)
end
+ def test_ungetbyte_fill
+ count = 100
+ s = StringIO.new
+ s.print 'a' * count
+ s.ungetbyte('b' * (count * 5))
+ assert_equal((count * 5), s.string.size)
+ assert_match(/\Ab+\z/, s.string)
+ end
+
def test_frozen
s = StringIO.new
s.freeze
@@ -760,18 +778,17 @@ def test_new_block_warning
end
def test_overflow
- skip if RbConfig::SIZEOF["void*"] > RbConfig::SIZEOF["long"]
+ return if RbConfig::SIZEOF["void*"] > RbConfig::SIZEOF["long"]
limit = (1 << (RbConfig::SIZEOF["void*"]*8-1)) - 0x10
assert_separately(%w[-rstringio], "#{<<-"begin;"}\n#{<<-"end;"}")
begin;
limit = #{limit}
ary = []
- while true
+ begin
x = "a"*0x100000
break if [x].pack("p").unpack("i!")[0] < 0
ary << x
- skip if ary.size > 100
- end
+ end while ary.size <= 100
s = StringIO.new(x)
s.gets("xxx", limit)
assert_equal(0x100000, s.pos)

@ -0,0 +1,203 @@
From 7957a25edf844c966de45848fa7e9e2513955660 Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Date: Thu, 21 Mar 2024 15:47:40 +0900
Subject: [PATCH 1/2] Merge RDoc-6.3.4.1
---
lib/rdoc/rdoc.rb | 3 ++-
lib/rdoc/store.rb | 45 ++++++++++++++++++++--------------
test/rdoc/test_rdoc_options.rb | 6 ++---
3 files changed, 31 insertions(+), 23 deletions(-)
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index a2711fbbd1..c5690fc3b4 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -162,8 +162,9 @@ def load_options
RDoc.load_yaml
begin
- options = YAML.load_file '.rdoc_options'
+ options = YAML.safe_load_file '.rdoc_options', permitted_classes: [RDoc::Options, Symbol]
rescue Psych::SyntaxError
+ raise RDoc::Error, "#{options_file} is not a valid rdoc options file"
end
raise RDoc::Error, "#{options_file} is not a valid rdoc options file" unless
diff --git a/lib/rdoc/store.rb b/lib/rdoc/store.rb
index 999aa76f92..07d03e90f7 100644
--- a/lib/rdoc/store.rb
+++ b/lib/rdoc/store.rb
@@ -539,9 +539,7 @@ def load_all
def load_cache
#orig_enc = @encoding
- open cache_path, 'rb' do |io|
- @cache = Marshal.load io.read
- end
+ @cache = marshal_load(cache_path)
load_enc = @cache[:encoding]
@@ -596,9 +594,7 @@ def load_class klass_name
def load_class_data klass_name
file = class_file klass_name
- open file, 'rb' do |io|
- Marshal.load io.read
- end
+ marshal_load(file)
rescue Errno::ENOENT => e
error = MissingFileError.new(self, file, klass_name)
error.set_backtrace e.backtrace
@@ -611,14 +607,10 @@ def load_class_data klass_name
def load_method klass_name, method_name
file = method_file klass_name, method_name
- open file, 'rb' do |io|
- obj = Marshal.load io.read
- obj.store = self
- obj.parent =
- find_class_or_module(klass_name) || load_class(klass_name) unless
- obj.parent
- obj
- end
+ obj = marshal_load(file)
+ obj.store = self
+ obj.parent ||= find_class_or_module(klass_name) || load_class(klass_name)
+ obj
rescue Errno::ENOENT => e
error = MissingFileError.new(self, file, klass_name + method_name)
error.set_backtrace e.backtrace
@@ -631,11 +623,9 @@ def load_method klass_name, method_name
def load_page page_name
file = page_file page_name
- open file, 'rb' do |io|
- obj = Marshal.load io.read
- obj.store = self
- obj
- end
+ obj = marshal_load(file)
+ obj.store = self
+ obj
rescue Errno::ENOENT => e
error = MissingFileError.new(self, file, page_name)
error.set_backtrace e.backtrace
@@ -965,4 +955,21 @@ def unique_modules
@unique_modules
end
+ private
+ def marshal_load(file)
+ File.open(file, 'rb') {|io| Marshal.load(io, MarshalFilter)}
+ end
+
+ MarshalFilter = proc do |obj|
+ case obj
+ when true, false, nil, Array, Class, Encoding, Hash, Integer, String, Symbol, RDoc::Text
+ else
+ unless obj.class.name.start_with?("RDoc::")
+ raise TypeError, "not permitted class: #{obj.class.name}"
+ end
+ end
+ obj
+ end
+ private_constant :MarshalFilter
+
end
diff --git a/test/rdoc/test_rdoc_options.rb b/test/rdoc/test_rdoc_options.rb
index 400ed9a549..247c7c87ce 100644
--- a/test/rdoc/test_rdoc_options.rb
+++ b/test/rdoc/test_rdoc_options.rb
@@ -145,7 +145,7 @@ def test_init_with_encoding
@options.encoding = Encoding::IBM437
- options = YAML.load YAML.dump @options
+ options = YAML.safe_load(YAML.dump(@options), permitted_classes: [RDoc::Options, Symbol])
assert_equal Encoding::IBM437, options.encoding
end
@@ -161,7 +161,7 @@ def test_init_with_trim_paths
- /etc
YAML
- options = YAML.load yaml
+ options = YAML.safe_load(yaml, permitted_classes: [RDoc::Options, Symbol])
assert_empty options.rdoc_include
assert_empty options.static_path
@@ -729,7 +729,7 @@ def test_write_options
assert File.exist? '.rdoc_options'
- assert_equal @options, YAML.load(File.read('.rdoc_options'))
+ assert_equal @options, YAML.safe_load(File.read('.rdoc_options'), permitted_classes: [RDoc::Options, Symbol])
end
end
From 153a4d16058783c923d0df5b1cbe2610ef96e3a8 Mon Sep 17 00:00:00 2001
From: Jarek Prokop <jprokop@redhat.com>
Date: Tue, 28 May 2024 16:56:26 +0200
Subject: [PATCH 2/2] Port the rebase to work with Ruby 2.5.9.
Ruby 2.5's Psych does not have safe_load_file method.
However, from Ruby 3.3's sources, the method is just File.read
simple wrapper with a safe_load call. Therefore it was copied over to
the lib/rdoc/rdoc.rb file.
---
lib/rdoc/rdoc.rb | 9 ++++++-
test/rdoc/test_rdoc_options.rb | 6 +++---
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index c5690fc3b4..435cd2eaf0 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -162,7 +162,12 @@ def load_options
RDoc.load_yaml
begin
- options = YAML.safe_load_file '.rdoc_options', permitted_classes: [RDoc::Options, Symbol]
+ # Opening file inspired from Ruby 3.3.0 sources,
+ # file 'ext/psych/lib/psych.rb', line 658.
+ # https://github.com/ruby/ruby/blob/v3_3_0/ext/psych/lib/psych.rb#L658
+ options = File.open('.rdoc_options', 'r:bom|utf-8') do |file|
+ YAML.safe_load file, [RDoc::Options, Symbol], [], false, '.rdoc_options'
+ end
rescue Psych::SyntaxError
raise RDoc::Error, "#{options_file} is not a valid rdoc options file"
end
diff --git a/test/rdoc/test_rdoc_options.rb b/test/rdoc/test_rdoc_options.rb
index 247c7c87ce..60fe035dce 100644
--- a/test/rdoc/test_rdoc_options.rb
+++ b/test/rdoc/test_rdoc_options.rb
@@ -145,7 +145,7 @@ def test_init_with_encoding
@options.encoding = Encoding::IBM437
- options = YAML.safe_load(YAML.dump(@options), permitted_classes: [RDoc::Options, Symbol])
+ options = YAML.safe_load(YAML.dump(@options), [RDoc::Options, Symbol])
assert_equal Encoding::IBM437, options.encoding
end
@@ -161,7 +161,7 @@ def test_init_with_trim_paths
- /etc
YAML
- options = YAML.safe_load(yaml, permitted_classes: [RDoc::Options, Symbol])
+ options = YAML.safe_load(yaml, [RDoc::Options, Symbol])
assert_empty options.rdoc_include
assert_empty options.static_path
@@ -729,7 +729,7 @@ def test_write_options
assert File.exist? '.rdoc_options'
- assert_equal @options, YAML.safe_load(File.read('.rdoc_options'), permitted_classes: [RDoc::Options, Symbol])
+ assert_equal @options, YAML.safe_load(File.read('.rdoc_options'), [RDoc::Options, Symbol])
end
end

@ -0,0 +1,48 @@
From 9eda3000e3efd5bdd4ed60d07e2f43633e39d361 Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Date: Tue, 23 Apr 2024 19:22:22 +0900
Subject: [PATCH] merge revision(s) 33e5b47c16f1fd3382186e6ffe73cfc6e00946f7:
Fix handling of reg->dmin in Regex matching
---
regexec.c | 10 ++++++++++
1 file changed, 10 insertions(+)
---
regexec.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/regexec.c b/regexec.c
index 4582c35c3f..36ac1d4bc5 100644
--- a/regexec.c
+++ b/regexec.c
@@ -3900,12 +3900,17 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,
UChar* range, UChar** low, UChar** high, UChar** low_prev)
{
UChar *p, *pprev = (UChar* )NULL;
+ size_t input_len = end - str;
#ifdef ONIG_DEBUG_SEARCH
fprintf(stderr, "forward_search_range: str: %"PRIuPTR" (%p), end: %"PRIuPTR" (%p), s: %"PRIuPTR" (%p), range: %"PRIuPTR" (%p)\n",
(uintptr_t )str, str, (uintptr_t )end, end, (uintptr_t )s, s, (uintptr_t )range, range);
#endif
+ if (reg->dmin > input_len) {
+ return 0;
+ }
+
p = s;
if (reg->dmin > 0) {
if (ONIGENC_IS_SINGLEBYTE(reg->enc)) {
@@ -4042,6 +4047,11 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end,
UChar** low, UChar** high)
{
UChar *p;
+ size_t input_len = end - str;
+
+ if (reg->dmin > input_len) {
+ return 0;
+ }
range += reg->dmin;
p = s;

@ -1,630 +0,0 @@
From 316cb2a41f154e4663d7e7fead60cfc0bfa86af9 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Mon, 12 Apr 2021 13:55:10 +0900
Subject: [PATCH 1/2] pkey: do not check NULL argument in ossl_pkey_new()
Passing NULL to ossl_pkey_new() makes no sense in the first place, and
in fact it is ensured not to be NULL in all cases.
---
ext/openssl/ossl_pkey.c | 6 +-----
ext/openssl/ossl_pkey.h | 1 +
2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index f9f5162e..820e4a2c 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -38,12 +38,8 @@ static VALUE
pkey_new0(EVP_PKEY *pkey)
{
VALUE klass, obj;
- int type;
- if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE)
- ossl_raise(rb_eRuntimeError, "pkey is empty");
-
- switch (type) {
+ switch (EVP_PKEY_base_id(pkey)) {
#if !defined(OPENSSL_NO_RSA)
case EVP_PKEY_RSA: klass = cRSA; break;
#endif
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index 4beede22..f0476780 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -35,6 +35,7 @@ extern const rb_data_type_t ossl_evp_pkey_type;
} \
} while (0)
+/* Takes ownership of the EVP_PKEY */
VALUE ossl_pkey_new(EVP_PKEY *);
void ossl_pkey_check_public_key(const EVP_PKEY *);
EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE);
From 74f6c6175688502a5bf27ae35367616858630c0f Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Mon, 12 Apr 2021 18:32:40 +0900
Subject: [PATCH 2/2] pkey: allocate EVP_PKEY on #initialize
Allocate an EVP_PKEY when the content is ready: when #initialize
or #initialize_copy is called, rather than when a T_DATA is allocated.
This is more natural because the lower level API has been deprecated
and an EVP_PKEY is becoming the minimum unit of handling keys.
---
ext/openssl/ossl_pkey.c | 15 ++----
ext/openssl/ossl_pkey.h | 15 ++----
ext/openssl/ossl_pkey_dh.c | 71 +++++++++++++++++++--------
ext/openssl/ossl_pkey_dsa.c | 93 ++++++++++++++++++++---------------
ext/openssl/ossl_pkey_ec.c | 91 +++++++++++++++++++----------------
ext/openssl/ossl_pkey_rsa.c | 96 ++++++++++++++++++++++---------------
6 files changed, 218 insertions(+), 163 deletions(-)
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 820e4a2c..ea75d63f 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -54,8 +54,8 @@ pkey_new0(EVP_PKEY *pkey)
#endif
default: klass = cPKey; break;
}
- obj = NewPKey(klass);
- SetPKey(obj, pkey);
+ obj = rb_obj_alloc(klass);
+ RTYPEDDATA_DATA(obj) = pkey;
return obj;
}
@@ -511,16 +511,7 @@ DupPKeyPtr(VALUE obj)
static VALUE
ossl_pkey_alloc(VALUE klass)
{
- EVP_PKEY *pkey;
- VALUE obj;
-
- obj = NewPKey(klass);
- if (!(pkey = EVP_PKEY_new())) {
- ossl_raise(ePKeyError, NULL);
- }
- SetPKey(obj, pkey);
-
- return obj;
+ return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL);
}
/*
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index f0476780..ed18bc69 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -15,19 +15,10 @@ extern VALUE cPKey;
extern VALUE ePKeyError;
extern const rb_data_type_t ossl_evp_pkey_type;
-#define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue)
-#define OSSL_PKEY_SET_PUBLIC(obj) rb_iv_set((obj), "private", Qfalse)
-#define OSSL_PKEY_IS_PRIVATE(obj) (rb_iv_get((obj), "private") == Qtrue)
+/* For ENGINE */
+#define OSSL_PKEY_SET_PRIVATE(obj) rb_ivar_set((obj), rb_intern("private"), Qtrue)
+#define OSSL_PKEY_IS_PRIVATE(obj) (rb_attr_get((obj), rb_intern("private")) == Qtrue)
-#define NewPKey(klass) \
- TypedData_Wrap_Struct((klass), &ossl_evp_pkey_type, 0)
-#define SetPKey(obj, pkey) do { \
- if (!(pkey)) { \
- rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \
- } \
- RTYPEDDATA_DATA(obj) = (pkey); \
- OSSL_PKEY_SET_PUBLIC(obj); \
-} while (0)
#define GetPKey(obj, pkey) do {\
TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \
if (!(pkey)) { \
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index ca782bbe..04c11b21 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -72,34 +72,57 @@ static VALUE
ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
+ int type;
DH *dh;
- BIO *in;
+ BIO *in = NULL;
VALUE arg;
- GetPKey(self, pkey);
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
+
/* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
dh = DH_new();
if (!dh)
ossl_raise(eDHError, "DH_new");
+ goto legacy;
}
- else {
- arg = ossl_to_der_if_possible(arg);
- in = ossl_obj2bio(&arg);
- dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
- if (!dh){
- OSSL_BIO_reset(in);
- dh = d2i_DHparams_bio(in, NULL);
- }
- BIO_free(in);
- if (!dh) {
- ossl_raise(eDHError, NULL);
- }
+
+ arg = ossl_to_der_if_possible(arg);
+ in = ossl_obj2bio(&arg);
+
+ /*
+ * On OpenSSL <= 1.1.1 and current versions of LibreSSL, the generic
+ * routine does not support DER-encoded parameters
+ */
+ dh = d2i_DHparams_bio(in, NULL);
+ if (dh)
+ goto legacy;
+ OSSL_BIO_reset(in);
+
+ pkey = ossl_pkey_read_generic(in, Qnil);
+ BIO_free(in);
+ if (!pkey)
+ ossl_raise(eDHError, "could not parse pkey");
+
+ type = EVP_PKEY_base_id(pkey);
+ if (type != EVP_PKEY_DH) {
+ EVP_PKEY_free(pkey);
+ rb_raise(eDHError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
- if (!EVP_PKEY_assign_DH(pkey, dh)) {
- DH_free(dh);
- ossl_raise(eDHError, NULL);
+ RTYPEDDATA_DATA(self) = pkey;
+ return self;
+
+ legacy:
+ BIO_free(in);
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
+ EVP_PKEY_free(pkey);
+ DH_free(dh);
+ ossl_raise(eDHError, "EVP_PKEY_assign_DH");
}
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
@@ -110,15 +133,14 @@ ossl_dh_initialize_copy(VALUE self, VALUE other)
DH *dh, *dh_other;
const BIGNUM *pub, *priv;
- GetPKey(self, pkey);
- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
- ossl_raise(eDHError, "DH already initialized");
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
GetDH(other, dh_other);
dh = DHparams_dup(dh_other);
if (!dh)
ossl_raise(eDHError, "DHparams_dup");
- EVP_PKEY_assign_DH(pkey, dh);
DH_get0_key(dh_other, &pub, &priv);
if (pub) {
@@ -133,6 +155,13 @@ ossl_dh_initialize_copy(VALUE self, VALUE other)
DH_set0_key(dh, pub2, priv2);
}
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
+ EVP_PKEY_free(pkey);
+ DH_free(dh);
+ ossl_raise(eDHError, "EVP_PKEY_assign_DH");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index 7af00eeb..15724548 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -83,50 +83,59 @@ VALUE eDSAError;
static VALUE
ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
{
- EVP_PKEY *pkey, *tmp;
- DSA *dsa = NULL;
- BIO *in;
+ EVP_PKEY *pkey;
+ DSA *dsa;
+ BIO *in = NULL;
VALUE arg, pass;
+ int type;
+
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
- GetPKey(self, pkey);
/* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
rb_scan_args(argc, argv, "02", &arg, &pass);
if (argc == 0) {
dsa = DSA_new();
if (!dsa)
ossl_raise(eDSAError, "DSA_new");
+ goto legacy;
}
- else {
- pass = ossl_pem_passwd_value(pass);
- arg = ossl_to_der_if_possible(arg);
- in = ossl_obj2bio(&arg);
-
- tmp = ossl_pkey_read_generic(in, pass);
- if (tmp) {
- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_DSA)
- rb_raise(eDSAError, "incorrect pkey type: %s",
- OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
- dsa = EVP_PKEY_get1_DSA(tmp);
- EVP_PKEY_free(tmp);
- }
- if (!dsa) {
- OSSL_BIO_reset(in);
-#define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \
- (d2i_of_void *)d2i_DSAPublicKey, PEM_STRING_DSA_PUBLIC, (bp), (void **)(x), (cb), (u))
- dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL);
-#undef PEM_read_bio_DSAPublicKey
- }
- BIO_free(in);
- if (!dsa) {
- ossl_clear_error();
- ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
- }
- }
- if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
- DSA_free(dsa);
- ossl_raise(eDSAError, NULL);
+
+ pass = ossl_pem_passwd_value(pass);
+ arg = ossl_to_der_if_possible(arg);
+ in = ossl_obj2bio(&arg);
+
+ /* DER-encoded DSAPublicKey format isn't supported by the generic routine */
+ dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey,
+ PEM_STRING_DSA_PUBLIC,
+ in, NULL, NULL, NULL);
+ if (dsa)
+ goto legacy;
+ OSSL_BIO_reset(in);
+
+ pkey = ossl_pkey_read_generic(in, pass);
+ BIO_free(in);
+ if (!pkey)
+ ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
+
+ type = EVP_PKEY_base_id(pkey);
+ if (type != EVP_PKEY_DSA) {
+ EVP_PKEY_free(pkey);
+ rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
+ RTYPEDDATA_DATA(self) = pkey;
+ return self;
+ legacy:
+ BIO_free(in);
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) {
+ EVP_PKEY_free(pkey);
+ DSA_free(dsa);
+ ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
@@ -136,16 +145,24 @@ ossl_dsa_initialize_copy(VALUE self, VALUE other)
EVP_PKEY *pkey;
DSA *dsa, *dsa_new;
- GetPKey(self, pkey);
- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
- ossl_raise(eDSAError, "DSA already initialized");
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
GetDSA(other, dsa);
- dsa_new = ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, (d2i_of_void *)d2i_DSAPrivateKey, (char *)dsa);
+ dsa_new = (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey,
+ (d2i_of_void *)d2i_DSAPrivateKey,
+ (char *)dsa);
if (!dsa_new)
ossl_raise(eDSAError, "ASN1_dup");
- EVP_PKEY_assign_DSA(pkey, dsa_new);
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) {
+ EVP_PKEY_free(pkey);
+ DSA_free(dsa_new);
+ ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index db80d112..71e63969 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -114,13 +114,16 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg)
VALUE obj;
obj = rb_obj_alloc(klass);
- GetPKey(obj, pkey);
ec = ec_key_new_from_group(arg);
- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
+ EVP_PKEY_free(pkey);
EC_KEY_free(ec);
ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
}
+ RTYPEDDATA_DATA(obj) = pkey;
+
if (!EC_KEY_generate_key(ec))
ossl_raise(eECError, "EC_KEY_generate_key");
@@ -141,51 +144,54 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg)
static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- EC_KEY *ec = NULL;
+ EC_KEY *ec;
+ BIO *in;
VALUE arg, pass;
+ int type;
- GetPKey(self, pkey);
- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
- ossl_raise(eECError, "EC_KEY already initialized");
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
rb_scan_args(argc, argv, "02", &arg, &pass);
-
if (NIL_P(arg)) {
if (!(ec = EC_KEY_new()))
- ossl_raise(eECError, NULL);
- } else if (rb_obj_is_kind_of(arg, cEC)) {
- EC_KEY *other_ec = NULL;
+ ossl_raise(eECError, "EC_KEY_new");
+ goto legacy;
+ }
+ else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
+ ec = ec_key_new_from_group(arg);
+ goto legacy;
+ }
- GetEC(arg, other_ec);
- if (!(ec = EC_KEY_dup(other_ec)))
- ossl_raise(eECError, NULL);
- } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
- ec = ec_key_new_from_group(arg);
- } else {
- BIO *in = ossl_obj2bio(&arg);
- EVP_PKEY *tmp;
- pass = ossl_pem_passwd_value(pass);
- tmp = ossl_pkey_read_generic(in, pass);
- if (tmp) {
- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_EC)
- rb_raise(eECError, "incorrect pkey type: %s",
- OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
- ec = EVP_PKEY_get1_EC_KEY(tmp);
- EVP_PKEY_free(tmp);
- }
- BIO_free(in);
+ pass = ossl_pem_passwd_value(pass);
+ arg = ossl_to_der_if_possible(arg);
+ in = ossl_obj2bio(&arg);
- if (!ec) {
- ossl_clear_error();
- ec = ec_key_new_from_group(arg);
- }
+ pkey = ossl_pkey_read_generic(in, pass);
+ BIO_free(in);
+ if (!pkey) {
+ ossl_clear_error();
+ ec = ec_key_new_from_group(arg);
+ goto legacy;
}
- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
- EC_KEY_free(ec);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ type = EVP_PKEY_base_id(pkey);
+ if (type != EVP_PKEY_EC) {
+ EVP_PKEY_free(pkey);
+ rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
+ RTYPEDDATA_DATA(self) = pkey;
+ return self;
+ legacy:
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
+ EVP_PKEY_free(pkey);
+ EC_KEY_free(ec);
+ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
@@ -195,18 +201,21 @@ ossl_ec_key_initialize_copy(VALUE self, VALUE other)
EVP_PKEY *pkey;
EC_KEY *ec, *ec_new;
- GetPKey(self, pkey);
- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
- ossl_raise(eECError, "EC already initialized");
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
GetEC(other, ec);
ec_new = EC_KEY_dup(ec);
if (!ec_new)
ossl_raise(eECError, "EC_KEY_dup");
- if (!EVP_PKEY_assign_EC_KEY(pkey, ec_new)) {
- EC_KEY_free(ec_new);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_new) != 1) {
+ EC_KEY_free(ec_new);
+ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
}
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 8ebd3ec5..b8dbc0e1 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -76,51 +76,62 @@ VALUE eRSAError;
static VALUE
ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
{
- EVP_PKEY *pkey, *tmp;
- RSA *rsa = NULL;
- BIO *in;
+ EVP_PKEY *pkey;
+ RSA *rsa;
+ BIO *in = NULL;
VALUE arg, pass;
+ int type;
+
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
- GetPKey(self, pkey);
/* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
rb_scan_args(argc, argv, "02", &arg, &pass);
if (argc == 0) {
rsa = RSA_new();
if (!rsa)
ossl_raise(eRSAError, "RSA_new");
+ goto legacy;
}
- else {
- pass = ossl_pem_passwd_value(pass);
- arg = ossl_to_der_if_possible(arg);
- in = ossl_obj2bio(&arg);
-
- tmp = ossl_pkey_read_generic(in, pass);
- if (tmp) {
- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_RSA)
- rb_raise(eRSAError, "incorrect pkey type: %s",
- OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
- rsa = EVP_PKEY_get1_RSA(tmp);
- EVP_PKEY_free(tmp);
- }
- if (!rsa) {
- OSSL_BIO_reset(in);
- rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
- }
- if (!rsa) {
- OSSL_BIO_reset(in);
- rsa = d2i_RSAPublicKey_bio(in, NULL);
- }
- BIO_free(in);
- if (!rsa) {
- ossl_clear_error();
- ossl_raise(eRSAError, "Neither PUB key nor PRIV key");
- }
- }
- if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
- RSA_free(rsa);
- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+
+ pass = ossl_pem_passwd_value(pass);
+ arg = ossl_to_der_if_possible(arg);
+ in = ossl_obj2bio(&arg);
+
+ /* First try RSAPublicKey format */
+ rsa = d2i_RSAPublicKey_bio(in, NULL);
+ if (rsa)
+ goto legacy;
+ OSSL_BIO_reset(in);
+ rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
+ if (rsa)
+ goto legacy;
+ OSSL_BIO_reset(in);
+
+ /* Use the generic routine */
+ pkey = ossl_pkey_read_generic(in, pass);
+ BIO_free(in);
+ if (!pkey)
+ ossl_raise(eRSAError, "Neither PUB key nor PRIV key");
+
+ type = EVP_PKEY_base_id(pkey);
+ if (type != EVP_PKEY_RSA) {
+ EVP_PKEY_free(pkey);
+ rb_raise(eRSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
+ RTYPEDDATA_DATA(self) = pkey;
+ return self;
+ legacy:
+ BIO_free(in);
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
+ EVP_PKEY_free(pkey);
+ RSA_free(rsa);
+ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
@@ -130,16 +141,23 @@ ossl_rsa_initialize_copy(VALUE self, VALUE other)
EVP_PKEY *pkey;
RSA *rsa, *rsa_new;
- GetPKey(self, pkey);
- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
- ossl_raise(eRSAError, "RSA already initialized");
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
GetRSA(other, rsa);
- rsa_new = ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey, (d2i_of_void *)d2i_RSAPrivateKey, (char *)rsa);
+ rsa_new = (RSA *)ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey,
+ (d2i_of_void *)d2i_RSAPrivateKey,
+ (char *)rsa);
if (!rsa_new)
ossl_raise(eRSAError, "ASN1_dup");
- EVP_PKEY_assign_RSA(pkey, rsa_new);
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa_new) != 1) {
+ RSA_free(rsa_new);
+ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}

@ -1,358 +0,0 @@
From f2cf3afc6fa1e13e960f732c0bc658ad408ee219 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Fri, 12 Jun 2020 14:12:59 +0900
Subject: [PATCH 1/3] pkey: fix potential memory leak in PKey#sign
Fix potential leak of EVP_MD_CTX object in an error path. This path is
normally unreachable, since the size of a signature generated by any
supported algorithms would not be larger than LONG_MAX.
---
ext/openssl/ossl_pkey.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index df8b425a0f..7488190e0e 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -777,8 +777,10 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_DigestSign");
}
- if (siglen > LONG_MAX)
+ if (siglen > LONG_MAX) {
+ EVP_MD_CTX_free(ctx);
rb_raise(ePKeyError, "signature would be too large");
+ }
sig = ossl_str_new(NULL, (long)siglen, &state);
if (state) {
EVP_MD_CTX_free(ctx);
@@ -799,8 +801,10 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_DigestSignFinal");
}
- if (siglen > LONG_MAX)
+ if (siglen > LONG_MAX) {
+ EVP_MD_CTX_free(ctx);
rb_raise(ePKeyError, "signature would be too large");
+ }
sig = ossl_str_new(NULL, (long)siglen, &state);
if (state) {
EVP_MD_CTX_free(ctx);
--
2.32.0
From 8b30ce20eb9e03180c28288e29a96308e594f860 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Fri, 2 Apr 2021 23:58:48 +0900
Subject: [PATCH 2/3] pkey: prepare pkey_ctx_apply_options() for usage by other
operations
The routine to apply Hash to EVP_PKEY_CTX_ctrl_str() is currently used
by key generation, but it is useful for other operations too. Let's
change it to a slightly more generic name.
---
ext/openssl/ossl_pkey.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 7488190e0e..fed4a2b81f 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -198,7 +198,7 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
}
static VALUE
-pkey_gen_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v))
+pkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v))
{
VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1);
EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v;
@@ -214,15 +214,25 @@ pkey_gen_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v))
}
static VALUE
-pkey_gen_apply_options0(VALUE args_v)
+pkey_ctx_apply_options0(VALUE args_v)
{
VALUE *args = (VALUE *)args_v;
rb_block_call(args[1], rb_intern("each"), 0, NULL,
- pkey_gen_apply_options_i, args[0]);
+ pkey_ctx_apply_options_i, args[0]);
return Qnil;
}
+static void
+pkey_ctx_apply_options(EVP_PKEY_CTX *ctx, VALUE options, int *state)
+{
+ VALUE args[2];
+ args[0] = (VALUE)ctx;
+ args[1] = options;
+
+ rb_protect(pkey_ctx_apply_options0, (VALUE)args, state);
+}
+
struct pkey_blocking_generate_arg {
EVP_PKEY_CTX *ctx;
EVP_PKEY *pkey;
@@ -330,11 +340,7 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
}
if (!NIL_P(options)) {
- VALUE args[2];
-
- args[0] = (VALUE)ctx;
- args[1] = options;
- rb_protect(pkey_gen_apply_options0, (VALUE)args, &state);
+ pkey_ctx_apply_options(ctx, options, &state);
if (state) {
EVP_PKEY_CTX_free(ctx);
rb_jump_tag(state);
--
2.32.0
From 4c7b0f91da666961d11908b94520db4e09ce4e67 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Sat, 18 Jul 2020 20:40:39 +0900
Subject: [PATCH 3/3] pkey: allow setting algorithm-specific options in #sign
and #verify
Similarly to OpenSSL::PKey.generate_key and .generate_parameters, let
OpenSSL::PKey::PKey#sign and #verify take an optional parameter for
specifying control strings for EVP_PKEY_CTX_ctrl_str().
---
ext/openssl/ossl_pkey.c | 113 ++++++++++++++++++++++------------
test/openssl/test_pkey_rsa.rb | 34 +++++-----
2 files changed, 89 insertions(+), 58 deletions(-)
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index fed4a2b81f..22e9f19982 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -739,33 +739,51 @@ ossl_pkey_public_to_pem(VALUE self)
}
/*
- * call-seq:
- * pkey.sign(digest, data) -> String
+ * call-seq:
+ * pkey.sign(digest, data [, options]) -> string
*
- * To sign the String _data_, _digest_, an instance of OpenSSL::Digest, must
- * be provided. The return value is again a String containing the signature.
- * A PKeyError is raised should errors occur.
- * Any previous state of the Digest instance is irrelevant to the signature
- * outcome, the digest instance is reset to its initial state during the
- * operation.
+ * Hashes and signs the +data+ using a message digest algorithm +digest+ and
+ * a private key +pkey+.
*
- * == Example
- * data = 'Sign me!'
- * digest = OpenSSL::Digest.new('SHA256')
- * pkey = OpenSSL::PKey::RSA.new(2048)
- * signature = pkey.sign(digest, data)
+ * See #verify for the verification operation.
+ *
+ * See also the man page EVP_DigestSign(3).
+ *
+ * +digest+::
+ * A String that represents the message digest algorithm name, or +nil+
+ * if the PKey type requires no digest algorithm.
+ * For backwards compatibility, this can be an instance of OpenSSL::Digest.
+ * Its state will not affect the signature.
+ * +data+::
+ * A String. The data to be hashed and signed.
+ * +options+::
+ * A Hash that contains algorithm specific control operations to \OpenSSL.
+ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
+ * +options+ parameter was added in version 2.3.
+ *
+ * Example:
+ * data = "Sign me!"
+ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
+ * signopts = { rsa_padding_mode: "pss" }
+ * signature = pkey.sign("SHA256", data, signopts)
+ *
+ * # Creates a copy of the RSA key pkey, but without the private components
+ * pub_key = pkey.public_key
+ * puts pub_key.verify("SHA256", signature, data, signopts) # => true
*/
static VALUE
-ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
+ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
+ VALUE digest, data, options, sig;
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx;
+ EVP_PKEY_CTX *pctx;
size_t siglen;
int state;
- VALUE sig;
pkey = GetPrivPKeyPtr(self);
+ rb_scan_args(argc, argv, "21", &digest, &data, &options);
if (!NIL_P(digest))
md = ossl_evp_get_digestbyname(digest);
StringValue(data);
@@ -773,10 +791,17 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
ctx = EVP_MD_CTX_new();
if (!ctx)
ossl_raise(ePKeyError, "EVP_MD_CTX_new");
- if (EVP_DigestSignInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) {
+ if (EVP_DigestSignInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_DigestSignInit");
}
+ if (!NIL_P(options)) {
+ pkey_ctx_apply_options(pctx, options, &state);
+ if (state) {
+ EVP_MD_CTX_free(ctx);
+ rb_jump_tag(state);
+ }
+ }
#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data),
RSTRING_LEN(data)) < 1) {
@@ -828,35 +853,40 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
}
/*
- * call-seq:
- * pkey.verify(digest, signature, data) -> String
+ * call-seq:
+ * pkey.verify(digest, signature, data [, options]) -> true or false
*
- * To verify the String _signature_, _digest_, an instance of
- * OpenSSL::Digest, must be provided to re-compute the message digest of the
- * original _data_, also a String. The return value is +true+ if the
- * signature is valid, +false+ otherwise. A PKeyError is raised should errors
- * occur.
- * Any previous state of the Digest instance is irrelevant to the validation
- * outcome, the digest instance is reset to its initial state during the
- * operation.
+ * Verifies the +signature+ for the +data+ using a message digest algorithm
+ * +digest+ and a public key +pkey+.
*
- * == Example
- * data = 'Sign me!'
- * digest = OpenSSL::Digest.new('SHA256')
- * pkey = OpenSSL::PKey::RSA.new(2048)
- * signature = pkey.sign(digest, data)
- * pub_key = pkey.public_key
- * puts pub_key.verify(digest, signature, data) # => true
+ * Returns +true+ if the signature is successfully verified, +false+ otherwise.
+ * The caller must check the return value.
+ *
+ * See #sign for the signing operation and an example.
+ *
+ * See also the man page EVP_DigestVerify(3).
+ *
+ * +digest+::
+ * See #sign.
+ * +signature+::
+ * A String containing the signature to be verified.
+ * +data+::
+ * See #sign.
+ * +options+::
+ * See #sign. +options+ parameter was added in version 2.3.
*/
static VALUE
-ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
+ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
+ VALUE digest, sig, data, options;
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx;
- int ret;
+ EVP_PKEY_CTX *pctx;
+ int state, ret;
GetPKey(self, pkey);
+ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
ossl_pkey_check_public_key(pkey);
if (!NIL_P(digest))
md = ossl_evp_get_digestbyname(digest);
@@ -866,10 +896,17 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
ctx = EVP_MD_CTX_new();
if (!ctx)
ossl_raise(ePKeyError, "EVP_MD_CTX_new");
- if (EVP_DigestVerifyInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) {
+ if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
EVP_MD_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_DigestVerifyInit");
}
+ if (!NIL_P(options)) {
+ pkey_ctx_apply_options(pctx, options, &state);
+ if (state) {
+ EVP_MD_CTX_free(ctx);
+ rb_jump_tag(state);
+ }
+ }
#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig),
RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data),
@@ -1042,8 +1079,8 @@ Init_ossl_pkey(void)
rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0);
- rb_define_method(cPKey, "sign", ossl_pkey_sign, 2);
- rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
+ rb_define_method(cPKey, "sign", ossl_pkey_sign, -1);
+ rb_define_method(cPKey, "verify", ossl_pkey_verify, -1);
rb_define_method(cPKey, "derive", ossl_pkey_derive, -1);
id_private_q = rb_intern("private?");
diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb
index 88164c3b52..d1e68dbc9f 100644
--- a/test/openssl/test_pkey_rsa.rb
+++ b/test/openssl/test_pkey_rsa.rb
@@ -117,27 +117,21 @@ def test_sign_verify
assert_equal false, rsa1024.verify("SHA256", signature1, data)
end
- def test_digest_state_irrelevant_sign
+ def test_sign_verify_options
key = Fixtures.pkey("rsa1024")
- digest1 = OpenSSL::Digest.new('SHA1')
- digest2 = OpenSSL::Digest.new('SHA1')
- data = 'Sign me!'
- digest1 << 'Change state of digest1'
- sig1 = key.sign(digest1, data)
- sig2 = key.sign(digest2, data)
- assert_equal(sig1, sig2)
- end
-
- def test_digest_state_irrelevant_verify
- key = Fixtures.pkey("rsa1024")
- digest1 = OpenSSL::Digest.new('SHA1')
- digest2 = OpenSSL::Digest.new('SHA1')
- data = 'Sign me!'
- sig = key.sign(digest1, data)
- digest1.reset
- digest1 << 'Change state of digest1'
- assert(key.verify(digest1, sig, data))
- assert(key.verify(digest2, sig, data))
+ data = "Sign me!"
+ pssopts = {
+ "rsa_padding_mode" => "pss",
+ "rsa_pss_saltlen" => 20,
+ "rsa_mgf1_md" => "SHA1"
+ }
+ sig_pss = key.sign("SHA256", data, pssopts)
+ assert_equal 128, sig_pss.bytesize
+ assert_equal true, key.verify("SHA256", sig_pss, data, pssopts)
+ assert_equal true, key.verify_pss("SHA256", sig_pss, data,
+ salt_length: 20, mgf1_hash: "SHA1")
+ # Defaults to PKCS #1 v1.5 padding => verification failure
+ assert_equal false, key.verify("SHA256", sig_pss, data)
end
def test_verify_empty_rsa
--
2.32.0

@ -1,719 +0,0 @@
From 46ca47060ca8ef3419ec36c2326a81b442d9b43b Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Sun, 12 Dec 2021 01:25:20 +0900
Subject: [PATCH 1/5] pkey/dh: avoid using DH#set_key in DH#compute_key
DH#set_key will not work on OpenSSL 3.0 because keys are immutable.
For now, let's reimplement DH#compute_key by manually constructing a
DER-encoded SubjectPublicKeyInfo structure and feeding it to
OpenSSL::PKey.read.
Eventually, we should implement a new method around EVP_PKEY_fromdata()
and use it instead.
---
ext/openssl/lib/openssl/pkey.rb | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb
index f6bf5892..5864faa9 100644
--- a/ext/openssl/lib/openssl/pkey.rb
+++ b/ext/openssl/lib/openssl/pkey.rb
@@ -47,9 +47,19 @@ def public_key
# * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by
# DH#public_key as that contains the DH parameters only.
def compute_key(pub_bn)
- peer = dup
- peer.set_key(pub_bn, nil)
- derive(peer)
+ # FIXME: This is constructing an X.509 SubjectPublicKeyInfo and is very
+ # inefficient
+ obj = OpenSSL::ASN1.Sequence([
+ OpenSSL::ASN1.Sequence([
+ OpenSSL::ASN1.ObjectId("dhKeyAgreement"),
+ OpenSSL::ASN1.Sequence([
+ OpenSSL::ASN1.Integer(p),
+ OpenSSL::ASN1.Integer(g),
+ ]),
+ ]),
+ OpenSSL::ASN1.BitString(OpenSSL::ASN1.Integer(pub_bn).to_der),
+ ])
+ derive(OpenSSL::PKey.read(obj.to_der))
end
# :call-seq:
From fc9aabc18df3c189cc6a76a1470ca908c4f16480 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Fri, 17 Dec 2021 02:22:25 +0900
Subject: [PATCH 2/5] pkey/ec: avoid using EC#public_key= in EC#dh_compute_key
Similarly to DH#compute_key, work around it by constructing a
SubjectPublicKeyInfo. This should be considered as a temporary
implementation.
---
ext/openssl/lib/openssl/pkey.rb | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb
index 5864faa9..ba04cf4b 100644
--- a/ext/openssl/lib/openssl/pkey.rb
+++ b/ext/openssl/lib/openssl/pkey.rb
@@ -259,9 +259,14 @@ def dsa_verify_asn1(data, sig)
# This method is provided for backwards compatibility, and calls #derive
# internally.
def dh_compute_key(pubkey)
- peer = OpenSSL::PKey::EC.new(group)
- peer.public_key = pubkey
- derive(peer)
+ obj = OpenSSL::ASN1.Sequence([
+ OpenSSL::ASN1.Sequence([
+ OpenSSL::ASN1.ObjectId("id-ecPublicKey"),
+ group.to_der,
+ ]),
+ OpenSSL::ASN1.BitString(pubkey.to_octet_string(:uncompressed)),
+ ])
+ derive(OpenSSL::PKey.read(obj.to_der))
end
end
From 8ee6a582c7e4614eec4f5ca5ab59898fbcb50d2a Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Fri, 22 Oct 2021 16:24:07 +0900
Subject: [PATCH 3/5] pkey/dh: deprecate OpenSSL::PKey::DH#generate_key!
OpenSSL::PKey::DH#generate_key! will not work on OpenSSL 3.0 because
keys are made immutable. Users should use OpenSSL::PKey.generate_key
instead.
---
ext/openssl/lib/openssl/pkey.rb | 23 +++++++++++++++++++----
ext/openssl/ossl_pkey_dh.c | 9 +++++----
test/openssl/test_pkey_dh.rb | 18 ++++++++++--------
3 files changed, 34 insertions(+), 16 deletions(-)
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb
index ba04cf4b..c3e06290 100644
--- a/ext/openssl/lib/openssl/pkey.rb
+++ b/ext/openssl/lib/openssl/pkey.rb
@@ -71,14 +71,29 @@ def compute_key(pub_bn)
# called first in order to generate the per-session keys before performing
# the actual key exchange.
#
+ # <b>Deprecated in version 3.0</b>. This method is incompatible with
+ # OpenSSL 3.0.0 or later.
+ #
# See also OpenSSL::PKey.generate_key.
#
# Example:
- # dh = OpenSSL::PKey::DH.new(2048)
- # public_key = dh.public_key #contains no private/public key yet
- # public_key.generate_key!
- # puts public_key.private? # => true
+ # # DEPRECATED USAGE: This will not work on OpenSSL 3.0 or later
+ # dh0 = OpenSSL::PKey::DH.new(2048)
+ # dh = dh0.public_key # #public_key only copies the DH parameters (contrary to the name)
+ # dh.generate_key!
+ # puts dh.private? # => true
+ # puts dh0.pub_key == dh.pub_key #=> false
+ #
+ # # With OpenSSL::PKey.generate_key
+ # dh0 = OpenSSL::PKey::DH.new(2048)
+ # dh = OpenSSL::PKey.generate_key(dh0)
+ # puts dh0.pub_key == dh.pub_key #=> false
def generate_key!
+ if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000
+ raise DHError, "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \
+ "use OpenSSL::PKey.generate_key instead"
+ end
+
unless priv_key
tmp = OpenSSL::PKey.generate_key(self)
set_key(tmp.pub_key, tmp.priv_key)
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index 04c11b2157..e70d60ed19 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -58,15 +58,16 @@ VALUE eDHError;
*
* Examples:
* # Creating an instance from scratch
- * dh = DH.new
+ * # Note that this is deprecated and will not work on OpenSSL 3.0 or later.
+ * dh = OpenSSL::PKey::DH.new
* dh.set_pqg(bn_p, nil, bn_g)
*
* # Generating a parameters and a key pair
- * dh = DH.new(2048) # An alias of DH.generate(2048)
+ * dh = OpenSSL::PKey::DH.new(2048) # An alias of OpenSSL::PKey::DH.generate(2048)
*
* # Reading DH parameters
- * dh = DH.new(File.read('parameters.pem')) # -> dh, but no public/private key yet
- * dh.generate_key! # -> dh with public and private key
+ * dh_params = OpenSSL::PKey::DH.new(File.read('parameters.pem')) # loads parameters only
+ * dh = OpenSSL::PKey.generate_key(dh_params) # generates a key pair
*/
static VALUE
ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb
index 757704ca..ac11af38 100644
--- a/test/openssl/test_pkey_dh.rb
+++ b/test/openssl/test_pkey_dh.rb
@@ -26,14 +26,19 @@ def test_new_break
end
def test_derive_key
- dh1 = Fixtures.pkey("dh1024").generate_key!
- dh2 = Fixtures.pkey("dh1024").generate_key!
+ params = Fixtures.pkey("dh1024")
+ dh1 = OpenSSL::PKey.generate_key(params)
+ dh2 = OpenSSL::PKey.generate_key(params)
dh1_pub = OpenSSL::PKey.read(dh1.public_to_der)
dh2_pub = OpenSSL::PKey.read(dh2.public_to_der)
+
z = dh1.g.mod_exp(dh1.priv_key, dh1.p).mod_exp(dh2.priv_key, dh1.p).to_s(2)
assert_equal z, dh1.derive(dh2_pub)
assert_equal z, dh2.derive(dh1_pub)
+ assert_raise(OpenSSL::PKey::PKeyError) { params.derive(dh1_pub) }
+ assert_raise(OpenSSL::PKey::PKeyError) { dh1_pub.derive(params) }
+
assert_equal z, dh1.compute_key(dh2.pub_key)
assert_equal z, dh2.compute_key(dh1.pub_key)
end
@@ -74,19 +79,16 @@ def test_public_key
end
def test_generate_key
- dh = Fixtures.pkey("dh1024").public_key # creates a copy
+ # Deprecated in v3.0.0; incompatible with OpenSSL 3.0
+ dh = Fixtures.pkey("dh1024").public_key # creates a copy with params only
assert_no_key(dh)
dh.generate_key!
assert_key(dh)
- end
- def test_key_exchange
- dh = Fixtures.pkey("dh1024")
dh2 = dh.public_key
- dh.generate_key!
dh2.generate_key!
assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key))
- end
+ end if !openssl?(3, 0, 0)
def test_params_ok?
dh0 = Fixtures.pkey("dh1024")
From 5e2e66cce870ea86001dbb0eaa3092badfd37994 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Fri, 17 Dec 2021 02:21:42 +0900
Subject: [PATCH 4/5] pkey/ec: deprecate OpenSSL::PKey::EC#generate_key!
OpenSSL::PKey::EC#generate_key! will not work on OpenSSL 3.0 because
keys are made immutable. Users should use OpenSSL::PKey.generate_key
instead.
---
ext/openssl/ossl_pkey_ec.c | 4 ++++
test/openssl/test_pkey_ec.rb | 21 +++++++++++++--------
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index db80d112..398a550a 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -442,6 +442,9 @@ ossl_ec_key_to_der(VALUE self)
*/
static VALUE ossl_ec_key_generate_key(VALUE self)
{
+#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+ rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
+#else
EC_KEY *ec;
GetEC(self, ec);
@@ -449,6 +452,7 @@ static VALUE ossl_ec_key_generate_key(VALUE self)
ossl_raise(eECError, "EC_KEY_generate_key");
return self;
+#endif
}
/*
diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb
index 3f5958af..33f78a4c 100644
--- a/test/openssl/test_pkey_ec.rb
+++ b/test/openssl/test_pkey_ec.rb
@@ -13,15 +13,13 @@ def test_ec_key
# FIPS-selftest failure on some environment, so skip for now.
next if ["Oakley", "X25519"].any? { |n| curve_name.start_with?(n) }
- key = OpenSSL::PKey::EC.new(curve_name)
- key.generate_key!
-
+ key = OpenSSL::PKey::EC.generate(curve_name)
assert_predicate key, :private?
assert_predicate key, :public?
assert_nothing_raised { key.check_key }
end
- key1 = OpenSSL::PKey::EC.new("prime256v1").generate_key!
+ key1 = OpenSSL::PKey::EC.generate("prime256v1")
key2 = OpenSSL::PKey::EC.new
key2.group = key1.group
@@ -52,6 +50,13 @@ def test_generate
assert_equal(true, ec.private?)
end
+ def test_generate_key
+ ec = OpenSSL::PKey::EC.new("prime256v1")
+ assert_equal false, ec.private?
+ ec.generate_key!
+ assert_equal true, ec.private?
+ end if !openssl?(3, 0, 0)
+
def test_marshal
key = Fixtures.pkey("p256")
deserialized = Marshal.load(Marshal.dump(key))
@@ -136,7 +141,7 @@ def test_sign_verify_raw
end
def test_dsa_sign_asn1_FIPS186_3
- key = OpenSSL::PKey::EC.new("prime256v1").generate_key!
+ key = OpenSSL::PKey::EC.generate("prime256v1")
size = key.group.order.num_bits / 8 + 1
dgst = (1..size).to_a.pack('C*')
sig = key.dsa_sign_asn1(dgst)
@@ -145,8 +150,8 @@ def test_dsa_sign_asn1_FIPS186_3
end
def test_dh_compute_key
- key_a = OpenSSL::PKey::EC.new("prime256v1").generate_key!
- key_b = OpenSSL::PKey::EC.new(key_a.group).generate_key!
+ key_a = OpenSSL::PKey::EC.generate("prime256v1")
+ key_b = OpenSSL::PKey::EC.generate(key_a.group)
pub_a = key_a.public_key
pub_b = key_b.public_key
@@ -276,7 +281,7 @@ def test_ec_group
def test_ec_point
group = OpenSSL::PKey::EC::Group.new("prime256v1")
- key = OpenSSL::PKey::EC.new(group).generate_key!
+ key = OpenSSL::PKey::EC.generate(group)
point = key.public_key
point2 = OpenSSL::PKey::EC::Point.new(group, point.to_bn)
From 6848d2d969d90e6a400d89848ecec21076b87888 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Tue, 21 Sep 2021 18:29:59 +0900
Subject: [PATCH 5/5] pkey: deprecate PKey#set_* methods
OpenSSL 3.0 made EVP_PKEY immutable. This means we can only have a const
pointer of the low level struct and the following methods can no longer
be provided when linked against OpenSSL 3.0:
- OpenSSL::PKey::RSA#set_key
- OpenSSL::PKey::RSA#set_factors
- OpenSSL::PKey::RSA#set_crt_params
- OpenSSL::PKey::DSA#set_pqg
- OpenSSL::PKey::DSA#set_key
- OpenSSL::PKey::DH#set_pqg
- OpenSSL::PKey::DH#set_key
- OpenSSL::PKey::EC#group=
- OpenSSL::PKey::EC#private_key=
- OpenSSL::PKey::EC#public_key=
There is no direct replacement for this functionality at the moment.
I plan to introduce a wrapper around EVP_PKEY_fromdata(), which takes
all key components at once to construct an EVP_PKEY.
---
ext/openssl/ossl_pkey.h | 16 +++++++
ext/openssl/ossl_pkey_ec.c | 12 +++++
test/openssl/test_pkey_dh.rb | 38 +++++++++++-----
test/openssl/test_pkey_dsa.rb | 8 +++-
test/openssl/test_pkey_ec.rb | 58 ++++++++++++++----------
test/openssl/test_pkey_rsa.rb | 85 ++++++++++++++++++++++-------------
6 files changed, 149 insertions(+), 68 deletions(-)
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index 4beede22..4536e58e 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -116,6 +116,7 @@ static VALUE ossl_##_keytype##_get_##_name(VALUE self) \
OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
_type##_get0_##_group(obj, NULL, &bn))
+#if !OSSL_OPENSSL_PREREQ(3, 0, 0)
#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
/* \
* call-seq: \
@@ -173,6 +174,21 @@ static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \
} \
return self; \
}
+#else
+#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
+static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \
+{ \
+ rb_raise(ePKeyError, \
+ #_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \
+}
+
+#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
+static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \
+{ \
+ rb_raise(ePKeyError, \
+ #_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \
+}
+#endif
#define OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, _name) \
/* \
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index 398a550a..7a6ed1c9 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -251,6 +251,9 @@ ossl_ec_key_get_group(VALUE self)
static VALUE
ossl_ec_key_set_group(VALUE self, VALUE group_v)
{
+#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+ rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
+#else
EC_KEY *ec;
EC_GROUP *group;
@@ -261,6 +264,7 @@ ossl_ec_key_set_group(VALUE self, VALUE group_v)
ossl_raise(eECError, "EC_KEY_set_group");
return group_v;
+#endif
}
/*
@@ -289,6 +293,9 @@ static VALUE ossl_ec_key_get_private_key(VALUE self)
*/
static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
{
+#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+ rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
+#else
EC_KEY *ec;
BIGNUM *bn = NULL;
@@ -307,6 +314,7 @@ static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
}
return private_key;
+#endif
}
/*
@@ -335,6 +343,9 @@ static VALUE ossl_ec_key_get_public_key(VALUE self)
*/
static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
{
+#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+ rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
+#else
EC_KEY *ec;
EC_POINT *point = NULL;
@@ -353,6 +364,7 @@ static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
}
return public_key;
+#endif
}
/*
diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb
index ac11af38..161af189 100644
--- a/test/openssl/test_pkey_dh.rb
+++ b/test/openssl/test_pkey_dh.rb
@@ -107,13 +107,32 @@ def test_params_ok?
end
def test_dup
- dh = Fixtures.pkey("dh1024")
- dh2 = dh.dup
- assert_equal dh.to_der, dh2.to_der # params
- assert_equal_params dh, dh2 # keys
- dh2.set_pqg(dh2.p + 1, nil, dh2.g)
- assert_not_equal dh2.p, dh.p
- assert_equal dh2.g, dh.g
+ # Parameters only
+ dh1 = Fixtures.pkey("dh1024")
+ dh2 = dh1.dup
+ assert_equal dh1.to_der, dh2.to_der
+ assert_not_equal nil, dh1.p
+ assert_not_equal nil, dh1.g
+ assert_equal [dh1.p, dh1.g], [dh2.p, dh2.g]
+ assert_equal nil, dh1.pub_key
+ assert_equal nil, dh1.priv_key
+ assert_equal [dh1.pub_key, dh1.priv_key], [dh2.pub_key, dh2.priv_key]
+
+ # PKey is immutable in OpenSSL >= 3.0
+ if !openssl?(3, 0, 0)
+ dh2.set_pqg(dh2.p + 1, nil, dh2.g)
+ assert_not_equal dh2.p, dh1.p
+ end
+
+ # With a key pair
+ dh3 = OpenSSL::PKey.generate_key(Fixtures.pkey("dh1024"))
+ dh4 = dh3.dup
+ assert_equal dh3.to_der, dh4.to_der
+ assert_equal dh1.to_der, dh4.to_der # encodes parameters only
+ assert_equal [dh1.p, dh1.g], [dh4.p, dh4.g]
+ assert_not_equal nil, dh3.pub_key
+ assert_not_equal nil, dh3.priv_key
+ assert_equal [dh3.pub_key, dh3.priv_key], [dh4.pub_key, dh4.priv_key]
end
def test_marshal
@@ -125,11 +144,6 @@ def test_marshal
private
- def assert_equal_params(dh1, dh2)
- assert_equal(dh1.g, dh2.g)
- assert_equal(dh1.p, dh2.p)
- end
-
def assert_no_key(dh)
assert_equal(false, dh.public?)
assert_equal(false, dh.private?)
diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb
index 0994607f..726b7dbf 100644
--- a/test/openssl/test_pkey_dsa.rb
+++ b/test/openssl/test_pkey_dsa.rb
@@ -208,8 +208,12 @@ def test_dup
key = Fixtures.pkey("dsa1024")
key2 = key.dup
assert_equal key.params, key2.params
- key2.set_pqg(key2.p + 1, key2.q, key2.g)
- assert_not_equal key.params, key2.params
+
+ # PKey is immutable in OpenSSL >= 3.0
+ if !openssl?(3, 0, 0)
+ key2.set_pqg(key2.p + 1, key2.q, key2.g)
+ assert_not_equal key.params, key2.params
+ end
end
def test_marshal
diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb
index 33f78a4c..ffe5a94e 100644
--- a/test/openssl/test_pkey_ec.rb
+++ b/test/openssl/test_pkey_ec.rb
@@ -21,11 +21,15 @@ def test_ec_key
key1 = OpenSSL::PKey::EC.generate("prime256v1")
- key2 = OpenSSL::PKey::EC.new
- key2.group = key1.group
- key2.private_key = key1.private_key
- key2.public_key = key1.public_key
- assert_equal key1.to_der, key2.to_der
+ # PKey is immutable in OpenSSL >= 3.0; constructing an empty EC object is
+ # deprecated
+ if !openssl?(3, 0, 0)
+ key2 = OpenSSL::PKey::EC.new
+ key2.group = key1.group
+ key2.private_key = key1.private_key
+ key2.public_key = key1.public_key
+ assert_equal key1.to_der, key2.to_der
+ end
key3 = OpenSSL::PKey::EC.new(key1)
assert_equal key1.to_der, key3.to_der
@@ -35,10 +39,14 @@ def test_ec_key
key5 = key1.dup
assert_equal key1.to_der, key5.to_der
- key_tmp = OpenSSL::PKey::EC.new("prime256v1").generate_key!
- key5.private_key = key_tmp.private_key
- key5.public_key = key_tmp.public_key
- assert_not_equal key1.to_der, key5.to_der
+
+ # PKey is immutable in OpenSSL >= 3.0; EC object should not be modified
+ if !openssl?(3, 0, 0)
+ key_tmp = OpenSSL::PKey::EC.generate("prime256v1")
+ key5.private_key = key_tmp.private_key
+ key5.public_key = key_tmp.public_key
+ assert_not_equal key1.to_der, key5.to_der
+ end
end
def test_generate
@@ -65,22 +73,26 @@ def test_marshal
end
def test_check_key
- key = OpenSSL::PKey::EC.new("prime256v1").generate_key!
- assert_equal(true, key.check_key)
- assert_equal(true, key.private?)
- assert_equal(true, key.public?)
- key2 = OpenSSL::PKey::EC.new(key.group)
- assert_equal(false, key2.private?)
- assert_equal(false, key2.public?)
- key2.public_key = key.public_key
- assert_equal(false, key2.private?)
- assert_equal(true, key2.public?)
- key2.private_key = key.private_key
+ key0 = Fixtures.pkey("p256")
+ assert_equal(true, key0.check_key)
+ assert_equal(true, key0.private?)
+ assert_equal(true, key0.public?)
+
+ key1 = OpenSSL::PKey.read(key0.public_to_der)
+ assert_equal(true, key1.check_key)
+ assert_equal(false, key1.private?)
+ assert_equal(true, key1.public?)
+
+ key2 = OpenSSL::PKey.read(key0.private_to_der)
assert_equal(true, key2.private?)
assert_equal(true, key2.public?)
assert_equal(true, key2.check_key)
- key2.private_key += 1
- assert_raise(OpenSSL::PKey::ECError) { key2.check_key }
+
+ # EC#private_key= is deprecated in 3.0 and won't work on OpenSSL 3.0
+ if !openssl?(3, 0, 0)
+ key2.private_key += 1
+ assert_raise(OpenSSL::PKey::ECError) { key2.check_key }
+ end
end
def test_sign_verify
@@ -112,7 +124,7 @@ def test_derive_key
assert_equal [zIUT].pack("H*"), a.derive(b)
assert_equal a.derive(b), a.dh_compute_key(b.public_key)
- end
+ end if !openssl?(3, 0, 0) # TODO: Test it without using #private_key=
def test_sign_verify_raw
key = Fixtures.pkey("p256")
diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb
index dbe87ba4..1c7f9ccf 100644
--- a/test/openssl/test_pkey_rsa.rb
+++ b/test/openssl/test_pkey_rsa.rb
@@ -31,15 +31,18 @@ def test_private
assert(!key4.private?)
rsa1024 = Fixtures.pkey("rsa1024")
- # Generated by RSA#set_key
- key5 = OpenSSL::PKey::RSA.new
- key5.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
- assert(key5.private?)
-
- # Generated by RSA#set_key, without d
- key6 = OpenSSL::PKey::RSA.new
- key6.set_key(rsa1024.n, rsa1024.e, nil)
- assert(!key6.private?)
+ if !openssl?(3, 0, 0)
+ key = OpenSSL::PKey::RSA.new
+ # Generated by RSA#set_key
+ key5 = OpenSSL::PKey::RSA.new
+ key5.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
+ assert(key5.private?)
+
+ # Generated by RSA#set_key, without d
+ key6 = OpenSSL::PKey::RSA.new
+ key6.set_key(rsa1024.n, rsa1024.e, nil)
+ assert(!key6.private?)
+ end
end
def test_new
@@ -235,36 +238,52 @@ def test_encrypt_decrypt_legacy
def test_export
rsa1024 = Fixtures.pkey("rsa1024")
- key = OpenSSL::PKey::RSA.new
- # key has only n, e and d
- key.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
- assert_equal rsa1024.public_key.export, key.export
+ pub = OpenSSL::PKey.read(rsa1024.public_to_der)
+ assert_not_equal rsa1024.export, pub.export
+ assert_equal rsa1024.public_to_pem, pub.export
+
+ # PKey is immutable in OpenSSL >= 3.0
+ if !openssl?(3, 0, 0)
+ key = OpenSSL::PKey::RSA.new
- # key has only n, e, d, p and q
- key.set_factors(rsa1024.p, rsa1024.q)
- assert_equal rsa1024.public_key.export, key.export
+ # key has only n, e and d
+ key.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
+ assert_equal rsa1024.public_key.export, key.export
- # key has n, e, d, p, q, dmp1, dmq1 and iqmp
- key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp)
- assert_equal rsa1024.export, key.export
+ # key has only n, e, d, p and q
+ key.set_factors(rsa1024.p, rsa1024.q)
+ assert_equal rsa1024.public_key.export, key.export
+
+ # key has n, e, d, p, q, dmp1, dmq1 and iqmp
+ key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp)
+ assert_equal rsa1024.export, key.export
+ end
end
def test_to_der
rsa1024 = Fixtures.pkey("rsa1024")
- key = OpenSSL::PKey::RSA.new
- # key has only n, e and d
- key.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
- assert_equal rsa1024.public_key.to_der, key.to_der
+ pub = OpenSSL::PKey.read(rsa1024.public_to_der)
+ assert_not_equal rsa1024.to_der, pub.to_der
+ assert_equal rsa1024.public_to_der, pub.to_der
- # key has only n, e, d, p and q
- key.set_factors(rsa1024.p, rsa1024.q)
- assert_equal rsa1024.public_key.to_der, key.to_der
+ # PKey is immutable in OpenSSL >= 3.0
+ if !openssl?(3, 0, 0)
+ key = OpenSSL::PKey::RSA.new
- # key has n, e, d, p, q, dmp1, dmq1 and iqmp
- key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp)
- assert_equal rsa1024.to_der, key.to_der
+ # key has only n, e and d
+ key.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
+ assert_equal rsa1024.public_key.to_der, key.to_der
+
+ # key has only n, e, d, p and q
+ key.set_factors(rsa1024.p, rsa1024.q)
+ assert_equal rsa1024.public_key.to_der, key.to_der
+
+ # key has n, e, d, p, q, dmp1, dmq1 and iqmp
+ key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp)
+ assert_equal rsa1024.to_der, key.to_der
+ end
end
def test_RSAPrivateKey
@@ -501,8 +520,12 @@ def test_dup
key = Fixtures.pkey("rsa1024")
key2 = key.dup
assert_equal key.params, key2.params
- key2.set_key(key2.n, 3, key2.d)
- assert_not_equal key.params, key2.params
+
+ # PKey is immutable in OpenSSL >= 3.0
+ if !openssl?(3, 0, 0)
+ key2.set_key(key2.n, 3, key2.d)
+ assert_not_equal key.params, key2.params
+ end
end
def test_marshal

@ -1,27 +0,0 @@
From 47975ece4096cdab16b3f200f93ea2377dfb41ac Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Mon, 31 May 2021 14:17:21 +0900
Subject: [PATCH] test/openssl/test_pkey_rsa: disable test_no_private_exp on
OpenSSL 3.0
OpenSSL::PKey::RSA#set_key does not exist when built with OpenSSL 3.0,
so it is not possible to create an RSA object with incomplete state.
https://github.com/ruby/openssl/commit/ca03c9c070
---
test/openssl/test_pkey_rsa.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb
index 4548bdb2cfa6..dbe87ba4c1b0 100644
--- a/test/openssl/test_pkey_rsa.rb
+++ b/test/openssl/test_pkey_rsa.rb
@@ -11,7 +11,7 @@ def test_no_private_exp
key.set_factors(rsa.p, rsa.q)
assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt("foo") }
assert_raise(OpenSSL::PKey::RSAError){ key.private_decrypt("foo") }
- end
+ end if !openssl?(3, 0, 0) # Impossible state in OpenSSL 3.0
def test_private
# Generated by key size and public exponent

@ -1,43 +0,0 @@
From 0ade5611df9f981005eed32b369d1e699e520221 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADt=20Ondruch?= <vondruch@redhat.com>
Date: Thu, 10 Feb 2022 13:26:44 +0100
Subject: [PATCH] Don't query `RubyVM::FrozenCore` for class path.
The `RubyVM::FrozenCore` class path is corrupted during GC cycle and
returns random garbage, which might result in segfault.
But since it is easy to detect the `RubyVM::FrozenCore`, just provide
the class path explicitly as a workaround.
Other possibility would be to ignore `RubyVM::FrozenCore` simlarly as
TracePoint API does:
https://github.com/ruby/ruby/blob/46f6575157d4c2f6bbd5693896e26a65037e5552/vm_trace.c#L411
---
vm.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/vm.c b/vm.c
index 8ce8b279d4..3d189fa63a 100644
--- a/vm.c
+++ b/vm.c
@@ -446,7 +446,15 @@ rb_dtrace_setup(rb_execution_context_t *ec, VALUE klass, ID id,
}
type = BUILTIN_TYPE(klass);
if (type == T_CLASS || type == T_ICLASS || type == T_MODULE) {
- VALUE name = rb_class_path(klass);
+ VALUE name = Qnil;
+ /*
+ * Special treatment for rb_mRubyVMFrozenCore wchi is broken by GC.
+ * https://bugs.ruby-lang.org/issues/18257
+ */
+ if (klass == rb_mRubyVMFrozenCore)
+ name = rb_str_new_cstr("RubyVM::FrozenCore");
+ else
+ name = rb_class_path(klass);
const char *classname, *filename;
const char *methodname = rb_id2name(id);
if (methodname && (filename = rb_source_location_cstr(&args->line_no)) != 0) {
--
2.34.1

@ -1,186 +0,0 @@
From 104b009e26c050584e4d186c8cc4e1496a14061b Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@ruby-lang.org>
Date: Thu, 5 Aug 2021 20:09:25 +0900
Subject: [PATCH] Get rid of type-punning pointer casts [Bug #18062]
---
vm_eval.c | 4 +++-
vm_insnhelper.c | 7 +++++--
vm_method.c | 41 ++++++++++++++++++++++++++---------------
3 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/vm_eval.c b/vm_eval.c
index 6d4b5c3c0b28..7ce9f157e671 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -350,9 +350,11 @@ cc_new(VALUE klass, ID mid, int argc, const rb_callable_method_entry_t *cme)
{
struct rb_class_cc_entries *ccs;
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
+ VALUE ccs_data;
- if (rb_id_table_lookup(cc_tbl, mid, (VALUE*)&ccs)) {
+ if (rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
// ok
+ ccs = (struct rb_class_cc_entries *)ccs_data;
}
else {
ccs = vm_ccs_create(klass, cme);
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 14928b2afe8e..e186376b24d7 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1637,9 +1637,11 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci)
const ID mid = vm_ci_mid(ci);
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
struct rb_class_cc_entries *ccs = NULL;
+ VALUE ccs_data;
if (cc_tbl) {
- if (rb_id_table_lookup(cc_tbl, mid, (VALUE *)&ccs)) {
+ if (rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
+ ccs = (struct rb_class_cc_entries *)ccs_data;
const int ccs_len = ccs->len;
VM_ASSERT(vm_ccs_verify(ccs, mid, klass));
@@ -1706,8 +1708,9 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci)
if (ccs == NULL) {
VM_ASSERT(cc_tbl != NULL);
- if (LIKELY(rb_id_table_lookup(cc_tbl, mid, (VALUE*)&ccs))) {
+ if (LIKELY(rb_id_table_lookup(cc_tbl, mid, &ccs_data))) {
// rb_callable_method_entry() prepares ccs.
+ ccs = (struct rb_class_cc_entries *)ccs_data;
}
else {
// TODO: required?
diff --git a/vm_method.c b/vm_method.c
index 016dba1dbb18..1fd0bd57f7ca 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -42,11 +42,11 @@ vm_ccs_dump(VALUE klass, ID target_mid)
{
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
if (cc_tbl) {
- const struct rb_class_cc_entries *ccs;
+ VALUE ccs;
if (target_mid) {
- if (rb_id_table_lookup(cc_tbl, target_mid, (VALUE *)&ccs)) {
+ if (rb_id_table_lookup(cc_tbl, target_mid, &ccs)) {
fprintf(stderr, " [CCTB] %p\n", (void *)cc_tbl);
- vm_ccs_dump_i(target_mid, (VALUE)ccs, NULL);
+ vm_ccs_dump_i(target_mid, ccs, NULL);
}
}
else {
@@ -72,11 +72,11 @@ vm_mtbl_dump(VALUE klass, ID target_mid)
fprintf(stderr, "# vm_mtbl\n");
while (klass) {
rp_m(" -> ", klass);
- rb_method_entry_t *me;
+ VALUE me;
if (RCLASS_M_TBL(klass)) {
if (target_mid != 0) {
- if (rb_id_table_lookup(RCLASS_M_TBL(klass), target_mid, (VALUE *)&me)) {
+ if (rb_id_table_lookup(RCLASS_M_TBL(klass), target_mid, &me)) {
rp_m(" [MTBL] ", me);
}
}
@@ -90,7 +90,7 @@ vm_mtbl_dump(VALUE klass, ID target_mid)
}
if (RCLASS_CALLABLE_M_TBL(klass)) {
if (target_mid != 0) {
- if (rb_id_table_lookup(RCLASS_CALLABLE_M_TBL(klass), target_mid, (VALUE *)&me)) {
+ if (rb_id_table_lookup(RCLASS_CALLABLE_M_TBL(klass), target_mid, &me)) {
rp_m(" [CM**] ", me);
}
}
@@ -144,10 +144,11 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid)
// check only current class
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
- struct rb_class_cc_entries *ccs;
+ VALUE ccs_data;
// invalidate CCs
- if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, (VALUE *)&ccs)) {
+ if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
rb_vm_ccs_free(ccs);
rb_id_table_delete(cc_tbl, mid);
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_ccs);
@@ -205,9 +206,10 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid)
}
else {
rb_vm_t *vm = GET_VM();
- if (rb_id_table_lookup(vm->negative_cme_table, mid, (VALUE *)&cme)) {
+ VALUE cme_data = (VALUE) cme;
+ if (rb_id_table_lookup(vm->negative_cme_table, mid, &cme_data)) {
rb_id_table_delete(vm->negative_cme_table, mid);
- vm_me_invalidate_cache((rb_callable_method_entry_t *)cme);
+ vm_me_invalidate_cache((rb_callable_method_entry_t *)cme_data);
RB_DEBUG_COUNTER_INC(cc_invalidate_negative);
}
@@ -1030,6 +1032,7 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_
{
struct rb_id_table *mtbl;
const rb_callable_method_entry_t *cme;
+ VALUE cme_data;
if (me) {
if (me->defined_class == 0) {
@@ -1039,7 +1042,8 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_
mtbl = RCLASS_CALLABLE_M_TBL(defined_class);
- if (mtbl && rb_id_table_lookup(mtbl, id, (VALUE *)&cme)) {
+ if (mtbl && rb_id_table_lookup(mtbl, id, &cme_data)) {
+ cme = (rb_callable_method_entry_t *)cme_data;
RB_DEBUG_COUNTER_INC(mc_cme_complement_hit);
VM_ASSERT(callable_method_entry_p(cme));
VM_ASSERT(!METHOD_ENTRY_INVALIDATED(cme));
@@ -1083,9 +1087,10 @@ cached_callable_method_entry(VALUE klass, ID mid)
ASSERT_vm_locking();
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
- struct rb_class_cc_entries *ccs;
+ VALUE ccs_data;
- if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, (VALUE *)&ccs)) {
+ if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
VM_ASSERT(vm_ccs_p(ccs));
if (LIKELY(!METHOD_ENTRY_INVALIDATED(ccs->cme))) {
@@ -1111,12 +1116,14 @@ cache_callable_method_entry(VALUE klass, ID mid, const rb_callable_method_entry_
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
struct rb_class_cc_entries *ccs;
+ VALUE ccs_data;
if (!cc_tbl) {
cc_tbl = RCLASS_CC_TBL(klass) = rb_id_table_create(2);
}
- if (rb_id_table_lookup(cc_tbl, mid, (VALUE *)&ccs)) {
+ if (rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
+ ccs = (struct rb_class_cc_entries *)ccs_data;
VM_ASSERT(ccs->cme == cme);
}
else {
@@ -1130,8 +1137,12 @@ negative_cme(ID mid)
{
rb_vm_t *vm = GET_VM();
const rb_callable_method_entry_t *cme;
+ VALUE cme_data;
- if (!rb_id_table_lookup(vm->negative_cme_table, mid, (VALUE *)&cme)) {
+ if (rb_id_table_lookup(vm->negative_cme_table, mid, &cme_data)) {
+ cme = (rb_callable_method_entry_t *)cme_data;
+ }
+ else {
cme = (rb_callable_method_entry_t *)rb_method_entry_alloc(mid, Qnil, Qnil, NULL);
rb_id_table_insert(vm->negative_cme_table, mid, (VALUE)cme);
}

@ -1,58 +0,0 @@
From 72317b333b85eed483ad00bcd4f40944019a7c13 Mon Sep 17 00:00:00 2001
From: "xtkoba+ruby@gmail.com" <xtkoba+ruby@gmail.com>
Date: Fri, 13 Aug 2021 13:45:53 +0000
Subject: [PATCH] Ignore `DW_FORM_ref_addr` [Bug #17052]
Ignore `DW_FORM_ref_addr` form and other forms that are not supposed
to be used currently.
---
addr2line.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/addr2line.c b/addr2line.c
index fed1a8da84e5..92c6da5e3bea 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -1593,14 +1593,31 @@ di_read_cu(DebugInfoReader *reader)
}
static void
-read_abstract_origin(DebugInfoReader *reader, uint64_t abstract_origin, line_info_t *line)
+read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_origin, line_info_t *line)
{
char *p = reader->p;
char *q = reader->q;
int level = reader->level;
DIE die;
- reader->p = reader->current_cu + abstract_origin;
+ switch (form) {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ reader->p = reader->current_cu + abstract_origin;
+ break;
+ case DW_FORM_ref_addr:
+ goto finish; /* not supported yet */
+ case DW_FORM_ref_sig8:
+ goto finish; /* not supported yet */
+ case DW_FORM_ref_sup4:
+ case DW_FORM_ref_sup8:
+ goto finish; /* not supported yet */
+ default:
+ goto finish;
+ }
if (!di_read_die(reader, &die)) goto finish;
/* enumerate abbrev */
@@ -1665,7 +1682,7 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
/* 1 or 3 */
break; /* goto skip_die; */
case DW_AT_abstract_origin:
- read_abstract_origin(reader, v.as.uint64, &line);
+ read_abstract_origin(reader, v.form, v.as.uint64, &line);
break; /* goto skip_die; */
}
}

@ -1,523 +0,0 @@
From 8253d7c9cea16c2aa009b59db4f5d93afb74c6eb Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Tue, 30 Jun 2020 14:27:13 +0900
Subject: [PATCH 1/2] hmac: add a test case for OpenSSL::HMAC singleton methods
---
test/openssl/test_hmac.rb | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/test/openssl/test_hmac.rb b/test/openssl/test_hmac.rb
index 9cb3c5a86..7202a5902 100644
--- a/test/openssl/test_hmac.rb
+++ b/test/openssl/test_hmac.rb
@@ -49,6 +49,15 @@ def test_eq
refute_equal h1, h2.digest
refute_equal h1, h3
end
+
+ def test_singleton_methods
+ # RFC 2202 2. Test Cases for HMAC-MD5
+ key = ["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*")
+ digest = OpenSSL::HMAC.digest("MD5", key, "Hi There")
+ assert_equal ["9294727a3638bb1c13f48ef8158bfc9d"].pack("H*"), digest
+ hexdigest = OpenSSL::HMAC.hexdigest("MD5", key, "Hi There")
+ assert_equal "9294727a3638bb1c13f48ef8158bfc9d", hexdigest
+ end
end
end
From 0317e2fc028be40a7d64d0e4337d3e21539613ce Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Mon, 18 May 2020 16:15:07 +0900
Subject: [PATCH 2/2] hmac: migrate from the low-level HMAC API to the EVP API
Use the EVP API instead of the low-level HMAC API. Use of the HMAC API
has been discouraged and is being marked as deprecated starting from
OpenSSL 3.0.0.
The two singleton methods OpenSSL::HMAC, HMAC.digest and HMAC.hexdigest
are now in lib/openssl/hmac.rb.
---
ext/openssl/extconf.rb | 3 +-
ext/openssl/lib/openssl/hmac.rb | 40 +++++++
ext/openssl/openssl_missing.c | 26 -----
ext/openssl/openssl_missing.h | 10 +-
ext/openssl/ossl.h | 1 -
ext/openssl/ossl_hmac.c | 179 ++++++++------------------------
6 files changed, 89 insertions(+), 170 deletions(-)
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 693e55cd9..063498a76 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -148,8 +148,7 @@ def find_openssl_library
have_func("BN_GENCB_get_arg")
have_func("EVP_MD_CTX_new")
have_func("EVP_MD_CTX_free")
-have_func("HMAC_CTX_new")
-have_func("HMAC_CTX_free")
+have_func("EVP_MD_CTX_pkey_ctx")
have_func("X509_STORE_get_ex_data")
have_func("X509_STORE_set_ex_data")
have_func("X509_STORE_get_ex_new_index")
diff --git a/ext/openssl/lib/openssl/hmac.rb b/ext/openssl/lib/openssl/hmac.rb
index 3d4427611d..9bc8bc8df3 100644
--- a/ext/openssl/lib/openssl/hmac.rb
+++ b/ext/openssl/lib/openssl/hmac.rb
@@ -9,5 +9,45 @@ def ==(other)
OpenSSL.fixed_length_secure_compare(self.digest, other.digest)
end
+
+ class << self
+ # :call-seq:
+ # HMAC.digest(digest, key, data) -> aString
+ #
+ # Returns the authentication code as a binary string. The _digest_ parameter
+ # specifies the digest algorithm to use. This may be a String representing
+ # the algorithm name or an instance of OpenSSL::Digest.
+ #
+ # === Example
+ # key = 'key'
+ # data = 'The quick brown fox jumps over the lazy dog'
+ #
+ # hmac = OpenSSL::HMAC.digest('SHA1', key, data)
+ # #=> "\xDE|\x9B\x85\xB8\xB7\x8A\xA6\xBC\x8Az6\xF7\n\x90p\x1C\x9D\xB4\xD9"
+ def digest(digest, key, data)
+ hmac = new(key, digest)
+ hmac << data
+ hmac.digest
+ end
+
+ # :call-seq:
+ # HMAC.hexdigest(digest, key, data) -> aString
+ #
+ # Returns the authentication code as a hex-encoded string. The _digest_
+ # parameter specifies the digest algorithm to use. This may be a String
+ # representing the algorithm name or an instance of OpenSSL::Digest.
+ #
+ # === Example
+ # key = 'key'
+ # data = 'The quick brown fox jumps over the lazy dog'
+ #
+ # hmac = OpenSSL::HMAC.hexdigest('SHA1', key, data)
+ # #=> "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
+ def hexdigest(digest, key, data)
+ hmac = new(key, digest)
+ hmac << data
+ hmac.hexdigest
+ end
+ end
end
end
diff --git a/ext/openssl/openssl_missing.c b/ext/openssl/openssl_missing.c
index b36ef0288..010c158dc 100644
--- a/ext/openssl/openssl_missing.c
+++ b/ext/openssl/openssl_missing.c
@@ -13,9 +13,6 @@
#if !defined(OPENSSL_NO_ENGINE)
# include <openssl/engine.h>
#endif
-#if !defined(OPENSSL_NO_HMAC)
-# include <openssl/hmac.h>
-#endif
#include <openssl/x509_vfy.h>
#include "openssl_missing.h"
@@ -58,29 +55,6 @@ ossl_EC_curve_nist2nid(const char *name)
#endif
/*** added in 1.1.0 ***/
-#if !defined(HAVE_HMAC_CTX_NEW)
-HMAC_CTX *
-ossl_HMAC_CTX_new(void)
-{
- HMAC_CTX *ctx = OPENSSL_malloc(sizeof(HMAC_CTX));
- if (!ctx)
- return NULL;
- HMAC_CTX_init(ctx);
- return ctx;
-}
-#endif
-
-#if !defined(HAVE_HMAC_CTX_FREE)
-void
-ossl_HMAC_CTX_free(HMAC_CTX *ctx)
-{
- if (ctx) {
- HMAC_CTX_cleanup(ctx);
- OPENSSL_free(ctx);
- }
-}
-#endif
-
#if !defined(HAVE_X509_CRL_GET0_SIGNATURE)
void
ossl_X509_CRL_get0_signature(const X509_CRL *crl, const ASN1_BIT_STRING **psig,
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index 7d218f86f..06d2a9082 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -54,14 +54,8 @@ int ossl_EC_curve_nist2nid(const char *);
# define EVP_MD_CTX_free EVP_MD_CTX_destroy
#endif
-#if !defined(HAVE_HMAC_CTX_NEW)
-HMAC_CTX *ossl_HMAC_CTX_new(void);
-# define HMAC_CTX_new ossl_HMAC_CTX_new
-#endif
-
-#if !defined(HAVE_HMAC_CTX_FREE)
-void ossl_HMAC_CTX_free(HMAC_CTX *);
-# define HMAC_CTX_free ossl_HMAC_CTX_free
+#if !defined(HAVE_EVP_MD_CTX_PKEY_CTX)
+# define EVP_MD_CTX_pkey_ctx(x) (x)->pctx
#endif
#if !defined(HAVE_X509_STORE_GET_EX_DATA)
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index c20f506bd..577eb6d6b 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -24,7 +24,6 @@
#include <openssl/ssl.h>
#include <openssl/pkcs12.h>
#include <openssl/pkcs7.h>
-#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <openssl/conf.h>
#ifndef OPENSSL_NO_TS
diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c
index 70e9fb819..a21db6c48 100644
--- a/ext/openssl/ossl_hmac.c
+++ b/ext/openssl/ossl_hmac.c
@@ -7,14 +7,12 @@
* This program is licensed under the same licence as Ruby.
* (See the file 'LICENCE'.)
*/
-#if !defined(OPENSSL_NO_HMAC)
-
#include "ossl.h"
#define NewHMAC(klass) \
TypedData_Wrap_Struct((klass), &ossl_hmac_type, 0)
#define GetHMAC(obj, ctx) do { \
- TypedData_Get_Struct((obj), HMAC_CTX, &ossl_hmac_type, (ctx)); \
+ TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_hmac_type, (ctx)); \
if (!(ctx)) { \
ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
} \
@@ -36,7 +34,7 @@ VALUE eHMACError;
static void
ossl_hmac_free(void *ctx)
{
- HMAC_CTX_free(ctx);
+ EVP_MD_CTX_free(ctx);
}
static const rb_data_type_t ossl_hmac_type = {
@@ -51,12 +49,12 @@ static VALUE
ossl_hmac_alloc(VALUE klass)
{
VALUE obj;
- HMAC_CTX *ctx;
+ EVP_MD_CTX *ctx;
obj = NewHMAC(klass);
- ctx = HMAC_CTX_new();
+ ctx = EVP_MD_CTX_new();
if (!ctx)
- ossl_raise(eHMACError, NULL);
+ ossl_raise(eHMACError, "EVP_MD_CTX");
RTYPEDDATA_DATA(obj) = ctx;
return obj;
@@ -76,8 +74,7 @@ ossl_hmac_alloc(VALUE klass)
* === Example
*
* key = 'key'
- * digest = OpenSSL::Digest.new('sha1')
- * instance = OpenSSL::HMAC.new(key, digest)
+ * instance = OpenSSL::HMAC.new(key, 'SHA1')
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
* instance.class
* #=> OpenSSL::HMAC
@@ -86,7 +83,7 @@ ossl_hmac_alloc(VALUE klass)
*
* Two instances can be securely compared with #== in constant time:
*
- * other_instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1'))
+ * other_instance = OpenSSL::HMAC.new('key', 'SHA1')
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
* instance == other_instance
* #=> true
@@ -95,12 +92,23 @@ ossl_hmac_alloc(VALUE klass)
static VALUE
ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
{
- HMAC_CTX *ctx;
+ EVP_MD_CTX *ctx;
+ EVP_PKEY *pkey;
- StringValue(key);
GetHMAC(self, ctx);
- HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LENINT(key),
- ossl_evp_get_digestbyname(digest), NULL);
+ StringValue(key);
+ pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL,
+ (unsigned char *)RSTRING_PTR(key),
+ RSTRING_LENINT(key));
+ if (!pkey)
+ ossl_raise(eHMACError, "EVP_PKEY_new_mac_key");
+ if (EVP_DigestSignInit(ctx, NULL, ossl_evp_get_digestbyname(digest),
+ NULL, pkey) != 1) {
+ EVP_PKEY_free(pkey);
+ ossl_raise(eHMACError, "EVP_DigestSignInit");
+ }
+ /* Decrement reference counter; EVP_MD_CTX still keeps it */
+ EVP_PKEY_free(pkey);
return self;
}
@@ -108,16 +116,15 @@ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
static VALUE
ossl_hmac_copy(VALUE self, VALUE other)
{
- HMAC_CTX *ctx1, *ctx2;
+ EVP_MD_CTX *ctx1, *ctx2;
rb_check_frozen(self);
if (self == other) return self;
GetHMAC(self, ctx1);
GetHMAC(other, ctx2);
-
- if (!HMAC_CTX_copy(ctx1, ctx2))
- ossl_raise(eHMACError, "HMAC_CTX_copy");
+ if (EVP_MD_CTX_copy(ctx1, ctx2) != 1)
+ ossl_raise(eHMACError, "EVP_MD_CTX_copy");
return self;
}
@@ -142,33 +149,16 @@ ossl_hmac_copy(VALUE self, VALUE other)
static VALUE
ossl_hmac_update(VALUE self, VALUE data)
{
- HMAC_CTX *ctx;
+ EVP_MD_CTX *ctx;
StringValue(data);
GetHMAC(self, ctx);
- HMAC_Update(ctx, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data));
+ if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
+ ossl_raise(eHMACError, "EVP_DigestSignUpdate");
return self;
}
-static void
-hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len)
-{
- HMAC_CTX *final;
-
- final = HMAC_CTX_new();
- if (!final)
- ossl_raise(eHMACError, "HMAC_CTX_new");
-
- if (!HMAC_CTX_copy(final, ctx)) {
- HMAC_CTX_free(final);
- ossl_raise(eHMACError, "HMAC_CTX_copy");
- }
-
- HMAC_Final(final, buf, buf_len);
- HMAC_CTX_free(final);
-}
-
/*
* call-seq:
* hmac.digest -> string
@@ -176,7 +166,7 @@ hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len)
* Returns the authentication code an instance represents as a binary string.
*
* === Example
- * instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1'))
+ * instance = OpenSSL::HMAC.new('key', 'SHA1')
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
* instance.digest
* #=> "\xF4+\xB0\xEE\xB0\x18\xEB\xBDE\x97\xAEr\x13q\x1E\xC6\a`\x84?"
@@ -184,15 +174,16 @@ hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len)
static VALUE
ossl_hmac_digest(VALUE self)
{
- HMAC_CTX *ctx;
- unsigned int buf_len;
+ EVP_MD_CTX *ctx;
+ size_t buf_len;
VALUE ret;
GetHMAC(self, ctx);
ret = rb_str_new(NULL, EVP_MAX_MD_SIZE);
- hmac_final(ctx, (unsigned char *)RSTRING_PTR(ret), &buf_len);
- assert(buf_len <= EVP_MAX_MD_SIZE);
- rb_str_set_len(ret, buf_len);
+ if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(ret),
+ &buf_len) != 1)
+ ossl_raise(eHMACError, "EVP_DigestSignFinal");
+ rb_str_set_len(ret, (long)buf_len);
return ret;
}
@@ -207,13 +198,14 @@ ossl_hmac_digest(VALUE self)
static VALUE
ossl_hmac_hexdigest(VALUE self)
{
- HMAC_CTX *ctx;
+ EVP_MD_CTX *ctx;
unsigned char buf[EVP_MAX_MD_SIZE];
- unsigned int buf_len;
+ size_t buf_len;
VALUE ret;
GetHMAC(self, ctx);
- hmac_final(ctx, buf, &buf_len);
+ if (EVP_DigestSignFinal(ctx, buf, &buf_len) != 1)
+ ossl_raise(eHMACError, "EVP_DigestSignFinal");
ret = rb_str_new(NULL, buf_len * 2);
ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len);
@@ -230,7 +222,7 @@ ossl_hmac_hexdigest(VALUE self)
* === Example
*
* data = "The quick brown fox jumps over the lazy dog"
- * instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1'))
+ * instance = OpenSSL::HMAC.new('key', 'SHA1')
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
*
* instance.update(data)
@@ -242,84 +234,17 @@ ossl_hmac_hexdigest(VALUE self)
static VALUE
ossl_hmac_reset(VALUE self)
{
- HMAC_CTX *ctx;
+ EVP_MD_CTX *ctx;
+ EVP_PKEY *pkey;
GetHMAC(self, ctx);
- HMAC_Init_ex(ctx, NULL, 0, NULL, NULL);
+ pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_pkey_ctx(ctx));
+ if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_md(ctx), NULL, pkey) != 1)
+ ossl_raise(eHMACError, "EVP_DigestSignInit");
return self;
}
-/*
- * call-seq:
- * HMAC.digest(digest, key, data) -> aString
- *
- * Returns the authentication code as a binary string. The _digest_ parameter
- * specifies the digest algorithm to use. This may be a String representing
- * the algorithm name or an instance of OpenSSL::Digest.
- *
- * === Example
- *
- * key = 'key'
- * data = 'The quick brown fox jumps over the lazy dog'
- *
- * hmac = OpenSSL::HMAC.digest('sha1', key, data)
- * #=> "\xDE|\x9B\x85\xB8\xB7\x8A\xA6\xBC\x8Az6\xF7\n\x90p\x1C\x9D\xB4\xD9"
- *
- */
-static VALUE
-ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data)
-{
- unsigned char *buf;
- unsigned int buf_len;
-
- StringValue(key);
- StringValue(data);
- buf = HMAC(ossl_evp_get_digestbyname(digest), RSTRING_PTR(key),
- RSTRING_LENINT(key), (unsigned char *)RSTRING_PTR(data),
- RSTRING_LEN(data), NULL, &buf_len);
-
- return rb_str_new((const char *)buf, buf_len);
-}
-
-/*
- * call-seq:
- * HMAC.hexdigest(digest, key, data) -> aString
- *
- * Returns the authentication code as a hex-encoded string. The _digest_
- * parameter specifies the digest algorithm to use. This may be a String
- * representing the algorithm name or an instance of OpenSSL::Digest.
- *
- * === Example
- *
- * key = 'key'
- * data = 'The quick brown fox jumps over the lazy dog'
- *
- * hmac = OpenSSL::HMAC.hexdigest('sha1', key, data)
- * #=> "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
- *
- */
-static VALUE
-ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data)
-{
- unsigned char buf[EVP_MAX_MD_SIZE];
- unsigned int buf_len;
- VALUE ret;
-
- StringValue(key);
- StringValue(data);
-
- if (!HMAC(ossl_evp_get_digestbyname(digest), RSTRING_PTR(key),
- RSTRING_LENINT(key), (unsigned char *)RSTRING_PTR(data),
- RSTRING_LEN(data), buf, &buf_len))
- ossl_raise(eHMACError, "HMAC");
-
- ret = rb_str_new(NULL, buf_len * 2);
- ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len);
-
- return ret;
-}
-
/*
* INIT
*/
@@ -353,8 +278,7 @@ Init_ossl_hmac(void)
* data1 = File.read("file1")
* data2 = File.read("file2")
* key = "key"
- * digest = OpenSSL::Digest.new('SHA256')
- * hmac = OpenSSL::HMAC.new(key, digest)
+ * hmac = OpenSSL::HMAC.new(key, 'SHA256')
* hmac << data1
* hmac << data2
* mac = hmac.digest
@@ -364,8 +288,6 @@ Init_ossl_hmac(void)
cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject);
rb_define_alloc_func(cHMAC, ossl_hmac_alloc);
- rb_define_singleton_method(cHMAC, "digest", ossl_hmac_s_digest, 3);
- rb_define_singleton_method(cHMAC, "hexdigest", ossl_hmac_s_hexdigest, 3);
rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2);
rb_define_method(cHMAC, "initialize_copy", ossl_hmac_copy, 1);
@@ -378,12 +300,3 @@ Init_ossl_hmac(void)
rb_define_alias(cHMAC, "inspect", "hexdigest");
rb_define_alias(cHMAC, "to_s", "hexdigest");
}
-
-#else /* NO_HMAC */
-# warning >>> OpenSSL is compiled without HMAC support <<<
-void
-Init_ossl_hmac(void)
-{
- rb_warning("HMAC is not available: OpenSSL is compiled without HMAC.");
-}
-#endif /* NO_HMAC */
--
2.34.1

@ -1,458 +0,0 @@
From 91d04f991f8b9910efea7bbe5aecb0fea2bbd5fa Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Sun, 24 Oct 2021 17:50:18 +0900
Subject: [PATCH 1/8] cipher: update test_ciphers
Do not attempt to actually use all algorithms. Not all algorithms listed
in OpenSSL::Cipher.ciphers are always available.
---
test/openssl/test_cipher.rb | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb
index 6d18c0c8..b5fdf0b3 100644
--- a/test/openssl/test_cipher.rb
+++ b/test/openssl/test_cipher.rb
@@ -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
From 6a60c7b2e7b6afe8b8c98d864ef2740094d86e1d Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Sat, 11 Dec 2021 16:27:42 +0900
Subject: [PATCH 2/8] hmac: fix wrong usage of EVP_DigestSignFinal()
According to the manpage, the "siglen" parameter must be initialized
beforehand.
---
ext/openssl/ossl_hmac.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c
index f89ff2f9..bfe3a74b 100644
--- a/ext/openssl/ossl_hmac.c
+++ b/ext/openssl/ossl_hmac.c
@@ -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);
@@ -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);
From 46995816392a79d037df5550b2fb226652c06f42 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Sat, 11 Dec 2021 16:30:30 +0900
Subject: [PATCH 3/8] hmac: skip test_dup on OpenSSL 3.0 for now
EVP_MD_CTX_copy() doesn't seem to work as intended on HMAC EVP_MD_CTX
on OpenSSL 3.0.0 and causes a double free. I haven't found the root
problem yet, but let's skip the test case for now.
---
test/openssl/test_hmac.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/openssl/test_hmac.rb b/test/openssl/test_hmac.rb
index 2f53a813..47cb3718 100644
--- a/test/openssl/test_hmac.rb
+++ b/test/openssl/test_hmac.rb
@@ -19,6 +19,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
From 69a27d8de4bd291cb4eb21a4d715b197e7da5a06 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Thu, 15 Apr 2021 00:51:58 +0900
Subject: [PATCH 4/8] engine: disable OpenSSL::Engine on OpenSSL 3.0
The entire ENGINE API is deprecated in OpenSSL 3.0 in favor of the new
"Provider" concept.
OpenSSL::Engine will not be defined when compiled with OpenSSL 3.0.
We would need a way to interact with providers from Ruby programs, but
since the concept is completely different from the ENGINE API, it will
not be through the current OpenSSL::Engine interface.
---
ext/openssl/openssl_missing.c | 3 ---
ext/openssl/ossl.h | 8 +++++---
ext/openssl/ossl_engine.c | 3 ++-
ext/openssl/ossl_pkey.c | 4 ++++
4 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/ext/openssl/openssl_missing.c b/ext/openssl/openssl_missing.c
index 8b93cba6..4415703d 100644
--- a/ext/openssl/openssl_missing.c
+++ b/ext/openssl/openssl_missing.c
@@ -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"
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index 3a0ab1e5..4b512689 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -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>
@@ -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
@@ -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
*/
diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c
index 661a1368..1abde7f7 100644
--- a/ext/openssl/ossl_engine.c
+++ b/ext/openssl/ossl_engine.c
@@ -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)
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 7030be3c..94760d32 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -9,6 +9,10 @@
*/
#include "ossl.h"
+#ifdef OSSL_USE_ENGINE
+# include <openssl/engine.h>
+#endif
+
/*
* Classes
*/
From b1ee2f23b28c2d0b14fd9b4b9fef13e870370746 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Wed, 17 Nov 2021 11:39:06 +0900
Subject: [PATCH 5/8] ssl: add constants for new SSL_OP_* flags
Add all SSL_OP_* constants defined in OpenSSL 3.0.0 which are not
specific to DTLS.
---
ext/openssl/ossl_ssl.c | 35 +++++++++++++++++++++++++++++------
1 file changed, 29 insertions(+), 6 deletions(-)
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 3b425ca7..9a0682a7 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -2941,13 +2941,28 @@ 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
#ifdef SSL_OP_TLSEXT_PADDING /* OpenSSL 1.0.1h and OpenSSL 1.0.2 */
rb_define_const(mSSL, "OP_TLSEXT_PADDING", ULONG2NUM(SSL_OP_TLSEXT_PADDING));
#endif
#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG /* OpenSSL 1.0.1f and OpenSSL 1.0.2 */
rb_define_const(mSSL, "OP_SAFARI_ECDHE_ECDSA_BUG", ULONG2NUM(SSL_OP_SAFARI_ECDHE_ECDSA_BUG));
#endif
+#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
@@ -2959,13 +2974,15 @@ 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));
@@ -2973,6 +2990,12 @@ Init_ossl_ssl(void)
#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
From e168df0f3570709bfb38e9a39838bd0a7e78164c Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Sun, 12 Dec 2021 00:47:35 +0900
Subject: [PATCH 6/8] ssl: update test_options_disable_versions
Use the combination of TLS 1.2 and TLS 1.3 instead of TLS 1.1 and TLS
1.2 so that will the test case will be run on latest platforms.
---
test/openssl/test_ssl.rb | 75 +++++++++++++++++++++-------------------
1 file changed, 40 insertions(+), 35 deletions(-)
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index 22691292..2abade06 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -1180,46 +1180,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
From ccdb6f7bfa5f988a07beecedbf2b6205b6ab8492 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Sat, 20 Mar 2021 23:16:41 +0900
Subject: [PATCH 7/8] pkey: assume a pkey always has public key components on
OpenSSL 3.0
OpenSSL 3.0's EVP_PKEY_get0() returns NULL for provider-backed pkeys.
This causes segfault because it was supposed to never return NULL
before.
We can't check the existence of public key components in this way on
OpenSSL 3.0. Let's just skip it for now.
---
ext/openssl/ossl_pkey.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 94760d32..09d45d85 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -428,9 +428,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;
@@ -466,6 +476,7 @@ ossl_pkey_check_public_key(const EVP_PKEY *pkey)
return;
}
ossl_raise(ePKeyError, "public key missing");
+#endif
}
EVP_PKEY *
From d6535d13d174cd87ae99f3e60e97f7a00e1474e5 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Mon, 12 Apr 2021 10:43:46 +0900
Subject: [PATCH 8/8] pkey: use EVP_PKEY_CTX_new_from_name() on OpenSSL 3.0
Replace EVP_PKEY_CTX_new_id() with the new EVP_PKEY_CTX_new_from_name()
which takes the algorithm name in a string instead of in an NID.
---
ext/openssl/ossl_pkey.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 09d45d85..2a4835a2 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -315,6 +315,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;
@@ -333,6 +338,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) {

@ -1,304 +0,0 @@
From 8f948ed68a4ed6c05ff66d822711e3b70ae4bb3f Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Mon, 27 Sep 2021 13:32:03 +0900
Subject: [PATCH 1/5] ext/openssl/ossl.h: add helper macros for
OpenSSL/LibreSSL versions
Add following convenient macros:
- OSSL_IS_LIBRESSL
- OSSL_OPENSSL_PREREQ(maj, min, pat)
- OSSL_LIBRESSL_PREREQ(maj, min, pat)
---
ext/openssl/ossl.h | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index c20f506bda..a0cef29d74 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -42,6 +42,18 @@
#include <openssl/evp.h>
#include <openssl/dh.h>
+#ifndef LIBRESSL_VERSION_NUMBER
+# define OSSL_IS_LIBRESSL 0
+# define OSSL_OPENSSL_PREREQ(maj, min, pat) \
+ (OPENSSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12))
+# define OSSL_LIBRESSL_PREREQ(maj, min, pat) 0
+#else
+# define OSSL_IS_LIBRESSL 1
+# define OSSL_OPENSSL_PREREQ(maj, min, pat) 0
+# define OSSL_LIBRESSL_PREREQ(maj, min, pat) \
+ (LIBRESSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12))
+#endif
+
/*
* Common Module
*/
--
2.32.0
From bbf235091e49807ece8f3a3df95bbfcc9d3ab43d Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Sat, 22 Feb 2020 05:37:01 +0900
Subject: [PATCH 2/5] ts: use TS_VERIFY_CTX_set_certs instead of
TS_VERIFY_CTS_set_certs
OpenSSL 3.0 fixed the typo in the function name and replaced the
current 'CTS' version with a macro.
---
ext/openssl/extconf.rb | 5 ++++-
ext/openssl/openssl_missing.h | 5 +++++
ext/openssl/ossl_ts.c | 2 +-
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 17d93443fc..09cae05b72 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -172,7 +172,7 @@ def find_openssl_library
have_func("TS_STATUS_INFO_get0_status")
have_func("TS_STATUS_INFO_get0_text")
have_func("TS_STATUS_INFO_get0_failure_info")
-have_func("TS_VERIFY_CTS_set_certs")
+have_func("TS_VERIFY_CTS_set_certs(NULL, NULL)", "openssl/ts.h")
have_func("TS_VERIFY_CTX_set_store")
have_func("TS_VERIFY_CTX_add_flags")
have_func("TS_RESP_CTX_set_time_cb")
@@ -181,6 +181,9 @@ def find_openssl_library
# added in 1.1.1
have_func("EVP_PKEY_check")
+
+# added in 3.0.0
+have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", "openssl/ts.h")
Logging::message "=== Checking done. ===\n"
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index e575415f49..fe486bcfcf 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -236,4 +236,9 @@ IMPL_PKEY_GETTER(EC_KEY, ec)
} while (0)
#endif
+/* added in 3.0.0 */
+#if !defined(HAVE_TS_VERIFY_CTX_SET_CERTS)
+# define TS_VERIFY_CTX_set_certs(ctx, crts) TS_VERIFY_CTS_set_certs(ctx, crts)
+#endif
+
#endif /* _OSSL_OPENSSL_MISSING_H_ */
diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c
index 692c0d620f..f1da7c1947 100644
--- a/ext/openssl/ossl_ts.c
+++ b/ext/openssl/ossl_ts.c
@@ -820,7 +820,7 @@ ossl_ts_resp_verify(int argc, VALUE *argv, VALUE self)
X509_up_ref(cert);
}
- TS_VERIFY_CTS_set_certs(ctx, x509inter);
+ TS_VERIFY_CTX_set_certs(ctx, x509inter);
TS_VERIFY_CTX_add_flags(ctx, TS_VFY_SIGNATURE);
TS_VERIFY_CTX_set_store(ctx, x509st);
--
2.32.0
From 5fba3bc1df93ab6abc3ea53be3393480f36ea259 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Fri, 19 Mar 2021 19:18:25 +0900
Subject: [PATCH 3/5] ssl: use SSL_get_rbio() to check if SSL is started or not
Use SSL_get_rbio() instead of SSL_get_fd(). SSL_get_fd() internally
calls SSL_get_rbio() and it's enough for our purpose.
In OpenSSL 3.0, SSL_get_fd() leaves an entry in the OpenSSL error queue
if BIO has not been set up yet, and we would have to clean it up.
---
ext/openssl/ossl_ssl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 4b7efa39f5..ec430bfb0c 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -1535,8 +1535,8 @@ ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self)
static inline int
ssl_started(SSL *ssl)
{
- /* the FD is set in ossl_ssl_setup(), called by #connect or #accept */
- return SSL_get_fd(ssl) >= 0;
+ /* BIO is created through ossl_ssl_setup(), called by #connect or #accept */
+ return SSL_get_rbio(ssl) != NULL;
}
static void
--
2.32.0
From 0a253027e6be47c0b7fd8b664f1048f24d7ca657 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Thu, 22 Apr 2021 13:57:47 +0900
Subject: [PATCH 4/5] digest: use EVP_MD_CTX_get0_md() instead of
EVP_MD_CTX_md() if exists
The function was renamed in OpenSSL 3.0 due to the change of the
lifetime of EVP_MD objects. They are no longer necessarily statically
allocated and can be reference-counted -- when an EVP_MD_CTX is free'd,
the associated EVP_MD can also become inaccessible.
Currently Ruby/OpenSSL only handles builtin algorithms, so no special
handling is needed except for adapting to the rename.
---
ext/openssl/extconf.rb | 1 +
ext/openssl/openssl_missing.h | 4 ++++
ext/openssl/ossl_digest.c | 6 +++---
ext/openssl/ossl_hmac.c | 2 +-
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 98f96afe..842b7f5b 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -184,6 +184,7 @@ def find_openssl_library
# added in 3.0.0
have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", "openssl/ts.h")
+have_func("EVP_MD_CTX_get0_md")
Logging::message "=== Checking done. ===\n"
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index 1b1a54a8..64212349 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -241,4 +241,8 @@ IMPL_PKEY_GETTER(EC_KEY, ec)
# define TS_VERIFY_CTX_set_certs(ctx, crts) TS_VERIFY_CTS_set_certs(ctx, crts)
#endif
+#ifndef HAVE_EVP_MD_CTX_GET0_MD
+# define EVP_MD_CTX_get0_md(ctx) EVP_MD_CTX_md(ctx)
+#endif
+
#endif /* _OSSL_OPENSSL_MISSING_H_ */
diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c
index b2506de7..fc326ec1 100644
--- a/ext/openssl/ossl_digest.c
+++ b/ext/openssl/ossl_digest.c
@@ -63,7 +63,7 @@ ossl_evp_get_digestbyname(VALUE obj)
GetDigest(obj, ctx);
- md = EVP_MD_CTX_md(ctx);
+ md = EVP_MD_CTX_get0_md(ctx);
}
return md;
@@ -176,7 +176,7 @@ ossl_digest_reset(VALUE self)
EVP_MD_CTX *ctx;
GetDigest(self, ctx);
- if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_md(ctx), NULL) != 1) {
+ if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_get0_md(ctx), NULL) != 1) {
ossl_raise(eDigestError, "Digest initialization failed.");
}
@@ -259,7 +259,7 @@ ossl_digest_name(VALUE self)
GetDigest(self, ctx);
- return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx)));
+ return rb_str_new_cstr(EVP_MD_name(EVP_MD_CTX_get0_md(ctx)));
}
/*
diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c
index a21db6c4..2642728b 100644
--- a/ext/openssl/ossl_hmac.c
+++ b/ext/openssl/ossl_hmac.c
@@ -239,7 +239,7 @@ ossl_hmac_reset(VALUE self)
GetHMAC(self, ctx);
pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_pkey_ctx(ctx));
- if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_md(ctx), NULL, pkey) != 1)
+ if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_get0_md(ctx), NULL, pkey) != 1)
ossl_raise(eHMACError, "EVP_DigestSignInit");
return self;
From c106d888c62e44a11cdbba5e4d2d0cb837ec3e52 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Tue, 22 Jun 2021 18:50:17 +0900
Subject: [PATCH 5/5] hmac: use EVP_MD_CTX_get_pkey_ctx() instead of
EVP_MD_CTX_pkey_ctx()
OpenSSL 3.0 renamed EVP_MD_CTX_pkey_ctx() to include "get" in the
function name. Adjust compatibility macro so that we can use the new
function name for all OpenSSL 1.0.2-3.0.
---
ext/openssl/extconf.rb | 1 +
ext/openssl/openssl_missing.h | 16 ++++++++++++----
ext/openssl/ossl_hmac.c | 2 +-
3 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 842b7f5b..d9d34b7c 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -185,6 +185,7 @@ def find_openssl_library
# added in 3.0.0
have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", "openssl/ts.h")
have_func("EVP_MD_CTX_get0_md")
+have_func("EVP_MD_CTX_get_pkey_ctx")
Logging::message "=== Checking done. ===\n"
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index 64212349..55c4f378 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -42,10 +42,6 @@ int ossl_EC_curve_nist2nid(const char *);
# define EVP_MD_CTX_free EVP_MD_CTX_destroy
#endif
-#if !defined(HAVE_EVP_MD_CTX_PKEY_CTX)
-# define EVP_MD_CTX_pkey_ctx(x) (x)->pctx
-#endif
-
#if !defined(HAVE_X509_STORE_GET_EX_DATA)
# define X509_STORE_get_ex_data(x, idx) \
CRYPTO_get_ex_data(&(x)->ex_data, (idx))
@@ -245,4 +241,16 @@ IMPL_PKEY_GETTER(EC_KEY, ec)
# define EVP_MD_CTX_get0_md(ctx) EVP_MD_CTX_md(ctx)
#endif
+/*
+ * OpenSSL 1.1.0 added EVP_MD_CTX_pkey_ctx(), and then it was renamed to
+ * EVP_MD_CTX_get_pkey_ctx(x) in OpenSSL 3.0.
+ */
+#ifndef HAVE_EVP_MD_CTX_GET_PKEY_CTX
+# ifdef HAVE_EVP_MD_CTX_PKEY_CTX
+# define EVP_MD_CTX_get_pkey_ctx(x) EVP_MD_CTX_pkey_ctx(x)
+# else
+# define EVP_MD_CTX_get_pkey_ctx(x) (x)->pctx
+# endif
+#endif
+
#endif /* _OSSL_OPENSSL_MISSING_H_ */
diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c
index 2642728b..f89ff2f9 100644
--- a/ext/openssl/ossl_hmac.c
+++ b/ext/openssl/ossl_hmac.c
@@ -238,7 +238,7 @@ ossl_hmac_reset(VALUE self)
EVP_PKEY *pkey;
GetHMAC(self, ctx);
- pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_pkey_ctx(ctx));
+ pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_get_pkey_ctx(ctx));
if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_get0_md(ctx), NULL, pkey) != 1)
ossl_raise(eHMACError, "EVP_DigestSignInit");

@ -1,93 +0,0 @@
From 96684439e96aa92e10376b5be45f006772028295 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADt=20Ondruch?= <vondruch@redhat.com>
Date: Thu, 21 Oct 2021 13:02:38 +0200
Subject: [PATCH] Properly exclude test cases.
Lets consider the following scenario:
~~~
irb(#<Test::Unit::AutoRunner::Runner:0x0000560f68afc3c8>):001:0> p suite
OpenSSL::TestEC
=> OpenSSL::TestEC
irb(#<Test::Unit::AutoRunner::Runner:0x0000560f68afc3c8>):002:0> p all_test_methods
["test_ECPrivateKey", "test_ECPrivateKey_encrypted", "test_PUBKEY", "test_check_key", "test_derive_key", "test_dh_compute_key", "test_dsa_sign_asn1_FIPS186_3", "test_ec_group", "test_ec_key", "test_ec_point", "test_ec_point_add", "test_ec_point_mul", "test_generate", "test_marshal", "test_sign_verify", "test_sign_verify_raw"]
=>
["test_ECPrivateKey",
"test_ECPrivateKey_encrypted",
"test_PUBKEY",
"test_check_key",
"test_derive_key",
"test_dh_compute_key",
"test_dsa_sign_asn1_FIPS186_3",
"test_ec_group",
"test_ec_key",
"test_ec_point",
"test_ec_point_add",
"test_ec_point_mul",
"test_generate",
"test_marshal",
"test_sign_verify",
"test_sign_verify_raw"]
irb(#<Test::Unit::AutoRunner::Runner:0x0000560f68afc3c8>):003:0> p filter
/\A(?=.*)(?!.*(?-mix:(?-mix:memory_leak)|(?-mix:OpenSSL::TestEC.test_check_key)))/
=> /\A(?=.*)(?!.*(?-mix:(?-mix:memory_leak)|(?-mix:OpenSSL::TestEC.test_check_key)))/
irb(#<Test::Unit::AutoRunner::Runner:0x0000560f68afc3c8>):004:0> method = "test_check_key"
=> "test_check_key"
~~~
The intention here is to exclude the `test_check_key` test case.
Unfortunately this does not work as expected, because the negative filter
is never checked:
~~~
irb(#<Test::Unit::AutoRunner::Runner:0x0000560f68afc3c8>):005:0> filter === method
=> true
irb(#<Test::Unit::AutoRunner::Runner:0x0000560f68afc3c8>):006:0> filter === "#{suite}##{method}"
=> false
irb(#<Test::Unit::AutoRunner::Runner:0x0000560f68afc3c8>):007:0> filter === method || filter === "#{suite}##{method}"
=> true
~~~
Therefore always filter against the fully qualified method name
`#{suite}##{method}`, which should provide the expected result.
However, if plain string filter is used, keep checking also only the
method name.
This resolves [Bug #16936].
---
tool/lib/minitest/unit.rb | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/tool/lib/minitest/unit.rb b/tool/lib/minitest/unit.rb
index c58a609bfa..d5af6cb906 100644
--- a/tool/lib/minitest/unit.rb
+++ b/tool/lib/minitest/unit.rb
@@ -956,9 +956,15 @@ def _run_suite suite, type
all_test_methods = suite.send "#{type}_methods"
- filtered_test_methods = all_test_methods.find_all { |m|
- filter === m || filter === "#{suite}##{m}"
- }
+ filtered_test_methods = if Regexp === filter
+ all_test_methods.find_all { |m|
+ filter === "#{suite}##{m}"
+ }
+ else
+ all_test_methods.find_all {|m|
+ filter === m || filter === "#{suite}##{m}"
+ }
+ end
leakchecker = LeakChecker.new
--
2.32.0

File diff suppressed because it is too large Load Diff

@ -1,229 +0,0 @@
From 3b91792d3d644d6d6b0059cb315c9fe5d3626bab Mon Sep 17 00:00:00 2001
From: Yusuke Endoh <mame@ruby-lang.org>
Date: Sat, 6 Mar 2021 00:03:57 +0900
Subject: [PATCH] Support GCC's DWARF 5 [Bug #17585]
Co-Authored-By: xtkoba (Tee KOBAYASHI) <xtkoba+ruby@gmail.com>
---
addr2line.c | 119 ++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 97 insertions(+), 22 deletions(-)
diff --git a/addr2line.c b/addr2line.c
index 0029cffbca..855efb40d4 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -159,11 +159,12 @@ typedef struct obj_info {
struct dwarf_section debug_info;
struct dwarf_section debug_line;
struct dwarf_section debug_ranges;
+ struct dwarf_section debug_rnglists;
struct dwarf_section debug_str;
struct obj_info *next;
} obj_info_t;
-#define DWARF_SECTION_COUNT 5
+#define DWARF_SECTION_COUNT 6
static struct dwarf_section *
obj_dwarf_section_at(obj_info_t *obj, int n)
@@ -173,6 +174,7 @@ obj_dwarf_section_at(obj_info_t *obj, int n)
&obj->debug_info,
&obj->debug_line,
&obj->debug_ranges,
+ &obj->debug_rnglists,
&obj->debug_str
};
if (n < 0 || DWARF_SECTION_COUNT <= n) {
@@ -411,7 +413,7 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line,
FILL_LINE();
break;
case DW_LNS_advance_pc:
- a = uleb128((char **)&p);
+ a = uleb128((char **)&p) * header.minimum_instruction_length;
addr += a;
break;
case DW_LNS_advance_line: {
@@ -451,7 +453,7 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line,
/* isa = (unsigned int)*/(void)uleb128((char **)&p);
break;
case 0:
- a = *(unsigned char *)p++;
+ a = uleb128((char **)&p);
op = *p++;
switch (op) {
case DW_LNE_end_sequence:
@@ -808,6 +810,18 @@ enum
DW_FORM_addrx4 = 0x2c
};
+/* Range list entry encodings */
+enum {
+ DW_RLE_end_of_list = 0x00,
+ DW_RLE_base_addressx = 0x01,
+ DW_RLE_startx_endx = 0x02,
+ DW_RLE_startx_length = 0x03,
+ DW_RLE_offset_pair = 0x04,
+ DW_RLE_base_address = 0x05,
+ DW_RLE_start_end = 0x06,
+ DW_RLE_start_length = 0x07
+};
+
enum {
VAL_none = 0,
VAL_cstr = 1,
@@ -961,6 +975,23 @@ debug_info_reader_init(DebugInfoReader *reader, obj_info_t *obj)
reader->current_low_pc = 0;
}
+static void
+di_skip_die_attributes(char **p)
+{
+ for (;;) {
+ uint64_t at = uleb128(p);
+ uint64_t form = uleb128(p);
+ if (!at && !form) break;
+ switch (form) {
+ default:
+ break;
+ case DW_FORM_implicit_const:
+ sleb128(p);
+ break;
+ }
+ }
+}
+
static void
di_read_debug_abbrev_cu(DebugInfoReader *reader)
{
@@ -975,12 +1006,7 @@ di_read_debug_abbrev_cu(DebugInfoReader *reader)
prev = abbrev_number;
uleb128(&p); /* tag */
p++; /* has_children */
- /* skip content */
- for (;;) {
- uint64_t at = uleb128(&p);
- uint64_t form = uleb128(&p);
- if (!at && !form) break;
- }
+ di_skip_die_attributes(&p);
}
}
@@ -1244,12 +1270,7 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number)
/* skip 255th record */
uleb128(&p); /* tag */
p++; /* has_children */
- /* skip content */
- for (;;) {
- uint64_t at = uleb128(&p);
- uint64_t form = uleb128(&p);
- if (!at && !form) break;
- }
+ di_skip_die_attributes(&p);
for (uint64_t n = uleb128(&p); abbrev_number != n; n = uleb128(&p)) {
if (n == 0) {
fprintf(stderr,"%d: Abbrev Number %"PRId64" not found\n",__LINE__, abbrev_number);
@@ -1257,12 +1278,7 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number)
}
uleb128(&p); /* tag */
p++; /* has_children */
- /* skip content */
- for (;;) {
- uint64_t at = uleb128(&p);
- uint64_t form = uleb128(&p);
- if (!at && !form) break;
- }
+ di_skip_die_attributes(&p);
}
return p;
}
@@ -1390,6 +1406,21 @@ ranges_set(ranges_t *ptr, DebugInfoValue *v)
}
}
+static uint64_t
+read_dw_form_addr(DebugInfoReader *reader, char **ptr)
+{
+ char *p = *ptr;
+ *ptr = p + reader->format;
+ if (reader->format == 4) {
+ return read_uint32(&p);
+ } else if (reader->format == 8) {
+ return read_uint64(&p);
+ } else {
+ fprintf(stderr,"unknown address_size:%d", reader->address_size);
+ abort();
+ }
+}
+
static uintptr_t
ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr)
{
@@ -1403,8 +1434,50 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr)
}
else if (ptr->ranges_set) {
/* TODO: support base address selection entry */
- char *p = reader->obj->debug_ranges.ptr + ptr->ranges;
+ char *p;
uint64_t base = ptr->low_pc_set ? ptr->low_pc : reader->current_low_pc;
+ if (reader->obj->debug_rnglists.ptr) {
+ p = reader->obj->debug_rnglists.ptr + ptr->ranges;
+ for (;;) {
+ uint8_t rle = read_uint8(&p);
+ uintptr_t base_address = 0;
+ uintptr_t from, to;
+ if (rle == DW_RLE_end_of_list) break;
+ switch (rle) {
+ case DW_RLE_base_addressx:
+ uleb128(&p);
+ break;
+ case DW_RLE_startx_endx:
+ uleb128(&p);
+ uleb128(&p);
+ break;
+ case DW_RLE_startx_length:
+ uleb128(&p);
+ uleb128(&p);
+ break;
+ case DW_RLE_offset_pair:
+ from = base_address + uleb128(&p);
+ to = base_address + uleb128(&p);
+ if (base + from <= addr && addr < base + to) {
+ return from;
+ }
+ break;
+ case DW_RLE_base_address:
+ base_address = read_dw_form_addr(reader, &p);
+ break;
+ case DW_RLE_start_end:
+ read_dw_form_addr(reader, &p);
+ read_dw_form_addr(reader, &p);
+ break;
+ case DW_RLE_start_length:
+ read_dw_form_addr(reader, &p);
+ uleb128(&p);
+ break;
+ }
+ }
+ return false;
+ }
+ p = reader->obj->debug_ranges.ptr + ptr->ranges;
for (;;) {
uintptr_t from = read_uintptr(&p);
uintptr_t to = read_uintptr(&p);
@@ -1750,6 +1823,7 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
".debug_info",
".debug_line",
".debug_ranges",
+ ".debug_rnglists",
".debug_str"
};
@@ -2006,6 +2080,7 @@ found_mach_header:
"__debug_info",
"__debug_line",
"__debug_ranges",
+ "__debug_rnglists",
"__debug_str"
};
struct LP(segment_command) *scmd = (struct LP(segment_command) *)lcmd;

@ -1,831 +0,0 @@
From cf070378020088cd7e69b1cb08be68152ab8a078 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Sun, 17 May 2020 18:25:38 +0900
Subject: [PATCH 1/3] pkey: implement #to_text using EVP API
Use EVP_PKEY_print_private() instead of the low-level API *_print()
functions, such as RSA_print().
EVP_PKEY_print_*() family was added in OpenSSL 1.0.0.
Note that it falls back to EVP_PKEY_print_public() and
EVP_PKEY_print_params() as necessary. This is required for EVP_PKEY_DH
type for which _private() fails if the private component is not set in
the pkey object.
Since the new API works in the same way for all key types, we now
implement #to_text in the base class OpenSSL::PKey::PKey rather than in
each subclass.
---
ext/openssl/ossl_pkey.c | 38 +++++++++++++++++++++++++++++++++++++
ext/openssl/ossl_pkey_dh.c | 29 ----------------------------
ext/openssl/ossl_pkey_dsa.c | 29 ----------------------------
ext/openssl/ossl_pkey_ec.c | 27 --------------------------
ext/openssl/ossl_pkey_rsa.c | 31 ------------------------------
test/openssl/test_pkey.rb | 5 +++++
6 files changed, 43 insertions(+), 116 deletions(-)
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index f9282b9417..21cd4b2cda 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -539,6 +539,43 @@ ossl_pkey_inspect(VALUE self)
OBJ_nid2sn(nid));
}
+/*
+ * call-seq:
+ * pkey.to_text -> string
+ *
+ * Dumps key parameters, public key, and private key components contained in
+ * the key into a human-readable text.
+ *
+ * This is intended for debugging purpose.
+ *
+ * See also the man page EVP_PKEY_print_private(3).
+ */
+static VALUE
+ossl_pkey_to_text(VALUE self)
+{
+ EVP_PKEY *pkey;
+ BIO *bio;
+
+ GetPKey(self, pkey);
+ if (!(bio = BIO_new(BIO_s_mem())))
+ ossl_raise(ePKeyError, "BIO_new");
+
+ if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1)
+ goto out;
+ OSSL_BIO_reset(bio);
+ if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1)
+ goto out;
+ OSSL_BIO_reset(bio);
+ if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1)
+ goto out;
+
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "EVP_PKEY_print_params");
+
+ out:
+ return ossl_membio2str(bio);
+}
+
VALUE
ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
{
@@ -1039,6 +1076,7 @@ Init_ossl_pkey(void)
rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
+ rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0);
rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1);
rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index 6b477b077c..acd3bf474e 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -266,34 +266,6 @@ ossl_dh_get_params(VALUE self)
return hash;
}
-/*
- * call-seq:
- * dh.to_text -> aString
- *
- * Prints all parameters of key to buffer
- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
- * Don't use :-)) (I's up to you)
- */
-static VALUE
-ossl_dh_to_text(VALUE self)
-{
- DH *dh;
- BIO *out;
- VALUE str;
-
- GetDH(self, dh);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eDHError, NULL);
- }
- if (!DHparams_print(out, dh)) {
- BIO_free(out);
- ossl_raise(eDHError, NULL);
- }
- str = ossl_membio2str(out);
-
- return str;
-}
-
/*
* call-seq:
* dh.public_key -> aDH
@@ -426,7 +398,6 @@ Init_ossl_dh(void)
rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1);
rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
- rb_define_method(cDH, "to_text", ossl_dh_to_text, 0);
rb_define_method(cDH, "export", ossl_dh_export, 0);
rb_define_alias(cDH, "to_pem", "export");
rb_define_alias(cDH, "to_s", "export");
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index 1c5a8a737e..f017cceb4a 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -264,34 +264,6 @@ ossl_dsa_get_params(VALUE self)
return hash;
}
-/*
- * call-seq:
- * dsa.to_text -> aString
- *
- * Prints all parameters of key to buffer
- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
- * Don't use :-)) (I's up to you)
- */
-static VALUE
-ossl_dsa_to_text(VALUE self)
-{
- DSA *dsa;
- BIO *out;
- VALUE str;
-
- GetDSA(self, dsa);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eDSAError, NULL);
- }
- if (!DSA_print(out, dsa, 0)) { /* offset = 0 */
- BIO_free(out);
- ossl_raise(eDSAError, NULL);
- }
- str = ossl_membio2str(out);
-
- return str;
-}
-
/*
* call-seq:
* dsa.public_key -> aDSA
@@ -469,7 +441,6 @@ Init_ossl_dsa(void)
rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
- rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0);
rb_define_method(cDSA, "export", ossl_dsa_export, -1);
rb_define_alias(cDSA, "to_pem", "export");
rb_define_alias(cDSA, "to_s", "export");
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index c2534251c3..ecb8305184 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -417,32 +417,6 @@ ossl_ec_key_to_der(VALUE self)
else
return ossl_pkey_export_spki(self, 1);
}
-
-/*
- * call-seq:
- * key.to_text => String
- *
- * See the OpenSSL documentation for EC_KEY_print()
- */
-static VALUE ossl_ec_key_to_text(VALUE self)
-{
- EC_KEY *ec;
- BIO *out;
- VALUE str;
-
- GetEC(self, ec);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eECError, "BIO_new(BIO_s_mem())");
- }
- if (!EC_KEY_print(out, ec, 0)) {
- BIO_free(out);
- ossl_raise(eECError, "EC_KEY_print");
- }
- str = ossl_membio2str(out);
-
- return str;
-}
-
/*
* call-seq:
* key.generate_key! => self
@@ -1633,7 +1607,6 @@ void Init_ossl_ec(void)
rb_define_method(cEC, "export", ossl_ec_key_export, -1);
rb_define_alias(cEC, "to_pem", "export");
rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
- rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 43f82cb29e..7a7e66dbda 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -587,36 +587,6 @@ ossl_rsa_get_params(VALUE self)
return hash;
}
-/*
- * call-seq:
- * rsa.to_text => String
- *
- * THIS METHOD IS INSECURE, PRIVATE INFORMATION CAN LEAK OUT!!!
- *
- * Dumps all parameters of a keypair to a String
- *
- * Don't use :-)) (It's up to you)
- */
-static VALUE
-ossl_rsa_to_text(VALUE self)
-{
- RSA *rsa;
- BIO *out;
- VALUE str;
-
- GetRSA(self, rsa);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eRSAError, NULL);
- }
- if (!RSA_print(out, rsa, 0)) { /* offset = 0 */
- BIO_free(out);
- ossl_raise(eRSAError, NULL);
- }
- str = ossl_membio2str(out);
-
- return str;
-}
-
/*
* call-seq:
* rsa.public_key -> RSA
@@ -738,7 +708,6 @@ Init_ossl_rsa(void)
rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0);
rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0);
- rb_define_method(cRSA, "to_text", ossl_rsa_to_text, 0);
rb_define_method(cRSA, "export", ossl_rsa_export, -1);
rb_define_alias(cRSA, "to_pem", "export");
rb_define_alias(cRSA, "to_s", "export");
diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb
index 5307fe5b08..3630458b3c 100644
--- a/test/openssl/test_pkey.rb
+++ b/test/openssl/test_pkey.rb
@@ -151,4 +151,9 @@ def test_x25519
assert_equal bob_pem, bob.public_to_pem
assert_equal [shared_secret].pack("H*"), alice.derive(bob)
end
+
+ def test_to_text
+ rsa = Fixtures.pkey("rsa1024")
+ assert_include rsa.to_text, "publicExponent"
+ end
end
--
2.32.0
From 0c45b22e485bfa62f4d704b08e3704e6444118c4 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Thu, 15 Apr 2021 19:11:32 +0900
Subject: [PATCH 2/3] pkey: implement {DH,DSA,RSA}#public_key in Ruby
The low-level API that is used to implement #public_key is deprecated
in OpenSSL 3.0. It is actually very simple to implement in another way,
using existing methods only, in much shorter code. Let's do it.
While we are at it, the documentation is updated to recommend against
using #public_key. Now that OpenSSL::PKey::PKey implements public_to_der
method, there is no real use case for #public_key in newly written Ruby
programs.
---
ext/openssl/lib/openssl/pkey.rb | 55 ++++++++++++++++++++++++++++
ext/openssl/ossl_pkey_dh.c | 63 +++++++--------------------------
ext/openssl/ossl_pkey_dsa.c | 42 ----------------------
ext/openssl/ossl_pkey_rsa.c | 58 +-----------------------------
test/openssl/test_pkey_rsa.rb | 37 ++++++++++---------
5 files changed, 87 insertions(+), 168 deletions(-)
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb
index 53ee52f98b..569559e1ce 100644
--- a/ext/openssl/lib/openssl/pkey.rb
+++ b/ext/openssl/lib/openssl/pkey.rb
@@ -10,6 +10,30 @@ module OpenSSL::PKey
class DH
include OpenSSL::Marshal
+ # :call-seq:
+ # dh.public_key -> dhnew
+ #
+ # Returns a new DH instance that carries just the \DH parameters.
+ #
+ # Contrary to the method name, the returned DH object contains only
+ # parameters and not the public key.
+ #
+ # This method is provided for backwards compatibility. In most cases, there
+ # is no need to call this method.
+ #
+ # For the purpose of re-generating the key pair while keeping the
+ # parameters, check OpenSSL::PKey.generate_key.
+ #
+ # Example:
+ # # OpenSSL::PKey::DH.generate by default generates a random key pair
+ # dh1 = OpenSSL::PKey::DH.generate(2048)
+ # p dh1.priv_key #=> #<OpenSSL::BN 1288347...>
+ # dhcopy = dh1.public_key
+ # p dhcopy.priv_key #=> nil
+ def public_key
+ DH.new(to_der)
+ end
+
# :call-seq:
# dh.compute_key(pub_bn) -> string
#
@@ -89,6 +113,22 @@ def new(*args, &blk) # :nodoc:
class DSA
include OpenSSL::Marshal
+ # :call-seq:
+ # dsa.public_key -> dsanew
+ #
+ # Returns a new DSA instance that carries just the \DSA parameters and the
+ # public key.
+ #
+ # This method is provided for backwards compatibility. In most cases, there
+ # is no need to call this method.
+ #
+ # For the purpose of serializing the public key, to PEM or DER encoding of
+ # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and
+ # PKey#public_to_der.
+ def public_key
+ OpenSSL::PKey.read(public_to_der)
+ end
+
class << self
# :call-seq:
# DSA.generate(size) -> dsa
@@ -159,6 +199,21 @@ def to_bn(conversion_form = group.point_conversion_form)
class RSA
include OpenSSL::Marshal
+ # :call-seq:
+ # rsa.public_key -> rsanew
+ #
+ # Returns a new RSA instance that carries just the public key components.
+ #
+ # This method is provided for backwards compatibility. In most cases, there
+ # is no need to call this method.
+ #
+ # For the purpose of serializing the public key, to PEM or DER encoding of
+ # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and
+ # PKey#public_to_der.
+ def public_key
+ OpenSSL::PKey.read(public_to_der)
+ end
+
class << self
# :call-seq:
# RSA.generate(size, exponent = 65537) -> RSA
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index acd3bf474e..a512b209d3 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -266,48 +266,6 @@ ossl_dh_get_params(VALUE self)
return hash;
}
-/*
- * call-seq:
- * dh.public_key -> aDH
- *
- * Returns a new DH instance that carries just the public information, i.e.
- * the prime _p_ and the generator _g_, but no public/private key yet. Such
- * a pair may be generated using DH#generate_key!. The "public key" needed
- * for a key exchange with DH#compute_key is considered as per-session
- * information and may be retrieved with DH#pub_key once a key pair has
- * been generated.
- * If the current instance already contains private information (and thus a
- * valid public/private key pair), this information will no longer be present
- * in the new instance generated by DH#public_key. This feature is helpful for
- * publishing the Diffie-Hellman parameters without leaking any of the private
- * per-session information.
- *
- * === Example
- * dh = OpenSSL::PKey::DH.new(2048) # has public and private key set
- * public_key = dh.public_key # contains only prime and generator
- * parameters = public_key.to_der # it's safe to publish this
- */
-static VALUE
-ossl_dh_to_public_key(VALUE self)
-{
- EVP_PKEY *pkey;
- DH *orig_dh, *dh;
- VALUE obj;
-
- obj = rb_obj_alloc(rb_obj_class(self));
- GetPKey(obj, pkey);
-
- GetDH(self, orig_dh);
- dh = DHparams_dup(orig_dh);
- if (!dh)
- ossl_raise(eDHError, "DHparams_dup");
- if (!EVP_PKEY_assign_DH(pkey, dh)) {
- DH_free(dh);
- ossl_raise(eDHError, "EVP_PKEY_assign_DH");
- }
- return obj;
-}
-
/*
* call-seq:
* dh.params_ok? -> true | false
@@ -384,14 +342,20 @@ Init_ossl_dh(void)
* The per-session private key, an OpenSSL::BN.
*
* === Example of a key exchange
- * dh1 = OpenSSL::PKey::DH.new(2048)
- * der = dh1.public_key.to_der #you may send this publicly to the participating party
- * dh2 = OpenSSL::PKey::DH.new(der)
- * dh2.generate_key! #generate the per-session key pair
- * symm_key1 = dh1.compute_key(dh2.pub_key)
- * symm_key2 = dh2.compute_key(dh1.pub_key)
+ * # you may send the parameters (der) and own public key (pub1) publicly
+ * # to the participating party
+ * dh1 = OpenSSL::PKey::DH.new(2048)
+ * der = dh1.to_der
+ * pub1 = dh1.pub_key
+ *
+ * # the other party generates its per-session key pair
+ * dhparams = OpenSSL::PKey::DH.new(der)
+ * dh2 = OpenSSL::PKey.generate_key(dhparams)
+ * pub2 = dh2.pub_key
*
- * puts symm_key1 == symm_key2 # => true
+ * symm_key1 = dh1.compute_key(pub2)
+ * symm_key2 = dh2.compute_key(pub1)
+ * puts symm_key1 == symm_key2 # => true
*/
cDH = rb_define_class_under(mPKey, "DH", cPKey);
rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
@@ -402,7 +366,6 @@ Init_ossl_dh(void)
rb_define_alias(cDH, "to_pem", "export");
rb_define_alias(cDH, "to_s", "export");
rb_define_method(cDH, "to_der", ossl_dh_to_der, 0);
- rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);
DEF_OSSL_PKEY_BN(cDH, dh, p);
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index f017cceb4a..ab9ac781e8 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -264,47 +264,6 @@ ossl_dsa_get_params(VALUE self)
return hash;
}
-/*
- * call-seq:
- * dsa.public_key -> aDSA
- *
- * Returns a new DSA instance that carries just the public key information.
- * If the current instance has also private key information, this will no
- * longer be present in the new instance. This feature is helpful for
- * publishing the public key information without leaking any of the private
- * information.
- *
- * === Example
- * dsa = OpenSSL::PKey::DSA.new(2048) # has public and private information
- * pub_key = dsa.public_key # has only the public part available
- * pub_key_der = pub_key.to_der # it's safe to publish this
- *
- *
- */
-static VALUE
-ossl_dsa_to_public_key(VALUE self)
-{
- EVP_PKEY *pkey, *pkey_new;
- DSA *dsa;
- VALUE obj;
-
- GetPKeyDSA(self, pkey);
- obj = rb_obj_alloc(rb_obj_class(self));
- GetPKey(obj, pkey_new);
-
-#define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \
- (i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa))
- dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey));
-#undef DSAPublicKey_dup
- if (!dsa)
- ossl_raise(eDSAError, "DSAPublicKey_dup");
- if (!EVP_PKEY_assign_DSA(pkey_new, dsa)) {
- DSA_free(dsa);
- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
- }
- return obj;
-}
-
/*
* call-seq:
* dsa.syssign(string) -> aString
@@ -445,7 +404,6 @@ Init_ossl_dsa(void)
rb_define_alias(cDSA, "to_pem", "export");
rb_define_alias(cDSA, "to_s", "export");
rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0);
- rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0);
rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1);
rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2);
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 7a7e66dbda..1c5476cdcd 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -390,7 +390,7 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
* data = "Sign me!"
* pkey = OpenSSL::PKey::RSA.new(2048)
* signature = pkey.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA256")
- * pub_key = pkey.public_key
+ * pub_key = OpenSSL::PKey.read(pkey.public_to_der)
* puts pub_key.verify_pss("SHA256", signature, data,
* salt_length: :auto, mgf1_hash: "SHA256") # => true
*/
@@ -587,61 +587,6 @@ ossl_rsa_get_params(VALUE self)
return hash;
}
-/*
- * call-seq:
- * rsa.public_key -> RSA
- *
- * Makes new RSA instance containing the public key from the private key.
- */
-static VALUE
-ossl_rsa_to_public_key(VALUE self)
-{
- EVP_PKEY *pkey, *pkey_new;
- RSA *rsa;
- VALUE obj;
-
- GetPKeyRSA(self, pkey);
- obj = rb_obj_alloc(rb_obj_class(self));
- GetPKey(obj, pkey_new);
-
- rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey));
- if (!rsa)
- ossl_raise(eRSAError, "RSAPublicKey_dup");
- if (!EVP_PKEY_assign_RSA(pkey_new, rsa)) {
- RSA_free(rsa);
- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
- }
- return obj;
-}
-
-/*
- * TODO: Test me
-
-static VALUE
-ossl_rsa_blinding_on(VALUE self)
-{
- RSA *rsa;
-
- GetRSA(self, rsa);
-
- if (RSA_blinding_on(rsa, ossl_bn_ctx) != 1) {
- ossl_raise(eRSAError, NULL);
- }
- return self;
-}
-
-static VALUE
-ossl_rsa_blinding_off(VALUE self)
-{
- RSA *rsa;
-
- GetRSA(self, rsa);
- RSA_blinding_off(rsa);
-
- return self;
-}
- */
-
/*
* Document-method: OpenSSL::PKey::RSA#set_key
* call-seq:
@@ -712,7 +657,6 @@ Init_ossl_rsa(void)
rb_define_alias(cRSA, "to_pem", "export");
rb_define_alias(cRSA, "to_s", "export");
rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0);
- rb_define_method(cRSA, "public_key", ossl_rsa_to_public_key, 0);
rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, -1);
rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1);
rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1);
diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb
index d1e68dbc9f..5f8d04e754 100644
--- a/test/openssl/test_pkey_rsa.rb
+++ b/test/openssl/test_pkey_rsa.rb
@@ -69,29 +69,28 @@ def test_private
end
def test_new
- key = OpenSSL::PKey::RSA.new 512
- pem = key.public_key.to_pem
- OpenSSL::PKey::RSA.new pem
- assert_equal([], OpenSSL.errors)
- end
+ key = OpenSSL::PKey::RSA.new(512)
+ assert_equal 512, key.n.num_bits
+ assert_equal 65537, key.e
+ assert_not_nil key.d
- def test_new_exponent_default
- assert_equal(65537, OpenSSL::PKey::RSA.new(512).e)
+ # Specify public exponent
+ key2 = OpenSSL::PKey::RSA.new(512, 3)
+ assert_equal 512, key2.n.num_bits
+ assert_equal 3, key2.e
+ assert_not_nil key2.d
end
- def test_new_with_exponent
- 1.upto(30) do |idx|
- e = (2 ** idx) + 1
- key = OpenSSL::PKey::RSA.new(512, e)
- assert_equal(e, key.e)
- end
- end
+ def test_s_generate
+ key1 = OpenSSL::PKey::RSA.generate(512)
+ assert_equal 512, key1.n.num_bits
+ assert_equal 65537, key1.e
- def test_generate
- key = OpenSSL::PKey::RSA.generate(512, 17)
- assert_equal 512, key.n.num_bits
- assert_equal 17, key.e
- assert_not_nil key.d
+ # Specify public exponent
+ key2 = OpenSSL::PKey::RSA.generate(512, 3)
+ assert_equal 512, key2.n.num_bits
+ assert_equal 3, key2.e
+ assert_not_nil key2.d
end
def test_new_break
--
2.32.0
From 2150af0e55b2a25c24f62006e27e0aec3dc81b57 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Fri, 10 Jul 2020 14:34:51 +0900
Subject: [PATCH 3/3] pkey/dh, pkey/ec: use EVP_PKEY_check() family
Use EVP_PKEY_param_check() instead of DH_check() if available. Also,
use EVP_PKEY_public_check() instead of EC_KEY_check_key().
EVP_PKEY_*check() is part of the EVP API and is meant to replace those
low-level functions. They were added by OpenSSL 1.1.1. It is currently
not provided by LibreSSL.
---
ext/openssl/extconf.rb | 3 +++
ext/openssl/ossl_pkey_dh.c | 27 +++++++++++++++++++++++----
ext/openssl/ossl_pkey_ec.c | 23 +++++++++++++++++++----
test/openssl/test_pkey_dh.rb | 16 ++++++++++++++++
4 files changed, 61 insertions(+), 8 deletions(-)
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index b3c6647faf..17d93443fc 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -179,6 +179,9 @@ def find_openssl_library
have_func("EVP_PBE_scrypt")
have_func("SSL_CTX_set_post_handshake_auth")
+# added in 1.1.1
+have_func("EVP_PKEY_check")
+
Logging::message "=== Checking done. ===\n"
create_header
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index a512b209d3..ca782bbe59 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -273,19 +273,38 @@ ossl_dh_get_params(VALUE self)
* Validates the Diffie-Hellman parameters associated with this instance.
* It checks whether a safe prime and a suitable generator are used. If this
* is not the case, +false+ is returned.
+ *
+ * See also the man page EVP_PKEY_param_check(3).
*/
static VALUE
ossl_dh_check_params(VALUE self)
{
+ int ret;
+#ifdef HAVE_EVP_PKEY_CHECK
+ EVP_PKEY *pkey;
+ EVP_PKEY_CTX *pctx;
+
+ GetPKey(self, pkey);
+ pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
+ if (!pctx)
+ ossl_raise(eDHError, "EVP_PKEY_CTX_new");
+ ret = EVP_PKEY_param_check(pctx);
+ EVP_PKEY_CTX_free(pctx);
+#else
DH *dh;
int codes;
GetDH(self, dh);
- if (!DH_check(dh, &codes)) {
- return Qfalse;
- }
+ ret = DH_check(dh, &codes) == 1 && codes == 0;
+#endif
- return codes == 0 ? Qtrue : Qfalse;
+ if (ret == 1)
+ return Qtrue;
+ else {
+ /* DH_check_ex() will put error entry on failure */
+ ossl_clear_error();
+ return Qfalse;
+ }
}
/*
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index ecb8305184..829529d4b9 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -443,20 +443,35 @@ static VALUE ossl_ec_key_generate_key(VALUE self)
}
/*
- * call-seq:
- * key.check_key => true
+ * call-seq:
+ * key.check_key => true
*
- * Raises an exception if the key is invalid.
+ * Raises an exception if the key is invalid.
*
- * See the OpenSSL documentation for EC_KEY_check_key()
+ * See also the man page EVP_PKEY_public_check(3).
*/
static VALUE ossl_ec_key_check_key(VALUE self)
{
+#ifdef HAVE_EVP_PKEY_CHECK
+ EVP_PKEY *pkey;
+ EVP_PKEY_CTX *pctx;
+ int ret;
+
+ GetPKey(self, pkey);
+ pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
+ if (!pctx)
+ ossl_raise(eDHError, "EVP_PKEY_CTX_new");
+ ret = EVP_PKEY_public_check(pctx);
+ EVP_PKEY_CTX_free(pctx);
+ if (ret != 1)
+ ossl_raise(eECError, "EVP_PKEY_public_check");
+#else
EC_KEY *ec;
GetEC(self, ec);
if (EC_KEY_check_key(ec) != 1)
ossl_raise(eECError, "EC_KEY_check_key");
+#endif
return Qtrue;
}
diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb
index 279ce1984c..f80af8f841 100644
--- a/test/openssl/test_pkey_dh.rb
+++ b/test/openssl/test_pkey_dh.rb
@@ -86,6 +86,22 @@ def test_key_exchange
assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key))
end
+ def test_params_ok?
+ dh0 = Fixtures.pkey("dh1024")
+
+ dh1 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([
+ OpenSSL::ASN1::Integer(dh0.p),
+ OpenSSL::ASN1::Integer(dh0.g)
+ ]))
+ assert_equal(true, dh1.params_ok?)
+
+ dh2 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([
+ OpenSSL::ASN1::Integer(dh0.p + 1),
+ OpenSSL::ASN1::Integer(dh0.g)
+ ]))
+ assert_equal(false, dh2.params_ok?)
+ end
+
def test_dup
dh = Fixtures.pkey("dh1024")
dh2 = dh.dup
--
2.32.0

@ -1,114 +0,0 @@
From 8c185e0ae5e42bf5f3d76a1a0898946671116fa3 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Wed, 3 Nov 2021 23:31:29 +0900
Subject: [PATCH 1/2] pkey: test parsing concatenated PEM string
PEM-encoded private keys are sometimes stored together with irrelevant
PEM blocks, such as the corresponding X.509 certificate.
PEM_read_bio_*() family automatically skips unknown PEM blocks, but on
OpenSSL 3.0 we will be using the new OSSL_DECODER API instead due to
some breaking changes around the password callback.
Let's add a test case so that we won't break the current behavior.
---
test/openssl/test_pkey_rsa.rb | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb
index dbe87ba4..7510658d 100644
--- a/test/openssl/test_pkey_rsa.rb
+++ b/test/openssl/test_pkey_rsa.rb
@@ -306,6 +306,12 @@ def test_RSAPrivateKey
assert_equal asn1.to_der, rsa1024.to_der
assert_equal pem, rsa1024.export
+
+ # Unknown PEM prepended
+ cert = issue_cert(OpenSSL::X509::Name.new([["CN", "nobody"]]), rsa1024, 1, [], nil, nil)
+ str = cert.to_text + cert.to_pem + rsa1024.to_pem
+ key = OpenSSL::PKey::RSA.new(str)
+ assert_same_rsa rsa1024, key
end
def test_RSAPrivateKey_encrypted
From a84ea531bbd080c3f58fe8d3dc9ffb1af2251f35 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Sat, 20 Mar 2021 23:16:16 +0900
Subject: [PATCH 2/2] pkey: use OSSL_DECODER to load encrypted PEM on OpenSSL
3.0
OpenSSL 3.0 has rewritten routines to load pkeys (PEM_read_bio_* and
d2i_* functions) around the newly introduced OSSL_DECODER API.
This comes with a slight behavior change. They now decrypt and parse
each encountered PEM block, then check the kind of the block. This used
to be the reverse: they checked the PEM header to see the kind, and then
decrypted the content. This means that the password callback may now be
called repeatedly.
Let's use the OSSL_DECODER API directly on OpenSSL 3.0 so that the
return value from the password callback will be reused automatically.
---
ext/openssl/ossl_pkey.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index f9f5162e..b08168a5 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -78,6 +78,45 @@ ossl_pkey_new(EVP_PKEY *pkey)
return obj;
}
+#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+# include <openssl/decoder.h>
+
+EVP_PKEY *
+ossl_pkey_read_generic(BIO *bio, VALUE pass)
+{
+ void *ppass = (void *)pass;
+ OSSL_DECODER_CTX *dctx;
+ EVP_PKEY *pkey = NULL;
+ int pos = 0, pos2;
+
+ dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, NULL, 0, NULL, NULL);
+ if (!dctx)
+ goto out;
+ if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
+ goto out;
+
+ /* First check DER */
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
+ goto out;
+
+ /* Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed */
+ OSSL_BIO_reset(bio);
+ if (OSSL_DECODER_CTX_set_input_type(dctx, "PEM") != 1)
+ goto out;
+ while (OSSL_DECODER_from_bio(dctx, bio) != 1) {
+ if (BIO_eof(bio))
+ goto out;
+ pos2 = BIO_tell(bio);
+ if (pos2 < 0 || pos2 <= pos)
+ goto out;
+ pos = pos2;
+ }
+
+ out:
+ OSSL_DECODER_CTX_free(dctx);
+ return pkey;
+}
+#else
EVP_PKEY *
ossl_pkey_read_generic(BIO *bio, VALUE pass)
{
@@ -106,6 +145,7 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
out:
return pkey;
}
+#endif
/*
* call-seq:

@ -1,359 +0,0 @@
From bcab8c3cd877506de75f50e0f9ed98827ed554b0 Mon Sep 17 00:00:00 2001
From: Peter Zhu <peter@peterzhu.ca>
Date: Tue, 23 Feb 2021 16:28:56 -0500
Subject: [PATCH] Use mmap for allocating heap pages
---
configure.ac | 16 ++++
gc.c | 149 ++++++++++++++++++++++++++---------
test/ruby/test_gc_compact.rb | 41 ++++++----
3 files changed, 155 insertions(+), 51 deletions(-)
diff --git a/configure.ac b/configure.ac
index 2dcebdde9f..b1b190004d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1952,6 +1952,7 @@ AC_CHECK_FUNCS(memmem)
AC_CHECK_FUNCS(mkfifo)
AC_CHECK_FUNCS(mknod)
AC_CHECK_FUNCS(mktime)
+AC_CHECK_FUNCS(mmap)
AC_CHECK_FUNCS(openat)
AC_CHECK_FUNCS(pipe2)
AC_CHECK_FUNCS(poll)
@@ -2674,6 +2675,21 @@ main(int argc, char *argv[])
rb_cv_fork_with_pthread=yes)])
test x$rb_cv_fork_with_pthread = xyes || AC_DEFINE(CANNOT_FORK_WITH_PTHREAD)
])
+
+AC_CHECK_HEADERS([sys/user.h])
+AS_IF([test "x$ac_cv_func_mmap" = xyes], [
+ AC_CACHE_CHECK([whether PAGE_SIZE is compile-time const], rb_cv_const_page_size,
+ [malloc_headers=`sed -n '/MALLOC_HEADERS_BEGIN/,/MALLOC_HEADERS_END/p' ${srcdir}/gc.c`
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$malloc_headers
+ typedef char conftest_page[PAGE_SIZE];
+ ]], [[]])],
+ [rb_cv_const_page_size=yes],
+ [rb_cv_const_page_size=no])])
+])
+AS_IF([test "x$rb_cv_const_page_size" = xyes],
+ [AC_DEFINE(HAVE_CONST_PAGE_SIZE, 1)],
+ [AC_DEFINE(HAVE_CONST_PAGE_SIZE, 0)]
+)
}
: "runtime section" && {
diff --git a/gc.c b/gc.c
index f6acf3e117..6f8e5f242d 100644
--- a/gc.c
+++ b/gc.c
@@ -32,6 +32,7 @@
#include <stdarg.h>
#include <stdio.h>
+/* MALLOC_HEADERS_BEGIN */
#ifndef HAVE_MALLOC_USABLE_SIZE
# ifdef _WIN32
# define HAVE_MALLOC_USABLE_SIZE
@@ -54,6 +55,12 @@
# endif
#endif
+#if !defined(PAGE_SIZE) && defined(HAVE_SYS_USER_H)
+/* LIST_HEAD conflicts with sys/queue.h on macOS */
+# include <sys/user.h>
+#endif
+/* MALLOC_HEADERS_END */
+
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
@@ -821,6 +828,25 @@ enum {
HEAP_PAGE_BITMAP_SIZE = (BITS_SIZE * HEAP_PAGE_BITMAP_LIMIT),
HEAP_PAGE_BITMAP_PLANES = 4 /* RGENGC: mark, unprotected, uncollectible, marking */
};
+#define HEAP_PAGE_ALIGN (1 << HEAP_PAGE_ALIGN_LOG)
+#define HEAP_PAGE_SIZE HEAP_PAGE_ALIGN
+
+#ifdef HAVE_MMAP
+# if HAVE_CONST_PAGE_SIZE
+/* If we have the HEAP_PAGE and it is a constant, then we can directly use it. */
+static const bool USE_MMAP_ALIGNED_ALLOC = (PAGE_SIZE <= HEAP_PAGE_SIZE);
+# elif defined(PAGE_MAX_SIZE) && (PAGE_MAX_SIZE <= HEAP_PAGE_SIZE)
+/* PAGE_SIZE <= HEAP_PAGE_SIZE */
+static const bool USE_MMAP_ALIGNED_ALLOC = true;
+# else
+/* Otherwise, fall back to determining if we can use mmap during runtime. */
+# define USE_MMAP_ALIGNED_ALLOC (use_mmap_aligned_alloc != false)
+
+static bool use_mmap_aligned_alloc;
+# endif
+#elif !defined(__MINGW32__) && !defined(_WIN32)
+static const bool USE_MMAP_ALIGNED_ALLOC = false;
+#endif
struct heap_page {
short total_slots;
@@ -1760,14 +1786,14 @@ heap_unlink_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *pag
heap->total_slots -= page->total_slots;
}
-static void rb_aligned_free(void *ptr);
+static void rb_aligned_free(void *ptr, size_t size);
static void
heap_page_free(rb_objspace_t *objspace, struct heap_page *page)
{
heap_allocated_pages--;
objspace->profile.total_freed_pages++;
- rb_aligned_free(GET_PAGE_BODY(page->start));
+ rb_aligned_free(GET_PAGE_BODY(page->start), HEAP_PAGE_SIZE);
free(page);
}
@@ -1819,7 +1845,7 @@ heap_page_allocate(rb_objspace_t *objspace)
/* assign heap_page entry */
page = calloc1(sizeof(struct heap_page));
if (page == 0) {
- rb_aligned_free(page_body);
+ rb_aligned_free(page_body, HEAP_PAGE_SIZE);
rb_memerror();
}
@@ -3159,15 +3185,18 @@ Init_heap(void)
{
rb_objspace_t *objspace = &rb_objspace;
-#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
- /* If Ruby's heap pages are not a multiple of the system page size, we
- * cannot use mprotect for the read barrier, so we must disable automatic
- * compaction. */
- int pagesize;
- pagesize = (int)sysconf(_SC_PAGE_SIZE);
- if ((HEAP_PAGE_SIZE % pagesize) != 0) {
- ruby_enable_autocompact = 0;
- }
+#if defined(HAVE_MMAP) && !HAVE_CONST_PAGE_SIZE && !defined(PAGE_MAX_SIZE)
+ /* Need to determine if we can use mmap at runtime. */
+# ifdef PAGE_SIZE
+ /* If the PAGE_SIZE macro can be used. */
+ use_mmap_aligned_alloc = PAGE_SIZE <= HEAP_PAGE_SIZE;
+# elif defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
+ /* If we can use sysconf to determine the page size. */
+ use_mmap_aligned_alloc = sysconf(_SC_PAGE_SIZE) <= HEAP_PAGE_SIZE;
+# else
+ /* Otherwise we can't determine the system page size, so don't use mmap. */
+ use_mmap_aligned_alloc = FALSE;
+# endif
#endif
objspace->next_object_id = INT2FIX(OBJ_ID_INITIAL);
@@ -8533,6 +8562,14 @@ gc_start_internal(rb_execution_context_t *ec, VALUE self, VALUE full_mark, VALUE
/* For now, compact implies full mark / sweep, so ignore other flags */
if (RTEST(compact)) {
+ /* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for
+ * the read barrier, so we must disable compaction. */
+#if !defined(__MINGW32__) && !defined(_WIN32)
+ if (!USE_MMAP_ALIGNED_ALLOC) {
+ rb_raise(rb_eNotImpError, "Compaction isn't available on this platform");
+ }
+#endif
+
reason |= GPR_FLAG_COMPACT;
} else {
if (!RTEST(full_mark)) reason &= ~GPR_FLAG_FULL_MARK;
@@ -9944,16 +9981,14 @@ gc_disable(rb_execution_context_t *ec, VALUE _)
static VALUE
gc_set_auto_compact(rb_execution_context_t *ec, VALUE _, VALUE v)
{
-#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
- /* If Ruby's heap pages are not a multiple of the system page size, we
- * cannot use mprotect for the read barrier, so we must disable automatic
- * compaction. */
- int pagesize;
- pagesize = (int)sysconf(_SC_PAGE_SIZE);
- if ((HEAP_PAGE_SIZE % pagesize) != 0) {
+ /* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for
+ * the read barrier, so we must disable automatic compaction. */
+#if !defined(__MINGW32__) && !defined(_WIN32)
+ if (!USE_MMAP_ALIGNED_ALLOC) {
rb_raise(rb_eNotImpError, "Automatic compaction isn't available on this platform");
}
#endif
+
ruby_enable_autocompact = RTEST(v);
return v;
}
@@ -10350,22 +10385,54 @@ rb_aligned_malloc(size_t alignment, size_t size)
#elif defined _WIN32
void *_aligned_malloc(size_t, size_t);
res = _aligned_malloc(size, alignment);
-#elif defined(HAVE_POSIX_MEMALIGN)
- if (posix_memalign(&res, alignment, size) == 0) {
- return res;
+#else
+ if (USE_MMAP_ALIGNED_ALLOC) {
+ GC_ASSERT(alignment % sysconf(_SC_PAGE_SIZE) == 0);
+
+ char *ptr = mmap(NULL, alignment + size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (ptr == MAP_FAILED) {
+ return NULL;
+ }
+
+ char *aligned = ptr + alignment;
+ aligned -= ((VALUE)aligned & (alignment - 1));
+ GC_ASSERT(aligned > ptr);
+ GC_ASSERT(aligned <= ptr + alignment);
+
+ size_t start_out_of_range_size = aligned - ptr;
+ GC_ASSERT(start_out_of_range_size % sysconf(_SC_PAGE_SIZE) == 0);
+ if (start_out_of_range_size > 0) {
+ if (munmap(ptr, start_out_of_range_size)) {
+ rb_bug("rb_aligned_malloc: munmap failed for start");
+ }
+ }
+
+ size_t end_out_of_range_size = alignment - start_out_of_range_size;
+ GC_ASSERT(end_out_of_range_size % sysconf(_SC_PAGE_SIZE) == 0);
+ if (end_out_of_range_size > 0) {
+ if (munmap(aligned + size, end_out_of_range_size)) {
+ rb_bug("rb_aligned_malloc: munmap failed for end");
+ }
+ }
+
+ res = (void *)aligned;
}
else {
- return NULL;
+# if defined(HAVE_POSIX_MEMALIGN)
+ if (posix_memalign(&res, alignment, size) != 0) {
+ return NULL;
+ }
+# elif defined(HAVE_MEMALIGN)
+ res = memalign(alignment, size);
+# else
+ char* aligned;
+ res = malloc(alignment + size + sizeof(void*));
+ aligned = (char*)res + alignment + sizeof(void*);
+ aligned -= ((VALUE)aligned & (alignment - 1));
+ ((void**)aligned)[-1] = res;
+ res = (void*)aligned;
+# endif
}
-#elif defined(HAVE_MEMALIGN)
- res = memalign(alignment, size);
-#else
- char* aligned;
- res = malloc(alignment + size + sizeof(void*));
- aligned = (char*)res + alignment + sizeof(void*);
- aligned -= ((VALUE)aligned & (alignment - 1));
- ((void**)aligned)[-1] = res;
- res = (void*)aligned;
#endif
/* alignment must be a power of 2 */
@@ -10375,16 +10442,26 @@ rb_aligned_malloc(size_t alignment, size_t size)
}
static void
-rb_aligned_free(void *ptr)
+rb_aligned_free(void *ptr, size_t size)
{
#if defined __MINGW32__
__mingw_aligned_free(ptr);
#elif defined _WIN32
_aligned_free(ptr);
-#elif defined(HAVE_MEMALIGN) || defined(HAVE_POSIX_MEMALIGN)
- free(ptr);
#else
- free(((void**)ptr)[-1]);
+ if (USE_MMAP_ALIGNED_ALLOC) {
+ GC_ASSERT(size % sysconf(_SC_PAGE_SIZE) == 0);
+ if (munmap(ptr, size)) {
+ rb_bug("rb_aligned_free: munmap failed");
+ }
+ }
+ else {
+# if defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_MEMALIGN)
+ free(ptr);
+# else
+ free(((void**)ptr)[-1]);
+# endif
+ }
#endif
}
diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb
index 4a8cff33f4..f5cab55ba7 100644
--- a/test/ruby/test_gc_compact.rb
+++ b/test/ruby/test_gc_compact.rb
@@ -4,12 +4,32 @@
require 'etc'
class TestGCCompact < Test::Unit::TestCase
- class AutoCompact < Test::Unit::TestCase
+ module SupportsCompact
def setup
skip "autocompact not supported on this platform" unless supports_auto_compact?
super
end
+ private
+
+ def supports_auto_compact?
+ return true unless defined?(Etc::SC_PAGE_SIZE)
+
+ begin
+ return GC::INTERNAL_CONSTANTS[:HEAP_PAGE_SIZE] % Etc.sysconf(Etc::SC_PAGE_SIZE) == 0
+ rescue NotImplementedError
+ rescue ArgumentError
+ end
+
+ true
+ end
+ end
+
+ include SupportsCompact
+
+ class AutoCompact < Test::Unit::TestCase
+ include SupportsCompact
+
def test_enable_autocompact
before = GC.auto_compact
GC.auto_compact = true
@@ -59,26 +79,17 @@ def test_implicit_compaction_does_something
ensure
GC.auto_compact = before
end
-
- private
-
- def supports_auto_compact?
- return true unless defined?(Etc::SC_PAGE_SIZE)
-
- begin
- return GC::INTERNAL_CONSTANTS[:HEAP_PAGE_SIZE] % Etc.sysconf(Etc::SC_PAGE_SIZE) == 0
- rescue NotImplementedError
- rescue ArgumentError
- end
-
- true
- end
end
def os_page_size
return true unless defined?(Etc::SC_PAGE_SIZE)
end
+ def setup
+ skip "autocompact not supported on this platform" unless supports_auto_compact?
+ super
+ end
+
def test_gc_compact_stats
list = []
--
2.30.1 (Apple Git-130)

@ -1,29 +0,0 @@
From a9977ba2f9863e3fb1b2346589ebbca67d80536c Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@ruby-lang.org>
Date: Sat, 14 Aug 2021 10:08:19 +0900
Subject: [PATCH] Constified addr2line.c
---
addr2line.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/addr2line.c b/addr2line.c
index 8ee4416650d3..fed1a8da84e5 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -1138,12 +1138,12 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
set_uint_value(v, read_uleb128(reader));
break;
case DW_FORM_ref_addr:
- if (reader->address_size == 4) {
+ if (reader->format == 4) {
set_uint_value(v, read_uint32(&reader->p));
- } else if (reader->address_size == 8) {
+ } else if (reader->format == 8) {
set_uint_value(v, read_uint64(&reader->p));
} else {
- fprintf(stderr,"unknown address_size:%d", reader->address_size);
+ fprintf(stderr,"unknown format:%d", reader->format);
abort();
}
break;

@ -1,29 +0,0 @@
From b4b5eab2a5fd0e9ac62c01102dd26d0a433c5683 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Mon, 18 May 2020 02:17:28 +0900
Subject: [PATCH] test/openssl/test_digest: do not test constants for legacy
algorithms
Remove availability test for MD4 and RIPEMD160 as they are considered
legacy and may be missing depending on the compile-time options of
OpenSSL. OpenSSL 3.0 by default disables them.
---
test/openssl/test_digest.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/openssl/test_digest.rb b/test/openssl/test_digest.rb
index 8d7046e831..84c128c12f 100644
--- a/test/openssl/test_digest.rb
+++ b/test/openssl/test_digest.rb
@@ -54,7 +54,7 @@ def test_reset
end
def test_digest_constants
- %w{MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512}.each do |name|
+ %w{MD5 SHA1 SHA224 SHA256 SHA384 SHA512}.each do |name|
assert_not_nil(OpenSSL::Digest.new(name))
klass = OpenSSL::Digest.const_get(name.tr('-', '_'))
assert_not_nil(klass.new)
--
2.32.0

@ -1,439 +0,0 @@
From 9596788bdd2d061bef042485af14262e9fc4020c Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Thu, 13 Aug 2020 23:20:55 +0900
Subject: [PATCH] test/openssl/test_pkcs12: fix test failures with OpenSSL 3.0
OpenSSL's PKCS12_create() by default uses pbewithSHAAnd40BitRC2-CBC for
encryption of the certificates. However, in OpenSSL 3.0, the algorithm
is part of the legacy provider and is not enabled by default.
Specify another algorithm that is still in the default provider for
these test cases.
---
test/openssl/test_pkcs12.rb | 297 ++++++++++++++++++------------------
1 file changed, 149 insertions(+), 148 deletions(-)
diff --git a/test/openssl/test_pkcs12.rb b/test/openssl/test_pkcs12.rb
index fdbe753b17..ec676743bc 100644
--- a/test/openssl/test_pkcs12.rb
+++ b/test/openssl/test_pkcs12.rb
@@ -5,6 +5,9 @@
module OpenSSL
class TestPKCS12 < OpenSSL::TestCase
+ DEFAULT_PBE_PKEYS = "PBE-SHA1-3DES"
+ DEFAULT_PBE_CERTS = "PBE-SHA1-3DES"
+
def setup
super
ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA")
@@ -14,47 +17,41 @@ def setup
["subjectKeyIdentifier","hash",false],
["authorityKeyIdentifier","keyid:always",false],
]
- @cacert = issue_cert(ca, Fixtures.pkey("rsa2048"), 1, ca_exts, nil, nil)
+ ca_key = Fixtures.pkey("rsa-1")
+ @cacert = issue_cert(ca, ca_key, 1, ca_exts, nil, nil)
inter_ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Intermediate CA")
- inter_ca_key = OpenSSL::PKey.read <<-_EOS_
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQDp7hIG0SFMG/VWv1dBUWziAPrNmkMXJgTCAoB7jffzRtyyN04K
-oq/89HAszTMStZoMigQURfokzKsjpUp8OYCAEsBtt9d5zPndWMz/gHN73GrXk3LT
-ZsxEn7Xv5Da+Y9F/Hx2QZUHarV5cdZixq2NbzWGwrToogOQMh2pxN3Z/0wIDAQAB
-AoGBAJysUyx3olpsGzv3OMRJeahASbmsSKTXVLZvoIefxOINosBFpCIhZccAG6UV
-5c/xCvS89xBw8aD15uUfziw3AuT8QPEtHCgfSjeT7aWzBfYswEgOW4XPuWr7EeI9
-iNHGD6z+hCN/IQr7FiEBgTp6A+i/hffcSdR83fHWKyb4M7TRAkEA+y4BNd668HmC
-G5MPRx25n6LixuBxrNp1umfjEI6UZgEFVpYOg4agNuimN6NqM253kcTR94QNTUs5
-Kj3EhG1YWwJBAO5rUjiOyCNVX2WUQrOMYK/c1lU7fvrkdygXkvIGkhsPoNRzLPeA
-HGJszKtrKD8bNihWpWNIyqKRHfKVD7yXT+kCQGCAhVCIGTRoypcDghwljHqLnysf
-ci0h5ZdPcIqc7ODfxYhFsJ/Rql5ONgYsT5Ig/+lOQAkjf+TRYM4c2xKx2/8CQBvG
-jv6dy70qDgIUgqzONtlmHeYyFzn9cdBO5sShdVYHvRHjFSMEXsosqK9zvW2UqvuK
-FJx7d3f29gkzynCLJDkCQGQZlEZJC4vWmWJGRKJ24P6MyQn3VsPfErSKOg4lvyM3
-Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es=
------END RSA PRIVATE KEY-----
- _EOS_
- @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, Fixtures.pkey("rsa2048"))
+ inter_ca_key = Fixtures.pkey("rsa-2")
+ @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, ca_key)
exts = [
["keyUsage","digitalSignature",true],
["subjectKeyIdentifier","hash",false],
]
ee = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Ruby PKCS12 Test Certificate")
- @mykey = Fixtures.pkey("rsa1024")
+ @mykey = Fixtures.pkey("rsa-3")
@mycert = issue_cert(ee, @mykey, 3, exts, @inter_cacert, inter_ca_key)
end
- def test_create
+ def test_create_single_key_single_cert
pkcs12 = OpenSSL::PKCS12.create(
"omg",
"hello",
@mykey,
- @mycert
+ @mycert,
+ nil,
+ DEFAULT_PBE_PKEYS,
+ DEFAULT_PBE_CERTS,
)
- assert_equal @mycert.to_der, pkcs12.certificate.to_der
+ assert_equal @mycert, pkcs12.certificate
assert_equal @mykey.to_der, pkcs12.key.to_der
assert_nil pkcs12.ca_certs
+
+ der = pkcs12.to_der
+ decoded = OpenSSL::PKCS12.new(der, "omg")
+ assert_equal @mykey.to_der, decoded.key.to_der
+ assert_equal @mycert, decoded.certificate
+ assert_equal [], Array(decoded.ca_certs)
end
def test_create_no_pass
@@ -62,14 +59,17 @@ def test_create_no_pass
nil,
"hello",
@mykey,
- @mycert
+ @mycert,
+ nil,
+ DEFAULT_PBE_PKEYS,
+ DEFAULT_PBE_CERTS,
)
- assert_equal @mycert.to_der, pkcs12.certificate.to_der
+ assert_equal @mycert, pkcs12.certificate
assert_equal @mykey.to_der, pkcs12.key.to_der
assert_nil pkcs12.ca_certs
decoded = OpenSSL::PKCS12.new(pkcs12.to_der)
- assert_cert @mycert, decoded.certificate
+ assert_equal @mycert, decoded.certificate
end
def test_create_with_chain
@@ -80,7 +80,9 @@ def test_create_with_chain
"hello",
@mykey,
@mycert,
- chain
+ chain,
+ DEFAULT_PBE_PKEYS,
+ DEFAULT_PBE_CERTS,
)
assert_equal chain, pkcs12.ca_certs
end
@@ -95,14 +97,16 @@ def test_create_with_chain_decode
"hello",
@mykey,
@mycert,
- chain
+ chain,
+ DEFAULT_PBE_PKEYS,
+ DEFAULT_PBE_CERTS,
)
decoded = OpenSSL::PKCS12.new(pkcs12.to_der, passwd)
assert_equal chain.size, decoded.ca_certs.size
- assert_include_cert @cacert, decoded.ca_certs
- assert_include_cert @inter_cacert, decoded.ca_certs
- assert_cert @mycert, decoded.certificate
+ assert_include decoded.ca_certs, @cacert
+ assert_include decoded.ca_certs, @inter_cacert
+ assert_equal @mycert, decoded.certificate
assert_equal @mykey.to_der, decoded.key.to_der
end
@@ -126,8 +130,8 @@ def test_create_with_itr
@mykey,
@mycert,
[],
- nil,
- nil,
+ DEFAULT_PBE_PKEYS,
+ DEFAULT_PBE_CERTS,
2048
)
@@ -138,8 +142,8 @@ def test_create_with_itr
@mykey,
@mycert,
[],
- nil,
- nil,
+ DEFAULT_PBE_PKEYS,
+ DEFAULT_PBE_CERTS,
"omg"
)
end
@@ -152,7 +156,8 @@ def test_create_with_mac_itr
@mykey,
@mycert,
[],
- nil,
+ DEFAULT_PBE_PKEYS,
+ DEFAULT_PBE_CERTS,
nil,
nil,
2048
@@ -165,148 +170,144 @@ def test_create_with_mac_itr
@mykey,
@mycert,
[],
- nil,
- nil,
+ DEFAULT_PBE_PKEYS,
+ DEFAULT_PBE_CERTS,
nil,
"omg"
)
end
end
- def test_new_with_one_key_and_one_cert
- # generated with:
- # openssl version #=> OpenSSL 1.0.2h 3 May 2016
- # openssl pkcs12 -in <@mycert> -inkey <RSA1024> -export -out <out>
- str = <<~EOF.unpack("m").first
-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
-vyl2WuMdEwQIMWFFphPkIUICAggA
- EOF
- p12 = OpenSSL::PKCS12.new(str, "abc123")
-
- assert_equal @mykey.to_der, p12.key.to_der
- assert_equal @mycert.subject.to_der, p12.certificate.subject.to_der
- assert_equal [], Array(p12.ca_certs)
- end
-
def test_new_with_no_keys
# generated with:
- # openssl pkcs12 -in <@mycert> -nokeys -export -out <out>
+ # openssl pkcs12 -certpbe PBE-SHA1-3DES -in <@mycert> -nokeys -export
str = <<~EOF.unpack("m").first
-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
+MIIGJAIBAzCCBeoGCSqGSIb3DQEHAaCCBdsEggXXMIIF0zCCBc8GCSqGSIb3
+DQEHBqCCBcAwggW8AgEAMIIFtQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQMw
+DgQIjv5c3OHvnBgCAggAgIIFiMJa8Z/w7errRvCQPXh9dGQz3eJaFq3S2gXD
+rh6oiwsgIRJZvYAWgU6ll9NV7N5SgvS2DDNVuc3tsP8TPWjp+bIxzS9qmGUV
+kYWuURWLMKhpF12ZRDab8jcIwBgKoSGiDJk8xHjx6L613/XcRM6ln3VeQK+C
+hlW5kXniNAUAgTft25Fn61Xa8xnhmsz/fk1ycGnyGjKCnr7Mgy7KV0C1vs23
+18n8+b1ktDWLZPYgpmXuMFVh0o+HJTV3O86mkIhJonMcnOMgKZ+i8KeXaocN
+JQlAPBG4+HOip7FbQT/h6reXv8/J+hgjLfqAb5aV3m03rUX9mXx66nR1tQU0
+Jq+XPfDh5+V4akIczLlMyyo/xZjI1/qupcMjr+giOGnGd8BA3cuXW+ueLQiA
+PpTp+DQLVHRfz9XTZbyqOReNEtEXvO9gOlKSEY5lp65ItXVEs2Oqyf9PfU9y
+DUltN6fCMilwPyyrsIBKXCu2ZLM5h65KVCXAYEX9lNqj9zrQ7vTqvCNN8RhS
+ScYouTX2Eqa4Z+gTZWLHa8RCQFoyP6hd+97/Tg2Gv2UTH0myQxIVcnpdi1wy
+cqb+er7tyKbcO96uSlUjpj/JvjlodtjJcX+oinEqGb/caj4UepbBwiG3vv70
+63bS3jTsOLNjDRsR9if3LxIhLa6DW8zOJiGC+EvMD1o4dzHcGVpQ/pZWCHZC
++YiNJpQOBApiZluE+UZ0m3XrtHFQYk7xblTrh+FJF91wBsok0rZXLAKd8m4p
+OJsc7quCq3cuHRRTzJQ4nSe01uqbwGDAYwLvi6VWy3svU5qa05eDRmgzEFTG
+e84Gp/1LQCtpQFr4txkjFchO2whWS80KoQKqmLPyGm1D9Lv53Q4ZsKMgNihs
+rEepuaOZMKHl4yMAYFoOXZCAYzfbhN6b2phcFAHjMUHUw9e3F0QuDk9D0tsr
+riYTrkocqlOKfK4QTomx27O0ON2J6f1rtEojGgfl9RNykN7iKGzjS3914QjW
+W6gGiZejxHsDPEAa4gUp0WiSUSXtD5WJgoyAzLydR2dKWsQ4WlaUXi01CuGy
++xvncSn2nO3bbot8VD5H6XU1CjREVtnIfbeRYO/uofyLUP3olK5RqN6ne6Xo
+eXnJ/bjYphA8NGuuuvuW1SCITmINkZDLC9cGlER9+K65RR/DR3TigkexXMeN
+aJ70ivZYAl0OuhZt3TGIlAzS64TIoyORe3z7Ta1Pp9PZQarYJpF9BBIZIFor
+757PHHuQKRuugiRkp8B7v4eq1BQ+VeAxCKpyZ7XrgEtbY/AWDiaKcGPKPjc3
+AqQraVeQm7kMBT163wFmZArCphzkDOI3bz2oEO8YArMgLq2Vto9jAZlqKyWr
+pi2bSJxuoP1aoD58CHcWMrf8/j1LVdQhKgHQXSik2ID0H2Wc/XnglhzlVFuJ
+JsNIW/EGJlZh/5WDez9U0bXqnBlu3uasPEOezdoKlcCmQlmTO5+uLHYLEtNA
+EH9MtnGZebi9XS5meTuS6z5LILt8O9IHZxmT3JRPHYj287FEzotlLdcJ4Ee5
+enW41UHjLrfv4OaITO1hVuoLRGdzjESx/fHMWmxroZ1nVClxECOdT42zvIYJ
+J3xBZ0gppzQ5fjoYiKjJpxTflRxUuxshk3ih6VUoKtqj/W18tBQ3g5SOlkgT
+yCW8r74yZlfYmNrPyDMUQYpLUPWj2n71GF0KyPfTU5yOatRgvheh262w5BG3
+omFY7mb3tCv8/U2jdMIoukRKacpZiagofz3SxojOJq52cHnCri+gTHBMX0cO
+j58ygfntHWRzst0pV7Ze2X3fdCAJ4DokH6bNJNthcgmolFJ/y3V1tJjgsdtQ
+7Pjn/vE6xUV0HXE2x4yoVYNirbAMIvkN/X+atxrN0dA4AchN+zGp8TAxMCEw
+CQYFKw4DAhoFAAQUQ+6XXkyhf6uYgtbibILN2IjKnOAECLiqoY45MPCrAgII
+AA==
EOF
p12 = OpenSSL::PKCS12.new(str, "abc123")
assert_equal nil, p12.key
assert_equal nil, p12.certificate
assert_equal 1, p12.ca_certs.size
- assert_equal @mycert.subject.to_der, p12.ca_certs[0].subject.to_der
+ assert_equal @mycert.subject, p12.ca_certs[0].subject
end
def test_new_with_no_certs
# generated with:
- # openssl pkcs12 -inkey <RSA1024> -nocerts -export -out <out>
+ # openssl pkcs12 -inkey fixtures/openssl/pkey/rsa-1.pem -nocerts -export
str = <<~EOF.unpack("m").first
-MIIDJwIBAzCCAu0GCSqGSIb3DQEHAaCCAt4EggLaMIIC1jCCAtIGCSqGSIb3DQEH
-AaCCAsMEggK/MIICuzCCArcGCyqGSIb3DQEMCgECoIICpjCCAqIwHAYKKoZIhvcN
-AQwBAzAOBAg6AaYnJs84SwICCAAEggKAQzZH+fWSpcQYD1J7PsGSune85A++fLCQ
-V7tacp2iv95GJkxwYmfTP176pJdgs00mceB9UJ/u9EX5nD0djdjjQjwo6sgKjY0q
-cpVhZw8CMxw7kBD2dhtui0zT8z5hy03LePxsjEKsGiSbeVeeGbSfw/I6AAYbv+Uh
-O/YPBGumeHj/D2WKnfsHJLQ9GAV3H6dv5VKYNxjciK7f/JEyZCuUQGIN64QFHDhJ
-7fzLqd/ul3FZzJZO6a+dwvcgux09SKVXDRSeFmRCEX4b486iWhJJVspCo9P2KNne
-ORrpybr3ZSwxyoICmjyo8gj0OSnEfdx9790Ej1takPqSA1wIdSdBLekbZqB0RBQg
-DEuPOsXNo3QFi8ji1vu0WBRJZZSNC2hr5NL6lNR+DKxG8yzDll2j4W4BBIp22mAE
-7QRX7kVxu17QJXQhOUac4Dd1qXmzebP8t6xkAxD9L7BWEN5OdiXWwSWGjVjMBneX
-nYObi/3UT/aVc5WHMHK2BhCI1bwH51E6yZh06d5m0TQpYGUTWDJdWGBSrp3A+8jN
-N2PMQkWBFrXP3smHoTEN4oZC4FWiPsIEyAkQsfKRhcV9lGKl2Xgq54ROTFLnwKoj
-Z3zJScnq9qmNzvVZSMmDLkjLyDq0pxRxGKBvgouKkWY7VFFIwwBIJM39iDJ5NbBY
-i1AQFTRsRSsZrNVPasCXrIq7bhMoJZb/YZOGBLNyJVqKUoYXhtwsajzSq54VlWft
-JxsPayEd4Vi6O9EU1ahnj6qFEZiKFzsicgK2J1Rb8cYagrp0XWjHW0SBn5GVUWCg
-GUokSFG/0JTdeYTo/sQuG4qNgJkOolRjpeI48Fciq5VUWLvVdKioXzAxMCEwCQYF
-Kw4DAhoFAAQUYAuwVtGD1TdgbFK4Yal2XBgwUR4ECEawsN3rNaa6AgIIAA==
+MIIJ7wIBAzCCCbUGCSqGSIb3DQEHAaCCCaYEggmiMIIJnjCCCZoGCSqGSIb3
+DQEHAaCCCYsEggmHMIIJgzCCCX8GCyqGSIb3DQEMCgECoIIJbjCCCWowHAYK
+KoZIhvcNAQwBAzAOBAjX5nN8jyRKwQICCAAEgglIBIRLHfiY1mNHpl3FdX6+
+72L+ZOVXnlZ1MY9HSeg0RMkCJcm0mJ2UD7INUOGXvwpK9fr6WJUZM1IqTihQ
+1dM0crRC2m23aP7KtAlXh2DYD3otseDtwoN/NE19RsiJzeIiy5TSW1d47weU
++D4Ig/9FYVFPTDgMzdCxXujhvO/MTbZIjqtcS+IOyF+91KkXrHkfkGjZC7KS
+WRmYw9BBuIPQEewdTI35sAJcxT8rK7JIiL/9mewbSE+Z28Wq1WXwmjL3oZm9
+lw6+f515b197GYEGomr6LQqJJamSYpwQbTGHonku6Tf3ylB4NLFqOnRCKE4K
+zRSSYIqJBlKHmQ4pDm5awoupHYxMZLZKZvXNYyYN3kV8r1iiNVlY7KBR4CsX
+rqUkXehRmcPnuqEMW8aOpuYe/HWf8PYI93oiDZjcEZMwW2IZFFrgBbqUeNCM
+CQTkjAYxi5FyoaoTnHrj/aRtdLOg1xIJe4KKcmOXAVMmVM9QEPNfUwiXJrE7
+n42gl4NyzcZpxqwWBT++9TnQGZ/lEpwR6dzkZwICNQLdQ+elsdT7mumywP+1
+WaFqg9kpurimaiBu515vJNp9Iqv1Nmke6R8Lk6WVRKPg4Akw0fkuy6HS+LyN
+ofdCfVUkPGN6zkjAxGZP9ZBwvXUbLRC5W3N5qZuAy5WcsS75z+oVeX9ePV63
+cue23sClu8JSJcw3HFgPaAE4sfkQ4MoihPY5kezgT7F7Lw/j86S0ebrDNp4N
+Y685ec81NRHJ80CAM55f3kGCOEhoifD4VZrvr1TdHZY9Gm3b1RYaJCit2huF
+nlOfzeimdcv/tkjb6UsbpXx3JKkF2NFFip0yEBERRCdWRYMUpBRcl3ad6XHy
+w0pVTgIjTxGlbbtOCi3siqMOK0GNt6UgjoEFc1xqjsgLwU0Ta2quRu7RFPGM
+GoEwoC6VH23p9Hr4uTFOL0uHfkKWKunNN+7YPi6LT6IKmTQwrp+fTO61N6Xh
+KlqTpwESKsIJB2iMnc8wBkjXJtmG/e2n5oTqfhICIrxYmEb7zKDyK3eqeTj3
+FhQh2t7cUIiqcT52AckUqniPmlE6hf82yBjhaQUPfi/ExTBtTDSmFfRPUzq+
+Rlla4OHllPRzUXJExyansgCxZbPqlw46AtygSWRGcWoYAKUKwwoYjerqIV5g
+JoZICV9BOU9TXco1dHXZQTs/nnTwoRmYiL/Ly5XpvUAnQOhYeCPjBeFnPSBR
+R/hRNqrDH2MOV57v5KQIH2+mvy26tRG+tVGHmLMaOJeQkjLdxx+az8RfXIrH
+7hpAsoBb+g9jUDY1mUVavPk1T45GMpQH8u3kkzRvChfOst6533GyIZhE7FhN
+KanC6ACabVFDUs6P9pK9RPQMp1qJfpA0XJFx5TCbVbPkvnkZd8K5Tl/tzNM1
+n32eRao4MKr9KDwoDL93S1yJgYTlYjy1XW/ewdedtX+B4koAoz/wSXDYO+GQ
+Zu6ZSpKSEHTRPhchsJ4oICvpriVaJkn0/Z7H3YjNMB9U5RR9+GiIg1wY1Oa1
+S3WfuwrrI6eqfbQwj6PDNu3IKy6srEgvJwaofQALNBPSYWbauM2brc8qsD+t
+n8jC/aD1aMcy00+9t3H/RVCjEOb3yKfUpAldIkEA2NTTnZpoDQDXeNYU2F/W
+yhmFjJy8A0O4QOk2xnZK9kcxSRs0v8vI8HivvgWENoVPscsDC4742SSIe6SL
+f/T08reIX11f0K70rMtLhtFMQdHdYOTNl6JzhkHPLr/f9MEZsBEQx52depnF
+ARb3gXGbCt7BAi0OeCEBSbLr2yWuW4r55N0wRZSOBtgqgjsiHP7CDQSkbL6p
+FPlQS1do9gBSHiNYvsmN1LN5bG+mhcVb0UjZub4mL0EqGadjDfDdRJmWqlX0
+r5dyMcOWQVy4O2cPqYFlcP9lk8buc5otcyVI2isrAFdlvBK29oK6jc52Aq5Q
+0b2ESDlgX8WRgiOPPxK8dySKEeuIwngCtJyNTecP9Ug06TDsu0znZGCXJ+3P
+8JOpykgA8EQdOZOYHbo76ZfB2SkklI5KeRA5IBjGs9G3TZ4PHLy2DIwsbWzS
+H1g01o1x264nx1cJ+eEgUN/KIiGFIib42RS8Af4D5e+Vj54Rt3axq+ag3kI+
+53p8uotyu+SpvvXUP7Kv4xpQ/L6k41VM0rfrd9+DrlDVvSfxP2uh6I1TKF7A
+CT5n8zguMbng4PGjxvyPBM5k62t6hN5fuw6Af0aZFexh+IjB/5wFQ6onSz23
+fBzMW4St7RgSs8fDg3lrM+5rwXiey1jxY1ddaxOoUsWRMvvdd7rZxRZQoN5v
+AcI5iMkK/vvpQgC/sfzhtXtrJ2XOPZ+GVgi7VcuDLKSkdFMcPbGzO8SdxUnS
+SLV5XTKqKND+Lrfx7DAoKi5wbDFHu5496/MHK5qP4tBe6sJ5bZc+KDJIH46e
+wTV1oWtB5tV4q46hOb5WRcn/Wjz3HSKaGZgx5QbK1MfKTzD5CTUn+ArMockX
+2wJhPnFK85U4rgv8iBuh9bRjyw+YaKf7Z3loXRiE1eRG6RzuPF0ZecFiDumk
+AC/VUXynJhzePBLqzrQj0exanACdullN+pSfHiRWBxR2VFUkjoFP5X45GK3z
+OstSH6FOkMVU4afqEmjsIwozDFIyin5EyWTtdhJe3szdJSGY23Tut+9hUatx
+9FDFLESOd8z3tyQSNiLk/Hib+e/lbjxqbXBG/p/oyvP3N999PLUPtpKqtYkV
+H0+18sNh9CVfojiJl44fzxe8yCnuefBjut2PxEN0EFRBPv9P2wWlmOxkPKUq
+NrCJP0rDj5aONLrNZPrR8bZNdIShkZ/rKkoTuA0WMZ+xUlDRxAupdMkWAlrz
+8IcwNcdDjPnkGObpN5Ctm3vK7UGSBmPeNqkXOYf3QTJ9gStJEd0F6+DzTN5C
+KGt1IyuGwZqL2Yk51FDIIkr9ykEnBMaA39LS7GFHEDNGlW+fKC7AzA0zfoOr
+fXZlHMBuqHtXqk3zrsHRqGGoocigg4ctrhD1UREYKj+eIj1TBiRdf7c6+COf
+NIOmej8pX3FmZ4ui+dDA8r2ctgsWHrb4A6iiH+v1DRA61GtoaA/tNRggewXW
+VXCZCGWyyTuyHGOqq5ozrv5MlzZLWD/KV/uDsAWmy20RAed1C4AzcXlpX25O
+M4SNl47g5VRNJRtMqokc8j6TjZrzMDEwITAJBgUrDgMCGgUABBRrkIRuS5qg
+BC8fv38mue8LZVcbHQQIUNrWKEnskCoCAggA
EOF
p12 = OpenSSL::PKCS12.new(str, "abc123")
- assert_equal @mykey.to_der, p12.key.to_der
+ assert_equal Fixtures.pkey("rsa-1").to_der, p12.key.to_der
assert_equal nil, p12.certificate
assert_equal [], Array(p12.ca_certs)
end
def test_dup
- p12 = OpenSSL::PKCS12.create("pass", "name", @mykey, @mycert)
+ p12 = OpenSSL::PKCS12.create(
+ "pass",
+ "name",
+ @mykey,
+ @mycert,
+ nil,
+ DEFAULT_PBE_PKEYS,
+ DEFAULT_PBE_CERTS,
+ )
assert_equal p12.to_der, p12.dup.to_der
end
-
- private
- def assert_cert expected, actual
- [
- :subject,
- :issuer,
- :serial,
- :not_before,
- :not_after,
- ].each do |attribute|
- assert_equal expected.send(attribute), actual.send(attribute)
- end
- assert_equal expected.to_der, actual.to_der
- end
-
- def assert_include_cert cert, ary
- der = cert.to_der
- ary.each do |candidate|
- if candidate.to_der == der
- return true
- end
- end
- false
- end
end
end
--
2.32.0

@ -1,67 +0,0 @@
From 10d2216b2f35a31777a099d9f765b0b6ea34a63e Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Mon, 18 May 2020 02:35:35 +0900
Subject: [PATCH] test/openssl/test_pkey: use EC keys for
PKey.generate_parameters tests
OpenSSL 3.0 refuses to generate DSA parameters shorter than 2048 bits,
but generating 2048 bits parameters takes very long time. Let's use EC
in these test cases instead.
---
test/openssl/test_pkey.rb | 27 +++++++++++----------------
1 file changed, 11 insertions(+), 16 deletions(-)
diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb
index 3630458b3c..88a6e04581 100644
--- a/test/openssl/test_pkey.rb
+++ b/test/openssl/test_pkey.rb
@@ -27,20 +27,16 @@ def test_generic_oid_inspect
end
def test_s_generate_parameters
- # 512 is non-default; 1024 is used if 'dsa_paramgen_bits' is not specified
- # with OpenSSL 1.1.0.
- pkey = OpenSSL::PKey.generate_parameters("DSA", {
- "dsa_paramgen_bits" => 512,
- "dsa_paramgen_q_bits" => 256,
+ pkey = OpenSSL::PKey.generate_parameters("EC", {
+ "ec_paramgen_curve" => "secp384r1",
})
- assert_instance_of OpenSSL::PKey::DSA, pkey
- assert_equal 512, pkey.p.num_bits
- assert_equal 256, pkey.q.num_bits
- assert_equal nil, pkey.priv_key
+ assert_instance_of OpenSSL::PKey::EC, pkey
+ assert_equal "secp384r1", pkey.group.curve_name
+ assert_equal nil, pkey.private_key
# Invalid options are checked
assert_raise(OpenSSL::PKey::PKeyError) {
- OpenSSL::PKey.generate_parameters("DSA", "invalid" => "option")
+ OpenSSL::PKey.generate_parameters("EC", "invalid" => "option")
}
# Parameter generation callback is called
@@ -59,14 +55,13 @@ def test_s_generate_key
# DSA key pair cannot be generated without parameters
OpenSSL::PKey.generate_key("DSA")
}
- pkey_params = OpenSSL::PKey.generate_parameters("DSA", {
- "dsa_paramgen_bits" => 512,
- "dsa_paramgen_q_bits" => 256,
+ pkey_params = OpenSSL::PKey.generate_parameters("EC", {
+ "ec_paramgen_curve" => "secp384r1",
})
pkey = OpenSSL::PKey.generate_key(pkey_params)
- assert_instance_of OpenSSL::PKey::DSA, pkey
- assert_equal 512, pkey.p.num_bits
- assert_not_equal nil, pkey.priv_key
+ assert_instance_of OpenSSL::PKey::EC, pkey
+ assert_equal "secp384r1", pkey.group.curve_name
+ assert_not_equal nil, pkey.private_key
end
def test_hmac_sign_verify
--
2.32.0

@ -1,31 +0,0 @@
From 05fd14aea7eff2a6911a6f529f1237276482c6e7 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Fri, 10 Jul 2020 13:56:38 +0900
Subject: [PATCH] test/openssl/test_ssl: relax regex to match OpenSSL's error
message
OpenSSL 3.0 slightly changed the error message for a certificate
verification failure when an untrusted self-signed certificate is found
in the chain.
---
test/openssl/test_ssl.rb | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index 6095d545b5..9e9b8b9b69 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -964,7 +964,9 @@ def test_connect_certificate_verify_failed_exception_message
start_server(ignore_listener_error: true) { |port|
ctx = OpenSSL::SSL::SSLContext.new
ctx.set_params
- assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed/) {
+ # OpenSSL <= 1.1.0: "self signed certificate in certificate chain"
+ # OpenSSL >= 3.0.0: "self-signed certificate in certificate chain"
+ assert_raise_with_message(OpenSSL::SSL::SSLError, /self.signed/) {
server_connect(port, ctx)
}
}
--
2.32.0

@ -1,265 +0,0 @@
From 2c6797bc97d7c92284dc3c0ed27f97ace4e5cfb9 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Mon, 31 May 2021 11:44:05 +0900
Subject: [PATCH] test/openssl/utils: remove dup_public helper method
It uses deprecated PKey::{RSA,DSA,DH}#set_* methods, which will not
work with OpenSSL 3.0. The same can easily be achieved using
PKey#public_to_der regardless of the key kind.
---
test/openssl/test_pkey_dh.rb | 8 +++++---
test/openssl/test_pkey_dsa.rb | 15 +++++++++++----
test/openssl/test_pkey_ec.rb | 15 +++++++++++----
test/openssl/test_pkey_rsa.rb | 31 +++++++++++++++++--------------
test/openssl/utils.rb | 26 --------------------------
5 files changed, 44 insertions(+), 51 deletions(-)
diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb
index f80af8f841..757704caf6 100644
--- a/test/openssl/test_pkey_dh.rb
+++ b/test/openssl/test_pkey_dh.rb
@@ -40,12 +40,14 @@ def test_derive_key
def test_DHparams
dh1024 = Fixtures.pkey("dh1024")
+ dh1024params = dh1024.public_key
+
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Integer(dh1024.p),
OpenSSL::ASN1::Integer(dh1024.g)
])
key = OpenSSL::PKey::DH.new(asn1.to_der)
- assert_same_dh dup_public(dh1024), key
+ assert_same_dh dh1024params, key
pem = <<~EOF
-----BEGIN DH PARAMETERS-----
@@ -55,9 +57,9 @@ def test_DHparams
-----END DH PARAMETERS-----
EOF
key = OpenSSL::PKey::DH.new(pem)
- assert_same_dh dup_public(dh1024), key
+ assert_same_dh dh1024params, key
key = OpenSSL::PKey.read(pem)
- assert_same_dh dup_public(dh1024), key
+ assert_same_dh dh1024params, key
assert_equal asn1.to_der, dh1024.to_der
assert_equal pem, dh1024.export
diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb
index 147e50176b..0994607f21 100644
--- a/test/openssl/test_pkey_dsa.rb
+++ b/test/openssl/test_pkey_dsa.rb
@@ -138,6 +138,8 @@ def test_DSAPrivateKey_encrypted
def test_PUBKEY
dsa512 = Fixtures.pkey("dsa512")
+ dsa512pub = OpenSSL::PKey::DSA.new(dsa512.public_to_der)
+
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::ObjectId("DSA"),
@@ -153,7 +155,7 @@ def test_PUBKEY
])
key = OpenSSL::PKey::DSA.new(asn1.to_der)
assert_not_predicate key, :private?
- assert_same_dsa dup_public(dsa512), key
+ assert_same_dsa dsa512pub, key
pem = <<~EOF
-----BEGIN PUBLIC KEY-----
@@ -166,10 +168,15 @@ def test_PUBKEY
-----END PUBLIC KEY-----
EOF
key = OpenSSL::PKey::DSA.new(pem)
- assert_same_dsa dup_public(dsa512), key
+ assert_same_dsa dsa512pub, key
+
+ assert_equal asn1.to_der, key.to_der
+ assert_equal pem, key.export
- assert_equal asn1.to_der, dup_public(dsa512).to_der
- assert_equal pem, dup_public(dsa512).export
+ assert_equal asn1.to_der, dsa512.public_to_der
+ assert_equal asn1.to_der, key.public_to_der
+ assert_equal pem, dsa512.public_to_pem
+ assert_equal pem, key.public_to_pem
end
def test_read_DSAPublicKey_pem
diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb
index 4b6df0290f..d62f1b5eb8 100644
--- a/test/openssl/test_pkey_ec.rb
+++ b/test/openssl/test_pkey_ec.rb
@@ -210,6 +210,8 @@ def test_ECPrivateKey_encrypted
def test_PUBKEY
p256 = Fixtures.pkey("p256")
+ p256pub = OpenSSL::PKey::EC.new(p256.public_to_der)
+
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::ObjectId("id-ecPublicKey"),
@@ -221,7 +223,7 @@ def test_PUBKEY
])
key = OpenSSL::PKey::EC.new(asn1.to_der)
assert_not_predicate key, :private?
- assert_same_ec dup_public(p256), key
+ assert_same_ec p256pub, key
pem = <<~EOF
-----BEGIN PUBLIC KEY-----
@@ -230,10 +232,15 @@ def test_PUBKEY
-----END PUBLIC KEY-----
EOF
key = OpenSSL::PKey::EC.new(pem)
- assert_same_ec dup_public(p256), key
+ assert_same_ec p256pub, key
+
+ assert_equal asn1.to_der, key.to_der
+ assert_equal pem, key.export
- assert_equal asn1.to_der, dup_public(p256).to_der
- assert_equal pem, dup_public(p256).export
+ assert_equal asn1.to_der, p256.public_to_der
+ assert_equal asn1.to_der, key.public_to_der
+ assert_equal pem, p256.public_to_pem
+ assert_equal pem, key.public_to_pem
end
def test_ec_group
diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb
index 5e127f5407..4548bdb2cf 100644
--- a/test/openssl/test_pkey_rsa.rb
+++ b/test/openssl/test_pkey_rsa.rb
@@ -201,7 +201,7 @@ def test_sign_verify_pss
def test_encrypt_decrypt
rsapriv = Fixtures.pkey("rsa-1")
- rsapub = dup_public(rsapriv)
+ rsapub = OpenSSL::PKey.read(rsapriv.public_to_der)
# Defaults to PKCS #1 v1.5
raw = "data"
@@ -216,7 +216,7 @@ def test_encrypt_decrypt
def test_encrypt_decrypt_legacy
rsapriv = Fixtures.pkey("rsa-1")
- rsapub = dup_public(rsapriv)
+ rsapub = OpenSSL::PKey.read(rsapriv.public_to_der)
# Defaults to PKCS #1 v1.5
raw = "data"
@@ -346,13 +346,15 @@ def test_RSAPrivateKey_encrypted
def test_RSAPublicKey
rsa1024 = Fixtures.pkey("rsa1024")
+ rsa1024pub = OpenSSL::PKey::RSA.new(rsa1024.public_to_der)
+
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Integer(rsa1024.n),
OpenSSL::ASN1::Integer(rsa1024.e)
])
key = OpenSSL::PKey::RSA.new(asn1.to_der)
assert_not_predicate key, :private?
- assert_same_rsa dup_public(rsa1024), key
+ assert_same_rsa rsa1024pub, key
pem = <<~EOF
-----BEGIN RSA PUBLIC KEY-----
@@ -362,11 +364,13 @@ def test_RSAPublicKey
-----END RSA PUBLIC KEY-----
EOF
key = OpenSSL::PKey::RSA.new(pem)
- assert_same_rsa dup_public(rsa1024), key
+ assert_same_rsa rsa1024pub, key
end
def test_PUBKEY
rsa1024 = Fixtures.pkey("rsa1024")
+ rsa1024pub = OpenSSL::PKey::RSA.new(rsa1024.public_to_der)
+
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::ObjectId("rsaEncryption"),
@@ -381,7 +385,7 @@ def test_PUBKEY
])
key = OpenSSL::PKey::RSA.new(asn1.to_der)
assert_not_predicate key, :private?
- assert_same_rsa dup_public(rsa1024), key
+ assert_same_rsa rsa1024pub, key
pem = <<~EOF
-----BEGIN PUBLIC KEY-----
@@ -392,10 +396,15 @@ def test_PUBKEY
-----END PUBLIC KEY-----
EOF
key = OpenSSL::PKey::RSA.new(pem)
- assert_same_rsa dup_public(rsa1024), key
+ assert_same_rsa rsa1024pub, key
+
+ assert_equal asn1.to_der, key.to_der
+ assert_equal pem, key.export
- assert_equal asn1.to_der, dup_public(rsa1024).to_der
- assert_equal pem, dup_public(rsa1024).export
+ assert_equal asn1.to_der, rsa1024.public_to_der
+ assert_equal asn1.to_der, key.public_to_der
+ assert_equal pem, rsa1024.public_to_pem
+ assert_equal pem, key.public_to_pem
end
def test_pem_passwd
@@ -482,12 +491,6 @@ def test_private_encoding_encrypted
assert_same_rsa rsa1024, OpenSSL::PKey.read(pem, "abcdef")
end
- def test_public_encoding
- rsa1024 = Fixtures.pkey("rsa1024")
- assert_equal dup_public(rsa1024).to_der, rsa1024.public_to_der
- assert_equal dup_public(rsa1024).to_pem, rsa1024.public_to_pem
- end
-
def test_dup
key = Fixtures.pkey("rsa1024")
key2 = key.dup
diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb
index c1d737b2ab..f664bd3074 100644
--- a/test/openssl/utils.rb
+++ b/test/openssl/utils.rb
@@ -313,32 +313,6 @@ def check_component(base, test, keys)
assert_equal base.send(comp), test.send(comp)
}
end
-
- def dup_public(key)
- case key
- when OpenSSL::PKey::RSA
- rsa = OpenSSL::PKey::RSA.new
- rsa.set_key(key.n, key.e, nil)
- rsa
- when OpenSSL::PKey::DSA
- dsa = OpenSSL::PKey::DSA.new
- dsa.set_pqg(key.p, key.q, key.g)
- dsa.set_key(key.pub_key, nil)
- dsa
- when OpenSSL::PKey::DH
- dh = OpenSSL::PKey::DH.new
- dh.set_pqg(key.p, nil, key.g)
- dh
- else
- if defined?(OpenSSL::PKey::EC) && OpenSSL::PKey::EC === key
- ec = OpenSSL::PKey::EC.new(key.group)
- ec.public_key = key.public_key
- ec
- else
- raise "unknown key type"
- end
- end
- end
end
module OpenSSL::Certs
--
2.32.0

@ -1,31 +0,0 @@
--- ext/openssl/ossl_ocsp.c.orig 2022-04-07 16:40:13.263752886 +0200
+++ ext/openssl/ossl_ocsp.c 2022-04-07 16:45:56.818971187 +0200
@@ -382,7 +382,7 @@
if (!NIL_P(flags))
flg = NUM2INT(flags);
if (NIL_P(digest))
- md = EVP_sha1();
+ md = NULL;
else
md = ossl_evp_get_digestbyname(digest);
if (NIL_P(certs))
@@ -1033,7 +1033,7 @@
if (!NIL_P(flags))
flg = NUM2INT(flags);
if (NIL_P(digest))
- md = EVP_sha1();
+ md = NULL;
else
md = ossl_evp_get_digestbyname(digest);
if (NIL_P(certs))
--- test/openssl/test_ocsp.rb.orig 2022-04-08 08:20:31.400739869 +0200
+++ test/openssl/test_ocsp.rb 2022-04-08 08:20:37.208727488 +0200
@@ -99,7 +99,7 @@
request.sign(@cert, @cert_key, [@ca_cert], 0)
asn1 = OpenSSL::ASN1.decode(request.to_der)
assert_equal cid.to_der, asn1.value[0].value.find { |a| a.tag_class == :UNIVERSAL }.value[0].value[0].to_der
- assert_equal OpenSSL::ASN1.ObjectId("sha1WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der
+ assert_equal OpenSSL::ASN1.ObjectId("sha256WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der
assert_equal @cert.to_der, asn1.value[1].value[0].value[2].value[0].value[0].to_der
assert_equal @ca_cert.to_der, asn1.value[1].value[0].value[2].value[0].value[1].to_der
assert_equal asn1.to_der, OpenSSL::OCSP::Request.new(asn1.to_der).to_der

@ -1,647 +0,0 @@
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index fedcb93..53ad621 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -181,6 +181,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
have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", "openssl/ts.h")
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index 4b51268..2ab8aea 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -43,13 +43,13 @@
#ifndef LIBRESSL_VERSION_NUMBER
# define OSSL_IS_LIBRESSL 0
# define OSSL_OPENSSL_PREREQ(maj, min, pat) \
- (OPENSSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12))
+ (OPENSSL_VERSION_NUMBER >= ((maj << 28) | (min << 20) | (pat << 12)))
# define OSSL_LIBRESSL_PREREQ(maj, min, pat) 0
#else
# define OSSL_IS_LIBRESSL 1
# define OSSL_OPENSSL_PREREQ(maj, min, pat) 0
# define OSSL_LIBRESSL_PREREQ(maj, min, pat) \
- (LIBRESSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12))
+ (LIBRESSL_VERSION_NUMBER >= ((maj << 28) | (min << 20) | (pat << 12)))
#endif
#if !defined(OPENSSL_NO_ENGINE) && !OSSL_OPENSSL_PREREQ(3, 0, 0)
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index a61d3ee..0d3fa9a 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -1510,7 +1510,7 @@ Init_ossl_asn1(void)
*
* An Array that stores the name of a given tag number. These names are
* the same as the name of the tag constant that is additionally defined,
- * e.g. UNIVERSAL_TAG_NAME[2] = "INTEGER" and OpenSSL::ASN1::INTEGER = 2.
+ * e.g. <tt>UNIVERSAL_TAG_NAME[2] = "INTEGER"</tt> and <tt>OpenSSL::ASN1::INTEGER = 2</tt>.
*
* == Example usage
*
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 2a4835a..24d0da4 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -649,7 +649,7 @@ ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
}
}
else {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
+#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_LIBRESSL_PREREQ(3, 5, 0)
if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
ossl_pem_passwd_cb,
(void *)pass)) {
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 9a0682a..af262d9 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -1025,27 +1025,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);
@@ -1059,14 +1059,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
+
#if !defined(OPENSSL_NO_EC)
/*
* call-seq:
@@ -2818,6 +2857,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
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/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb
index 0fd7971..c79bc14 100644
--- a/test/openssl/test_asn1.rb
+++ b/test/openssl/test_asn1.rb
@@ -14,7 +14,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase
["keyUsage","keyCertSign, cRLSign",true],
["subjectKeyIdentifier","hash",false],
]
- dgst = OpenSSL::Digest.new('SHA1')
+ dgst = OpenSSL::Digest.new('SHA256')
cert = OpenSSL::TestUtils.issue_cert(
subj, key, s, exts, nil, nil, digest: dgst, not_before: now, not_after: now+3600)
@@ -42,7 +42,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase
assert_equal(OpenSSL::ASN1::Sequence, sig.class)
assert_equal(2, sig.value.size)
assert_equal(OpenSSL::ASN1::ObjectId, sig.value[0].class)
- assert_equal("1.2.840.113549.1.1.5", sig.value[0].oid)
+ assert_equal("1.2.840.113549.1.1.11", sig.value[0].oid)
assert_equal(OpenSSL::ASN1::Null, sig.value[1].class)
dn = tbs_cert.value[3] # issuer
@@ -189,7 +189,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase
assert_equal(OpenSSL::ASN1::Null, pkey.value[0].value[1].class)
assert_equal(OpenSSL::ASN1::BitString, sig_val.class)
- cululated_sig = key.sign(OpenSSL::Digest.new('SHA1'), tbs_cert.to_der)
+ cululated_sig = key.sign(OpenSSL::Digest.new('SHA256'), tbs_cert.to_der)
assert_equal(cululated_sig, sig_val.value)
end
diff --git a/test/openssl/test_ns_spki.rb b/test/openssl/test_ns_spki.rb
index ed3be86..383931b 100644
--- a/test/openssl/test_ns_spki.rb
+++ b/test/openssl/test_ns_spki.rb
@@ -22,7 +22,7 @@ class OpenSSL::TestNSSPI < OpenSSL::TestCase
spki = OpenSSL::Netscape::SPKI.new
spki.challenge = "RandomString"
spki.public_key = key1.public_key
- spki.sign(key1, OpenSSL::Digest.new('SHA1'))
+ spki.sign(key1, OpenSSL::Digest.new('SHA256'))
assert(spki.verify(spki.public_key))
assert(spki.verify(key1.public_key))
assert(!spki.verify(key2.public_key))
diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb
index 726b7db..08213df 100644
--- a/test/openssl/test_pkey_dsa.rb
+++ b/test/openssl/test_pkey_dsa.rb
@@ -36,8 +36,8 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase
assert_equal true, dsa512.verify(OpenSSL::Digest.new('DSS1'), signature, data)
end
- signature = dsa512.sign("SHA1", data)
- assert_equal true, dsa512.verify("SHA1", signature, data)
+ signature = dsa512.sign("SHA256", data)
+ assert_equal true, dsa512.verify("SHA256", signature, data)
signature0 = (<<~'end;').unpack("m")[0]
MCwCFH5h40plgU5Fh0Z4wvEEpz0eE9SnAhRPbkRB8ggsN/vsSEYMXvJwjGg/
diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb
index ffe5a94..c06fe6f 100644
--- a/test/openssl/test_pkey_ec.rb
+++ b/test/openssl/test_pkey_ec.rb
@@ -98,8 +98,8 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
def test_sign_verify
p256 = Fixtures.pkey("p256")
data = "Sign me!"
- signature = p256.sign("SHA1", data)
- assert_equal true, p256.verify("SHA1", signature, data)
+ signature = p256.sign("SHA256", data)
+ assert_equal true, p256.verify("SHA256", signature, data)
signature0 = (<<~'end;').unpack("m")[0]
MEQCIEOTY/hD7eI8a0qlzxkIt8LLZ8uwiaSfVbjX2dPAvN11AiAQdCYx56Fq
diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb
index 4bb39ed..9e06e43 100644
--- a/test/openssl/test_pkey_rsa.rb
+++ b/test/openssl/test_pkey_rsa.rb
@@ -80,8 +80,8 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
def test_sign_verify
rsa1024 = Fixtures.pkey("rsa1024")
data = "Sign me!"
- signature = rsa1024.sign("SHA1", data)
- assert_equal true, rsa1024.verify("SHA1", signature, data)
+ signature = rsa1024.sign("SHA256", data)
+ assert_equal true, rsa1024.verify("SHA256", signature, data)
signature0 = (<<~'end;').unpack("m")[0]
oLCgbprPvfhM4pjFQiDTFeWI9Sk+Og7Nh9TmIZ/xSxf2CGXQrptlwo7NQ28+
@@ -113,10 +113,10 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
def test_sign_verify_raw
key = Fixtures.pkey("rsa-1")
data = "Sign me!"
- hash = OpenSSL::Digest.digest("SHA1", data)
- signature = key.sign_raw("SHA1", hash)
- assert_equal true, key.verify_raw("SHA1", signature, hash)
- assert_equal true, key.verify("SHA1", signature, data)
+ hash = OpenSSL::Digest.digest("SHA256", data)
+ signature = key.sign_raw("SHA256", hash)
+ assert_equal true, key.verify_raw("SHA256", signature, hash)
+ assert_equal true, key.verify("SHA256", signature, data)
# Too long data
assert_raise(OpenSSL::PKey::PKeyError) {
@@ -129,9 +129,9 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
"rsa_pss_saltlen" => 20,
"rsa_mgf1_md" => "SHA256"
}
- sig_pss = key.sign_raw("SHA1", hash, pssopts)
- assert_equal true, key.verify("SHA1", sig_pss, data, pssopts)
- assert_equal true, key.verify_raw("SHA1", sig_pss, hash, pssopts)
+ sig_pss = key.sign_raw("SHA256", hash, pssopts)
+ assert_equal true, key.verify("SHA256", sig_pss, data, pssopts)
+ assert_equal true, key.verify_raw("SHA256", sig_pss, hash, pssopts)
end
def test_sign_verify_raw_legacy
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index a7607da..3ba8b39 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -669,10 +669,16 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
# buzz.example.net, respectively). ...
assert_equal(true, OpenSSL::SSL.verify_certificate_identity(
create_cert_with_san('DNS:baz*.example.com'), 'baz1.example.com'))
+
+ # LibreSSL 3.5.0+ doesn't support other wildcard certificates
+ # (it isn't required to, as RFC states MAY, not MUST)
+ return if libressl?(3, 5, 0)
+
assert_equal(true, OpenSSL::SSL.verify_certificate_identity(
create_cert_with_san('DNS:*baz.example.com'), 'foobaz.example.com'))
assert_equal(true, OpenSSL::SSL.verify_certificate_identity(
create_cert_with_san('DNS:b*z.example.com'), 'buzz.example.com'))
+
# Section 6.4.3 of RFC6125 states that client should NOT match identifier
# where wildcard is other than left-most label.
#
@@ -1556,8 +1562,101 @@ 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)
+ if libressl?(3, 4, 0) && !libressl?(3, 5, 0)
+ assert_equal("AEAD-AES128-GCM-SHA256", ssl.cipher[0])
+ else
+ assert_equal(csuite[0], ssl.cipher[0])
+ end
+ 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
pend "TLS 1.2 is not supported" unless tls12_supported?
ctx_proc = -> ctx {
ctx.ssl_version = :TLSv1_2
diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb
index d696b98..4e2bd0c 100644
--- a/test/openssl/test_x509cert.rb
+++ b/test/openssl/test_x509cert.rb
@@ -180,6 +180,7 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) })
cert.serial = 2
assert_equal(false, cert.verify(@rsa2048))
+ rescue OpenSSL::X509::CertificateError # RHEL 9 disables SHA1
end
def test_sign_and_verify_rsa_md5
@@ -226,9 +227,8 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
assert_equal("dsa_with_SHA256", cert.signature_algorithm)
# TODO: need more tests for dsa + sha2
- # SHA1 is allowed from OpenSSL 1.0.0 (0.9.8 requires DSS1)
- cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha1")
- assert_equal("dsaWithSHA1", cert.signature_algorithm)
+ cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha512")
+ assert_equal("dsa_with_SHA512", cert.signature_algorithm)
end
def test_check_private_key
diff --git a/test/openssl/test_x509crl.rb b/test/openssl/test_x509crl.rb
index bcdb0a6..146ee07 100644
--- a/test/openssl/test_x509crl.rb
+++ b/test/openssl/test_x509crl.rb
@@ -20,7 +20,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
crl = issue_crl([], 1, now, now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
assert_equal(1, crl.version)
assert_equal(cert.issuer.to_der, crl.issuer.to_der)
assert_equal(now, crl.last_update)
@@ -57,7 +57,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
]
cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
revoked = crl.revoked
assert_equal(5, revoked.size)
assert_equal(1, revoked[0].serial)
@@ -98,7 +98,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
revoke_info = (1..1000).collect{|i| [i, now, 0] }
crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
revoked = crl.revoked
assert_equal(1000, revoked.size)
assert_equal(1, revoked[0].serial)
@@ -124,7 +124,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
cert = issue_cert(@ca, @rsa2048, 1, cert_exts, nil, nil)
crl = issue_crl([], 1, Time.now, Time.now+1600, crl_exts,
- cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
exts = crl.extensions
assert_equal(3, exts.size)
assert_equal("1", exts[0].value)
@@ -160,24 +160,24 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
assert_equal(false, exts[2].critical?)
no_ext_crl = issue_crl([], 1, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
assert_equal nil, no_ext_crl.authority_key_identifier
end
def test_crlnumber
cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
crl = issue_crl([], 1, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
assert_match(1.to_s, crl.extensions[0].value)
assert_match(/X509v3 CRL Number:\s+#{1}/m, crl.to_text)
crl = issue_crl([], 2**32, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
assert_match((2**32).to_s, crl.extensions[0].value)
assert_match(/X509v3 CRL Number:\s+#{2**32}/m, crl.to_text)
crl = issue_crl([], 2**100, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
assert_match(/X509v3 CRL Number:\s+#{2**100}/m, crl.to_text)
assert_match((2**100).to_s, crl.extensions[0].value)
end
@@ -185,7 +185,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
def test_sign_and_verify
cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
crl = issue_crl([], 1, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
assert_equal(false, crl.verify(@rsa1024))
assert_equal(true, crl.verify(@rsa2048))
assert_equal(false, crl_error_returns_false { crl.verify(@dsa256) })
@@ -195,7 +195,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
cert = issue_cert(@ca, @dsa512, 1, [], nil, nil)
crl = issue_crl([], 1, Time.now, Time.now+1600, [],
- cert, @dsa512, OpenSSL::Digest.new('SHA1'))
+ cert, @dsa512, OpenSSL::Digest.new('SHA256'))
assert_equal(false, crl_error_returns_false { crl.verify(@rsa1024) })
assert_equal(false, crl_error_returns_false { crl.verify(@rsa2048) })
assert_equal(false, crl.verify(@dsa256))
diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb
index ee9c678..a84b162 100644
--- a/test/openssl/test_x509req.rb
+++ b/test/openssl/test_x509req.rb
@@ -23,31 +23,31 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
end
def test_public_key
- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1'))
+ req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der)
req = OpenSSL::X509::Request.new(req.to_der)
assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der)
- req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA1'))
+ req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA256'))
assert_equal(@dsa512.public_key.to_der, req.public_key.to_der)
req = OpenSSL::X509::Request.new(req.to_der)
assert_equal(@dsa512.public_key.to_der, req.public_key.to_der)
end
def test_version
- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1'))
+ req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
assert_equal(0, req.version)
req = OpenSSL::X509::Request.new(req.to_der)
assert_equal(0, req.version)
- req = issue_csr(1, @dn, @rsa1024, OpenSSL::Digest.new('SHA1'))
+ req = issue_csr(1, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
assert_equal(1, req.version)
req = OpenSSL::X509::Request.new(req.to_der)
assert_equal(1, req.version)
end
def test_subject
- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1'))
+ req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
assert_equal(@dn.to_der, req.subject.to_der)
req = OpenSSL::X509::Request.new(req.to_der)
assert_equal(@dn.to_der, req.subject.to_der)
@@ -78,9 +78,9 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
OpenSSL::X509::Attribute.new("msExtReq", attrval),
]
- req0 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1'))
+ req0 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
attrs.each{|attr| req0.add_attribute(attr) }
- req1 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1'))
+ req1 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
req1.attributes = attrs
assert_equal(req0.to_der, req1.to_der)
@@ -101,7 +101,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
end
def test_sign_and_verify_rsa_sha1
- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1'))
+ req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
assert_equal(true, req.verify(@rsa1024))
assert_equal(false, req.verify(@rsa2048))
assert_equal(false, request_error_returns_false { req.verify(@dsa256) })
@@ -122,7 +122,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
end
def test_sign_and_verify_dsa
- req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA1'))
+ req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA256'))
assert_equal(false, request_error_returns_false { req.verify(@rsa1024) })
assert_equal(false, request_error_returns_false { req.verify(@rsa2048) })
assert_equal(false, req.verify(@dsa256))
@@ -137,13 +137,13 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
end
def test_dup
- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1'))
+ req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
assert_equal(req.to_der, req.dup.to_der)
end
def test_eq
- req1 = issue_csr(0, @dn, @rsa1024, "sha1")
- req2 = issue_csr(0, @dn, @rsa1024, "sha1")
+ req1 = issue_csr(0, @dn, @rsa1024, "sha512")
+ req2 = issue_csr(0, @dn, @rsa1024, "sha512")
req3 = issue_csr(0, @dn, @rsa1024, "sha256")
assert_equal false, req1 == 12345
--- a/test/openssl/test_x509store.rb.orig 2022-07-14 14:07:32.468809273 +0200
+++ b/test/openssl/test_x509store.rb 2022-07-13 17:27:58.115363595 +0200
@@ -72,16 +72,16 @@
revoke_info = []
crl1 = issue_crl(revoke_info, 1, now, now+1800, [],
- ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
revoke_info = [ [2, now, 1], ]
crl1_2 = issue_crl(revoke_info, 2, now, now+1800, [],
- ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
revoke_info = [ [20, now, 1], ]
crl2 = issue_crl(revoke_info, 1, now, now+1800, [],
- ca2_cert, @rsa1024, OpenSSL::Digest.new('SHA1'))
+ ca2_cert, @rsa1024, OpenSSL::Digest.new('SHA256'))
revoke_info = []
crl2_2 = issue_crl(revoke_info, 2, now-100, now-1, [],
- ca2_cert, @rsa1024, OpenSSL::Digest.new('SHA1'))
+ ca2_cert, @rsa1024, OpenSSL::Digest.new('SHA256'))
assert_equal(true, ca1_cert.verify(ca1_cert.public_key)) # self signed
assert_equal(true, ca2_cert.verify(ca1_cert.public_key)) # issued by ca1
@@ -220,10 +220,10 @@
revoke_info = []
crl1 = issue_crl(revoke_info, 1, now, now+1800, [],
- ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
revoke_info = [ [2, now, 1], ]
crl2 = issue_crl(revoke_info, 2, now+1800, now+3600, [],
- ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+ ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
store.add_crl(crl1)
assert_raise(OpenSSL::X509::StoreError){
store.add_crl(crl2) # add CRL issued by same CA twice.

@ -0,0 +1,70 @@
From a1124dc162810f86cb0bff58cde24064cfc561bc Mon Sep 17 00:00:00 2001
From: nagachika <nagachika@ruby-lang.org>
Date: Fri, 9 Dec 2022 21:11:47 +0900
Subject: [PATCH] merge revision(s) 58cc3c9f387dcf8f820b43e043b540fa06248da3:
[Backport #19187]
[Bug #19187] Fix for tzdata-2022g
---
test/ruby/test_time_tz.rb | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
---
test/ruby/test_time_tz.rb | 21 +++++++++++++++------
1 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/test/ruby/test_time_tz.rb b/test/ruby/test_time_tz.rb
index b6785f336028d..939f218ed4d10 100644
--- a/test/ruby/test_time_tz.rb
+++ b/test/ruby/test_time_tz.rb
@@ -6,9 +6,9 @@ class TestTimeTZ < Test::Unit::TestCase
has_lisbon_tz = true
force_tz_test = ENV["RUBY_FORCE_TIME_TZ_TEST"] == "yes"
case RUBY_PLATFORM
- when /linux/
+ when /darwin|linux/
force_tz_test = true
- when /darwin|freebsd/
+ when /freebsd|openbsd/
has_lisbon_tz = false
force_tz_test = true
end
@@ -94,6 +94,9 @@ def group_by(e, &block)
CORRECT_KIRITIMATI_SKIP_1994 = with_tz("Pacific/Kiritimati") {
Time.local(1994, 12, 31, 0, 0, 0).year == 1995
}
+ CORRECT_SINGAPORE_1982 = with_tz("Asia/Singapore") {
+ "2022g" if Time.local(1981, 12, 31, 23, 59, 59).utc_offset == 8*3600
+ }
def time_to_s(t)
t.to_s
@@ -139,9 +142,12 @@ def test_america_managua
def test_asia_singapore
with_tz(tz="Asia/Singapore") {
- assert_time_constructor(tz, "1981-12-31 23:59:59 +0730", :local, [1981,12,31,23,59,59])
- assert_time_constructor(tz, "1982-01-01 00:30:00 +0800", :local, [1982,1,1,0,0,0])
- assert_time_constructor(tz, "1982-01-01 00:59:59 +0800", :local, [1982,1,1,0,29,59])
+ assert_time_constructor(tz, "1981-12-31 23:29:59 +0730", :local, [1981,12,31,23,29,59])
+ if CORRECT_SINGAPORE_1982
+ assert_time_constructor(tz, "1982-01-01 00:00:00 +0800", :local, [1981,12,31,23,30,00])
+ assert_time_constructor(tz, "1982-01-01 00:00:00 +0800", :local, [1982,1,1,0,0,0])
+ assert_time_constructor(tz, "1982-01-01 00:29:59 +0800", :local, [1982,1,1,0,29,59])
+ end
assert_time_constructor(tz, "1982-01-01 00:30:00 +0800", :local, [1982,1,1,0,30,0])
}
end
@@ -364,8 +370,11 @@ def self.gen_zdump_test(data)
America/Managua Wed Jan 1 04:59:59 1997 UTC = Tue Dec 31 23:59:59 1996 EST isdst=0 gmtoff=-18000
America/Managua Wed Jan 1 05:00:00 1997 UTC = Tue Dec 31 23:00:00 1996 CST isdst=0 gmtoff=-21600
Asia/Singapore Sun Aug 8 16:30:00 1965 UTC = Mon Aug 9 00:00:00 1965 SGT isdst=0 gmtoff=27000
-Asia/Singapore Thu Dec 31 16:29:59 1981 UTC = Thu Dec 31 23:59:59 1981 SGT isdst=0 gmtoff=27000
+Asia/Singapore Thu Dec 31 15:59:59 1981 UTC = Thu Dec 31 23:29:59 1981 SGT isdst=0 gmtoff=27000
Asia/Singapore Thu Dec 31 16:30:00 1981 UTC = Fri Jan 1 00:30:00 1982 SGT isdst=0 gmtoff=28800
+End
+ gen_zdump_test <<'End' if CORRECT_SINGAPORE_1982
+Asia/Singapore Thu Dec 31 16:00:00 1981 UTC = Fri Jan 1 00:00:00 1982 SGT isdst=0 gmtoff=28800
End
gen_zdump_test CORRECT_TOKYO_DST_1951 ? <<'End' + (CORRECT_TOKYO_DST_1951 < "2018f" ? <<'2018e' : <<'2018f') : <<'End'
Asia/Tokyo Sat May 5 14:59:59 1951 UTC = Sat May 5 23:59:59 1951 JST isdst=0 gmtoff=32400

@ -0,0 +1,27 @@
From dae843f6b7502f921a7e66f39e3714a39d860181 Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Date: Wed, 19 Oct 2022 19:40:00 +0900
Subject: [PATCH] Bypass git submodule add/update with git config
protocol.file.allow=always option.
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
---
test/rubygems/test_gem_source_git.rb | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/test/rubygems/test_gem_source_git.rb b/test/rubygems/test_gem_source_git.rb
index 5702da05974b6..c3b324771fa4d 100644
--- a/test/rubygems/test_gem_source_git.rb
+++ b/test/rubygems/test_gem_source_git.rb
@@ -64,6 +64,11 @@ def test_checkout_local_cached
end
def test_checkout_submodules
+ # We need to allow to checkout submodules with file:// protocol
+ # CVE-2022-39253
+ # https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/
+ system(@git, *%W"config --global protocol.file.allow always")
+
source = Gem::Source::Git.new @name, @repository, 'master', true
git_gem 'b'

@ -1,32 +0,0 @@
From f0b254f1f6610294821bbfc06b414d2af452db5b Mon Sep 17 00:00:00 2001
From: Jun Aruga <jaruga@redhat.com>
Date: Thu, 13 Apr 2023 17:28:27 +0200
Subject: [PATCH] [ruby/openssl] Drop a common logic disabling the FIPS mode in
the tests.
We want to run the unit tests in the FIPS mode too.
https://github.com/ruby/openssl/commit/ab92baff34
---
test/openssl/utils.rb | 5 -----
1 file changed, 5 deletions(-)
diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb
index 4ebcb9837b..8a0be0d154 100644
--- a/test/openssl/utils.rb
+++ b/test/openssl/utils.rb
@@ -1,11 +1,6 @@
# frozen_string_literal: true
begin
require "openssl"
-
- # Disable FIPS mode for tests for installations
- # where FIPS mode would be enabled by default.
- # Has no effect on all other installations.
- OpenSSL.fips_mode=false
rescue LoadError
end
--
2.41.0

@ -1,73 +0,0 @@
From b6d7cdc2bad0eadbca73f3486917f0ec7a475814 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Tue, 29 Aug 2023 19:46:02 +0900
Subject: [PATCH] [ruby/openssl] ssl: use ffdhe2048 from RFC 7919 as the
default DH group parameters
In TLS 1.2 or before, if DH group parameters for DHE are not supplied
with SSLContext#tmp_dh= or #tmp_dh_callback=, we currently use the
self-generated parameters added in commit https://github.com/ruby/openssl/commit/bb3399a61c03 ("support 2048
bit length DH-key", 2016-01-15) as the fallback.
While there is no known weakness in the current parameters, it would be
a good idea to switch to pre-defined, more well audited parameters.
This also allows the fallback to work in the FIPS mode.
The PEM encoding was derived with:
# RFC 7919 Appendix A.1. ffdhe2048
print OpenSSL::PKey.read(OpenSSL::ASN1::Sequence([OpenSSL::ASN1::Integer((<<-END).split.join.to_i(16)), OpenSSL::ASN1::Integer(2)]).to_der).to_pem
FFFFFFFF FFFFFFFF ADF85458 A2BB4A9A AFDC5620 273D3CF1
D8B9C583 CE2D3695 A9E13641 146433FB CC939DCE 249B3EF9
7D2FE363 630C75D8 F681B202 AEC4617A D3DF1ED5 D5FD6561
2433F51F 5F066ED0 85636555 3DED1AF3 B557135E 7F57C935
984F0C70 E0E68B77 E2A689DA F3EFE872 1DF158A1 36ADE735
30ACCA4F 483A797A BC0AB182 B324FB61 D108A94B B2C8E3FB
B96ADAB7 60D7F468 1D4F42A3 DE394DF4 AE56EDE7 6372BB19
0B07A7C8 EE0A6D70 9E02FCE1 CDF7E2EC C03404CD 28342F61
9172FE9C E98583FF 8E4F1232 EEF28183 C3FE3B1B 4C6FAD73
3BB5FCBC 2EC22005 C58EF183 7D1683B2 C6F34A26 C1B2EFFA
886B4238 61285C97 FFFFFFFF FFFFFFFF
END
https://github.com/ruby/openssl/commit/a5527cb4f4
---
ext/openssl/lib/openssl/ssl.rb | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb
index ea8bb2a18e533..94be6ba80b894 100644
--- a/ext/openssl/lib/openssl/ssl.rb
+++ b/ext/openssl/lib/openssl/ssl.rb
@@ -31,21 +31,21 @@ class SSLContext
}
if defined?(OpenSSL::PKey::DH)
- DEFAULT_2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_
+ DH_ffdhe2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_
-----BEGIN DH PARAMETERS-----
-MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY
-JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab
-VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6
-YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
-1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD
-7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg==
+MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
+87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
+YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
+7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
+ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
-----END DH PARAMETERS-----
_end_of_pem_
- private_constant :DEFAULT_2048
+ private_constant :DH_ffdhe2048
DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| # :nodoc:
warn "using default DH parameters." if $VERBOSE
- DEFAULT_2048
+ DH_ffdhe2048
}
end

@ -1,160 +0,0 @@
From 40451afa279c52ce7a508f8a9ec553cfe7a76a10 Mon Sep 17 00:00:00 2001
From: Jun Aruga <jaruga@redhat.com>
Date: Wed, 12 Apr 2023 17:15:21 +0200
Subject: [PATCH] Fix OpenSSL::PKey.read in OpenSSL 3 FIPS module.
This is a combination of the following 2 commits. Because the combined patch is
easy to merge.
This is the 1st commit message:
[ruby/openssl] Workaround: Fix OpenSSL::PKey.read that cannot parse PKey in the FIPS mode.
This commit is a workaround to avoid the error below that the
`OpenSSL::PKey.read` fails with the OpenSSL 3.0 FIPS mode.
```
$ openssl genrsa -out key.pem 4096
$ ruby -e "require 'openssl'; OpenSSL::PKey.read(File.read('key.pem'))"
-e:1:in `read': Could not parse PKey (OpenSSL::PKey::PKeyError)
from -e:1:in `<main>'
```
The root cause is on the OpenSSL side. The `OSSL_DECODER_CTX_set_selection`
doesn't apply the selection value properly if there are multiple providers, and
a provider (e.g. "base" provider) handles the decoder implementation, and
another provider (e.g. "fips" provider) handles the keys.
The workaround is to create `OSSL_DECODER_CTX` variable each time without using
the `OSSL_DECODER_CTX_set_selection`.
https://github.com/ruby/openssl/commit/5ff4a31621
This is the commit message #2:
[ruby/openssl] ossl_pkey.c: Workaround: Decode with non-zero selections.
This is a workaround for the decoding issue in ossl_pkey_read_generic().
The issue happens in the case that a key management provider is different from
a decoding provider.
Try all the non-zero selections in order, instead of selection 0 for OpenSSL 3
to avoid the issue.
https://github.com/ruby/openssl/commit/db688fa739
---
ext/openssl/ossl_pkey.c | 78 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 73 insertions(+), 5 deletions(-)
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 24d0da4683..15854aeca1 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -81,18 +81,20 @@ ossl_pkey_new(EVP_PKEY *pkey)
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
# include <openssl/decoder.h>
-EVP_PKEY *
-ossl_pkey_read_generic(BIO *bio, VALUE pass)
+static EVP_PKEY *
+ossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass)
{
void *ppass = (void *)pass;
OSSL_DECODER_CTX *dctx;
EVP_PKEY *pkey = NULL;
int pos = 0, pos2;
- dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, NULL, 0, NULL, NULL);
+ dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, input_type, NULL, NULL,
+ selection, NULL, NULL);
if (!dctx)
goto out;
- if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
+ if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
+ ppass) != 1)
goto out;
/* First check DER */
@@ -111,11 +113,77 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
goto out;
pos = pos2;
}
-
out:
+ OSSL_BIO_reset(bio);
OSSL_DECODER_CTX_free(dctx);
return pkey;
}
+
+EVP_PKEY *
+ossl_pkey_read_generic(BIO *bio, VALUE pass)
+{
+ EVP_PKEY *pkey = NULL;
+ /* First check DER, then check PEM. */
+ const char *input_types[] = {"DER", "PEM"};
+ int input_type_num = (int)(sizeof(input_types) / sizeof(char *));
+ /*
+ * Non-zero selections to try to decode.
+ *
+ * See EVP_PKEY_fromdata(3) - Selections to see all the selections.
+ *
+ * This is a workaround for the decoder failing to decode or returning
+ * bogus keys with selection 0, if a key management provider is different
+ * from a decoder provider. The workaround is to avoid using selection 0.
+ *
+ * Affected OpenSSL versions: >= 3.1.0, <= 3.1.2, or >= 3.0.0, <= 3.0.10
+ * Fixed OpenSSL versions: 3.2, next release of the 3.1.z and 3.0.z
+ *
+ * See https://github.com/openssl/openssl/pull/21519 for details.
+ *
+ * First check for private key formats (EVP_PKEY_KEYPAIR). This is to keep
+ * compatibility with ruby/openssl < 3.0 which decoded the following as a
+ * private key.
+ *
+ * $ openssl ecparam -name prime256v1 -genkey -outform PEM
+ * -----BEGIN EC PARAMETERS-----
+ * BggqhkjOPQMBBw==
+ * -----END EC PARAMETERS-----
+ * -----BEGIN EC PRIVATE KEY-----
+ * MHcCAQEEIAG8ugBbA5MHkqnZ9ujQF93OyUfL9tk8sxqM5Wv5tKg5oAoGCCqGSM49
+ * AwEHoUQDQgAEVcjhJfkwqh5C7kGuhAf8XaAjVuG5ADwb5ayg/cJijCgs+GcXeedj
+ * 86avKpGH84DXUlB23C/kPt+6fXYlitUmXQ==
+ * -----END EC PRIVATE KEY-----
+ *
+ * While the first PEM block is a proper encoding of ECParameters, thus
+ * OSSL_DECODER_from_bio() would pick it up, ruby/openssl used to return
+ * the latter instead. Existing applications expect this behavior.
+ *
+ * Note that normally, the input is supposed to contain a single decodable
+ * PEM block only, so this special handling should not create a new problem.
+ *
+ * Note that we need to create the OSSL_DECODER_CTX variable each time when
+ * we use the different selection as a workaround.
+ * See https://github.com/openssl/openssl/issues/20657 for details.
+ */
+ int selections[] = {
+ EVP_PKEY_KEYPAIR,
+ EVP_PKEY_KEY_PARAMETERS,
+ EVP_PKEY_PUBLIC_KEY
+ };
+ int selection_num = (int)(sizeof(selections) / sizeof(int));
+ int i, j;
+
+ for (i = 0; i < input_type_num; i++) {
+ for (j = 0; j < selection_num; j++) {
+ pkey = ossl_pkey_read(bio, input_types[i], selections[j], pass);
+ if (pkey) {
+ goto out;
+ }
+ }
+ }
+ out:
+ return pkey;
+}
#else
EVP_PKEY *
ossl_pkey_read_generic(BIO *bio, VALUE pass)
--
2.41.0

@ -1,142 +0,0 @@
From 29920ec109751459a65c6478525f2e59c644891f Mon Sep 17 00:00:00 2001
From: Jun Aruga <jaruga@redhat.com>
Date: Thu, 16 Mar 2023 21:36:43 +0100
Subject: [PATCH] [ruby/openssl] Implement FIPS functions on OpenSSL 3.
This commit is to implement the `OpenSSL::OPENSSL_FIPS`, `ossl_fips_mode_get`
and `ossl_fips_mode_set` to pass the test `test/openssl/test_fips.rb`.
It seems that the `OPENSSL_FIPS` macro is not used on the FIPS mode case any
more, and some FIPS related APIs also were removed in OpenSSL 3.
See the document <https://github.com/openssl/openssl/blob/master/doc/man7/migration_guide.pod#removed-fips_mode-and-fips_mode_set>
the section OPENSSL 3.0 > Main Changes from OpenSSL 1.1.1 >
Other notable deprecations and changes - Removed FIPS_mode() and FIPS_mode_set() .
The `OpenSSL::OPENSSL_FIPS` returns always true in OpenSSL 3 because the used
functions `EVP_default_properties_enable_fips` and `EVP_default_properties_is_fips_enabled`
works with the OpenSSL installed without FIPS option.
The `TEST_RUBY_OPENSSL_FIPS_ENABLED` is set on the FIPS mode case on the CI.
Because I want to test that the `OpenSSL.fips_mode` returns the `true` or
'false' surely in the CI. You can test the FIPS mode case by setting
`TEST_RUBY_OPENSSL_FIPS_ENABLED` on local too. Right now I don't find a better
way to get the status of the FIPS mode enabled or disabled for this purpose. I
am afraid of the possibility that the FIPS test case is unintentionally skipped.
I also replaced the ambiguous "returns" with "should return" in the tests.
https://github.com/ruby/openssl/commit/c5b2bc1268
---
ext/openssl/ossl.c | 25 +++++++++++++++++++++----
test/openssl/test_fips.rb | 32 ++++++++++++++++++++++++++++----
2 files changed, 49 insertions(+), 8 deletions(-)
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 6c532aca94..fcf3744c65 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -405,7 +405,11 @@ static VALUE
ossl_fips_mode_get(VALUE self)
{
-#ifdef OPENSSL_FIPS
+#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+ VALUE enabled;
+ enabled = EVP_default_properties_is_fips_enabled(NULL) ? Qtrue : Qfalse;
+ return enabled;
+#elif OPENSSL_FIPS
VALUE enabled;
enabled = FIPS_mode() ? Qtrue : Qfalse;
return enabled;
@@ -429,8 +433,18 @@ ossl_fips_mode_get(VALUE self)
static VALUE
ossl_fips_mode_set(VALUE self, VALUE enabled)
{
-
-#ifdef OPENSSL_FIPS
+#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+ if (RTEST(enabled)) {
+ if (!EVP_default_properties_enable_fips(NULL, 1)) {
+ ossl_raise(eOSSLError, "Turning on FIPS mode failed");
+ }
+ } else {
+ if (!EVP_default_properties_enable_fips(NULL, 0)) {
+ ossl_raise(eOSSLError, "Turning off FIPS mode failed");
+ }
+ }
+ return enabled;
+#elif OPENSSL_FIPS
if (RTEST(enabled)) {
int mode = FIPS_mode();
if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */
@@ -1185,7 +1199,10 @@ Init_openssl(void)
* Boolean indicating whether OpenSSL is FIPS-capable or not
*/
rb_define_const(mOSSL, "OPENSSL_FIPS",
-#ifdef OPENSSL_FIPS
+/* OpenSSL 3 is FIPS-capable even when it is installed without fips option */
+#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+ Qtrue
+#elif OPENSSL_FIPS
Qtrue
#else
Qfalse
diff --git a/test/openssl/test_fips.rb b/test/openssl/test_fips.rb
index 8cd474f9a3..56a12a94ce 100644
--- a/test/openssl/test_fips.rb
+++ b/test/openssl/test_fips.rb
@@ -4,22 +4,46 @@
if defined?(OpenSSL)
class OpenSSL::TestFIPS < OpenSSL::TestCase
+ def test_fips_mode_get_is_true_on_fips_mode_enabled
+ unless ENV["TEST_RUBY_OPENSSL_FIPS_ENABLED"]
+ omit "Only for FIPS mode environment"
+ end
+
+ assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;")
+ assert OpenSSL.fips_mode == true, ".fips_mode should return true on FIPS mode enabled"
+ end;
+ end
+
+ def test_fips_mode_get_is_false_on_fips_mode_disabled
+ if ENV["TEST_RUBY_OPENSSL_FIPS_ENABLED"]
+ omit "Only for non-FIPS mode environment"
+ end
+
+ assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;")
+ message = ".fips_mode should return false on FIPS mode disabled. " \
+ "If you run the test on FIPS mode, please set " \
+ "TEST_RUBY_OPENSSL_FIPS_ENABLED=true"
+ assert OpenSSL.fips_mode == false, message
+ end;
+ end
+
def test_fips_mode_is_reentrant
OpenSSL.fips_mode = false
OpenSSL.fips_mode = false
end
- def test_fips_mode_get
- return unless OpenSSL::OPENSSL_FIPS
+ def test_fips_mode_get_with_fips_mode_set
+ omit('OpenSSL is not FIPS-capable') unless OpenSSL::OPENSSL_FIPS
+
assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;")
require #{__FILE__.dump}
begin
OpenSSL.fips_mode = true
- assert OpenSSL.fips_mode == true, ".fips_mode returns true when .fips_mode=true"
+ assert OpenSSL.fips_mode == true, ".fips_mode should return true when .fips_mode=true"
OpenSSL.fips_mode = false
- assert OpenSSL.fips_mode == false, ".fips_mode returns false when .fips_mode=false"
+ assert OpenSSL.fips_mode == false, ".fips_mode should return false when .fips_mode=false"
rescue OpenSSL::OpenSSLError
pend "Could not set FIPS mode (OpenSSL::OpenSSLError: \#$!); skipping"
end
--
2.41.0

@ -1,36 +0,0 @@
From 8d1109c03bacc952b6218af2e4ae9b74c9855273 Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Date: Wed, 22 Mar 2023 16:10:06 +0900
Subject: [PATCH] Added assertion values for Amazon Linux 2023
---
spec/ruby/core/file/utime_spec.rb | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/spec/ruby/core/file/utime_spec.rb b/spec/ruby/core/file/utime_spec.rb
index a191e2924037c..0b0e4f979c935 100644
--- a/spec/ruby/core/file/utime_spec.rb
+++ b/spec/ruby/core/file/utime_spec.rb
@@ -72,17 +72,19 @@
platform_is :linux do
platform_is wordsize: 64 do
- it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19)" do
+ it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19 or 2486-07-02)" do
# https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps
# "Therefore, timestamps should not overflow until May 2446."
# https://lwn.net/Articles/804382/
# "On-disk timestamps hitting the y2038 limit..."
# The problem seems to be being improved, but currently it actually fails on XFS on RHEL8
# https://rubyci.org/logs/rubyci.s3.amazonaws.com/rhel8/ruby-master/log/20201112T123004Z.fail.html.gz
+ # Amazon Linux 2023 returns 2486-07-02 in this example
+ # http://rubyci.s3.amazonaws.com/amazon2023/ruby-master/log/20230322T063004Z.fail.html.gz
time = Time.at(1<<44)
File.utime(time, time, @file1)
- [559444, 2446, 2038].should.include? File.atime(@file1).year
- [559444, 2446, 2038].should.include? File.mtime(@file1).year
+ [559444, 2486, 2446, 2038].should.include? File.atime(@file1).year
+ [559444, 2486, 2446, 2038].should.include? File.mtime(@file1).year
end
end
end

@ -1,28 +0,0 @@
From 1816c142a4d66a75c23ccf6fd89a06cbe422e34f Mon Sep 17 00:00:00 2001
From: "NARUSE, Yui" <nurse@users.noreply.github.com>
Date: Sat, 3 Feb 2024 22:35:44 +0900
Subject: [PATCH] Fix test session reuse but expire (#9824)
* OpenSSL 3.2.1 30 Jan 2024 is also broken
Import 45064610725ddd81a5ea3775da35aa46985bc789 from ruby_3_3 branch
tentatively.
---
test/net/http/test_https.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/net/http/test_https.rb b/test/net/http/test_https.rb
index 7b97e39586..aef748dfa0 100644
--- a/test/net/http/test_https.rb
+++ b/test/net/http/test_https.rb
@@ -178,6 +178,7 @@ def test_session_reuse
def test_session_reuse_but_expire
# FIXME: The new_session_cb is known broken for clients in OpenSSL 1.1.0h.
skip if OpenSSL::OPENSSL_LIBRARY_VERSION =~ /OpenSSL 1.1.0h/
+ omit if OpenSSL::OPENSSL_LIBRARY_VERSION.include?('OpenSSL 3.2.')
http = Net::HTTP.new("localhost", config("port"))
http.use_ssl = true
--
2.44.0

@ -12,31 +12,11 @@ Also lifetime has been extended to 10 years from 4 years.
https://github.com/ruby/net-http/commit/4ab6c4a500
---
test/net/fixtures/Makefile | 6 +--
test/net/fixtures/cacert.pem | 44 ++++++++--------
test/net/fixtures/server.crt | 99 +++++++-----------------------------
test/net/fixtures/server.key | 55 ++++++++++----------
4 files changed, 71 insertions(+), 133 deletions(-)
4 files changed, 68 insertions(+), 130 deletions(-)
diff --git a/test/net/fixtures/Makefile b/test/net/fixtures/Makefile
index b2bc9c7368ee2..88c232e3b6c16 100644
--- a/test/net/fixtures/Makefile
+++ b/test/net/fixtures/Makefile
@@ -5,11 +5,11 @@ regen_certs:
make server.crt
cacert.pem: server.key
- openssl req -new -x509 -days 1825 -key server.key -out cacert.pem -text -subj "/C=JP/ST=Shimane/L=Matz-e city/O=Ruby Core Team/CN=Ruby Test CA/emailAddress=security@ruby-lang.org"
+ openssl req -new -x509 -days 3650 -key server.key -out cacert.pem -subj "/C=JP/ST=Shimane/L=Matz-e city/O=Ruby Core Team/CN=Ruby Test CA/emailAddress=security@ruby-lang.org"
server.csr:
- openssl req -new -key server.key -out server.csr -text -subj "/C=JP/ST=Shimane/O=Ruby Core Team/OU=Ruby Test/CN=localhost"
+ openssl req -new -key server.key -out server.csr -subj "/C=JP/ST=Shimane/O=Ruby Core Team/OU=Ruby Test/CN=localhost"
server.crt: server.csr cacert.pem
- openssl x509 -days 1825 -CA cacert.pem -CAkey server.key -set_serial 00 -in server.csr -req -text -out server.crt
+ openssl x509 -days 3650 -CA cacert.pem -CAkey server.key -set_serial 00 -in server.csr -req -out server.crt
rm server.csr
diff --git a/test/net/fixtures/cacert.pem b/test/net/fixtures/cacert.pem
index f623bd62ed375..24c83f1c65225 100644
--- a/test/net/fixtures/cacert.pem

@ -1,25 +0,0 @@
From 58ebf0f84a1dcb148f21aa589693d49d4e3be7de Mon Sep 17 00:00:00 2001
From: Jun Aruga <jaruga@redhat.com>
Date: Thu, 2 May 2024 17:23:09 +0200
Subject: [PATCH] Allow OpenSSL 3 in Ruby OpenSSL 2.x.
---
ext/openssl/extconf.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 0dc1a5eb43..51de0d6e39 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -110,7 +110,7 @@ def find_openssl_library
!try_static_assert("OPENSSL_VERSION_MAJOR >= 3", "openssl/opensslv.h") }
end
unless version_ok
- raise "OpenSSL >= 1.0.1, < 3.0.0 or LibreSSL >= 2.5.0 is required"
+ # raise "OpenSSL >= 1.0.1, < 3.0.0 or LibreSSL >= 2.5.0 is required"
end
# Prevent wincrypt.h from being included, which defines conflicting macro with openssl/x509.h
--
2.44.0

@ -1,48 +0,0 @@
From 7e9ec8a20b0f7469b415283d2ec0c22087f8eb2b Mon Sep 17 00:00:00 2001
From: Jun Aruga <jaruga@redhat.com>
Date: Wed, 24 Aug 2022 12:02:56 +0200
Subject: [PATCH] Fix tests with Europe/Amsterdam pre-1970 time on tzdata
version 2022b.
The Time Zone Database (tzdata) changed the pre-1970 timestamps in some zones
including Europe/Amsterdam on tzdata version 2022b or later.
See <https://github.com/eggert/tz/commit/35fa37fbbb152f5dbed4fd5edfdc968e3584fe12>.
The tzdata RPM package maintainer on Fedora project suggested changing the Ruby
test, because the change is intentional.
See <https://bugzilla.redhat.com/show_bug.cgi?id=2118259#c1>.
We use post-1970 time test data to simplify the test.
---
spec/ruby/core/time/shared/local.rb | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/spec/ruby/core/time/shared/local.rb b/spec/ruby/core/time/shared/local.rb
index 997b7186f1..c4aa7a7ea9 100644
--- a/spec/ruby/core/time/shared/local.rb
+++ b/spec/ruby/core/time/shared/local.rb
@@ -6,18 +6,16 @@
end
end
-=begin
platform_is_not :windows do
describe "timezone changes" do
- it "correctly adjusts the timezone change to 'CEST' on 'Europe/Amsterdam'" do
+ it "correctly adjusts the timezone change to 'CET' on 'Europe/Amsterdam'" do
with_timezone("Europe/Amsterdam") do
- Time.send(@method, 1940, 5, 16).to_a.should ==
- [0, 40, 1, 16, 5, 1940, 4, 137, true, "CEST"]
+ Time.send(@method, 1970, 5, 16).to_a.should ==
+ [0, 0, 0, 16, 5, 1970, 6, 136, false, "CET"]
end
end
end
end
-=end
end
describe :time_local_10_arg, shared: true do
--
2.36.1

@ -0,0 +1,41 @@
From 5e09d632f3b56d85b2659ab47d5571ae9e270e10 Mon Sep 17 00:00:00 2001
From: Xenor Chang <tubaxenor@gmail.com>
Date: Mon, 28 Nov 2022 12:34:06 +0800
Subject: [PATCH] Loosen the domain regex to accept '.' (#29)
* Loosen the domain regex to accept '.'
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
Co-authored-by: Hiroshi SHIBATA <hsbt@ruby-lang.org>
---
lib/cgi/cookie.rb | 2 +-
test/cgi/test_cgi_cookie.rb | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb
index 1a9c1a8..9498e2f 100644
--- a/lib/cgi/cookie.rb
+++ b/lib/cgi/cookie.rb
@@ -42,7 +42,7 @@ class Cookie < Array
TOKEN_RE = %r"\A[[!-~]&&[^()<>@,;:\\\"/?=\[\]{}]]+\z"
PATH_VALUE_RE = %r"\A[[ -~]&&[^;]]*\z"
- DOMAIN_VALUE_RE = %r"\A(?<label>(?!-)[-A-Za-z0-9]+(?<!-))(?:\.\g<label>)*\z"
+ DOMAIN_VALUE_RE = %r"\A\.?(?<label>(?!-)[-A-Za-z0-9]+(?<!-))(?:\.\g<label>)*\z"
# Create a new CGI::Cookie object.
#
diff --git a/test/cgi/test_cgi_cookie.rb b/test/cgi/test_cgi_cookie.rb
index 6d31932..eadae45 100644
--- a/test/cgi/test_cgi_cookie.rb
+++ b/test/cgi/test_cgi_cookie.rb
@@ -65,6 +65,9 @@ class CGICookieTest < Test::Unit::TestCase
cookie = CGI::Cookie.new({'domain' => 'a.example.com'}.merge(h))
assert_equal('a.example.com', cookie.domain)
+ cookie = CGI::Cookie.new(h.merge('domain'=>'.example.com'))
+ assert_equal('.example.com', cookie.domain)
+
cookie = CGI::Cookie.new({'domain'=>'1.example.com'}.merge(h))
assert_equal('1.example.com', cookie.domain, 'enhanced by RFC 1123')

@ -0,0 +1,264 @@
From e56ac27d19cc3acdf6c1cb13b14224c43df5f5f6 Mon Sep 17 00:00:00 2001
From: Kouhei Sutou <kou@clear-code.com>
Date: Thu, 4 Apr 2019 17:52:50 +0900
Subject: [PATCH] Accept String as a pattern
It's only for head only match case such as StringScanner#scan.
If we use a String as a pattern, we can improve match performance.
Here is a result of the including benchmark. It shows String as a
pattern is 1.25x faster than Regexp as a pattern.
% rake benchmark
/tmp/local/bin/ruby -S benchmark-driver benchmark/scan.yaml
Warming up --------------------------------------
regexp 12.094M i/s - 12.242M times in 1.012250s (82.69ns/i, 277clocks/i)
string 14.653M i/s - 14.889M times in 1.016124s (68.25ns/i, 252clocks/i)
Calculating -------------------------------------
regexp 14.713M i/s - 36.281M times in 2.465970s (67.97ns/i, 254clocks/i)
string 18.422M i/s - 43.959M times in 2.386255s (54.28ns/i, 201clocks/i)
Comparison:
string: 18421631.8 i/s
regexp: 14712660.7 i/s - 1.25x slower
====
Backport https://github.com/ruby/strscan/pull/4 for strscan.
REXML fixes for CVE-2024-35716 depend on this feature.
---
ext/strscan/strscan.c | 92 +++++++++++++++++++-----------
test/strscan/test_stringscanner.rb | 45 ++++++++++++++-
2 files changed, 100 insertions(+), 37 deletions(-)
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index d6168a0d4f..43319b672e 100644
--- a/ext/strscan/strscan.c
+++ b/ext/strscan/strscan.c
@@ -447,15 +447,18 @@ strscan_set_pos(VALUE self, VALUE v)
}
static VALUE
-strscan_do_scan(VALUE self, VALUE regex, int succptr, int getstr, int headonly)
+strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly)
{
- regex_t *rb_reg_prepare_re(VALUE re, VALUE str);
struct strscanner *p;
- regex_t *re;
- long ret;
- int tmpreg;
- Check_Type(regex, T_REGEXP);
+ if (headonly) {
+ if (!RB_TYPE_P(pattern, T_REGEXP)) {
+ StringValue(pattern);
+ }
+ }
+ else {
+ Check_Type(pattern, T_REGEXP);
+ }
GET_SCANNER(self, p);
CLEAR_MATCH_STATUS(p);
@@ -463,37 +466,55 @@ strscan_do_scan(VALUE self, VALUE regex, int succptr, int getstr, int headonly)
return Qnil;
}
- p->regex = regex;
- re = rb_reg_prepare_re(regex, p->str);
- tmpreg = re != RREGEXP_PTR(regex);
- if (!tmpreg) RREGEXP(regex)->usecnt++;
+ if (RB_TYPE_P(pattern, T_REGEXP)) {
+ regex_t *rb_reg_prepare_re(VALUE re, VALUE str);
+ regex_t *re;
+ long ret;
+ int tmpreg;
+
+ p->regex = pattern;
+ re = rb_reg_prepare_re(pattern, p->str);
+ tmpreg = re != RREGEXP_PTR(pattern);
+ if (!tmpreg) RREGEXP(pattern)->usecnt++;
+
+ if (headonly) {
+ ret = onig_match(re, (UChar* )CURPTR(p),
+ (UChar* )(CURPTR(p) + S_RESTLEN(p)),
+ (UChar* )CURPTR(p), &(p->regs), ONIG_OPTION_NONE);
+ }
+ else {
+ ret = onig_search(re,
+ (UChar* )CURPTR(p), (UChar* )(CURPTR(p) + S_RESTLEN(p)),
+ (UChar* )CURPTR(p), (UChar* )(CURPTR(p) + S_RESTLEN(p)),
+ &(p->regs), ONIG_OPTION_NONE);
+ }
+ if (!tmpreg) RREGEXP(pattern)->usecnt--;
+ if (tmpreg) {
+ if (RREGEXP(pattern)->usecnt) {
+ onig_free(re);
+ }
+ else {
+ onig_free(RREGEXP_PTR(pattern));
+ RREGEXP_PTR(pattern) = re;
+ }
+ }
- if (headonly) {
- ret = onig_match(re, (UChar* )CURPTR(p),
- (UChar* )(CURPTR(p) + S_RESTLEN(p)),
- (UChar* )CURPTR(p), &(p->regs), ONIG_OPTION_NONE);
+ if (ret == -2) rb_raise(ScanError, "regexp buffer overflow");
+ if (ret < 0) {
+ /* not matched */
+ return Qnil;
+ }
}
else {
- ret = onig_search(re,
- (UChar* )CURPTR(p), (UChar* )(CURPTR(p) + S_RESTLEN(p)),
- (UChar* )CURPTR(p), (UChar* )(CURPTR(p) + S_RESTLEN(p)),
- &(p->regs), ONIG_OPTION_NONE);
- }
- if (!tmpreg) RREGEXP(regex)->usecnt--;
- if (tmpreg) {
- if (RREGEXP(regex)->usecnt) {
- onig_free(re);
+ rb_enc_check(p->str, pattern);
+ if (S_RESTLEN(p) < RSTRING_LEN(pattern)) {
+ return Qnil;
}
- else {
- onig_free(RREGEXP_PTR(regex));
- RREGEXP_PTR(regex) = re;
+ if (memcmp(CURPTR(p), RSTRING_PTR(pattern), RSTRING_LEN(pattern)) != 0) {
+ return Qnil;
}
- }
-
- if (ret == -2) rb_raise(ScanError, "regexp buffer overflow");
- if (ret < 0) {
- /* not matched */
- return Qnil;
+ onig_region_clear(&(p->regs));
+ onig_region_set(&(p->regs), 0, 0, RSTRING_LEN(pattern));
}
MATCHED(p);
@@ -520,7 +541,8 @@ strscan_do_scan(VALUE self, VALUE regex, int succptr, int getstr, int headonly)
* p s.scan(/\w+/) # -> "test"
* p s.scan(/\w+/) # -> nil
* p s.scan(/\s+/) # -> " "
- * p s.scan(/\w+/) # -> "string"
+ * p s.scan("str") # -> "str"
+ * p s.scan(/\w+/) # -> "ing"
* p s.scan(/./) # -> nil
*
*/
@@ -539,6 +561,7 @@ strscan_scan(VALUE self, VALUE re)
* s = StringScanner.new('test string')
* p s.match?(/\w+/) # -> 4
* p s.match?(/\w+/) # -> 4
+ * p s.match?("test") # -> 4
* p s.match?(/\s+/) # -> nil
*/
static VALUE
@@ -560,7 +583,8 @@ strscan_match_p(VALUE self, VALUE re)
* p s.skip(/\w+/) # -> 4
* p s.skip(/\w+/) # -> nil
* p s.skip(/\s+/) # -> 1
- * p s.skip(/\w+/) # -> 6
+ * p s.skip("st") # -> 2
+ * p s.skip(/\w+/) # -> 4
* p s.skip(/./) # -> nil
*
*/
diff --git a/test/strscan/test_stringscanner.rb b/test/strscan/test_stringscanner.rb
index 3423f9cfed..63b1ce1f9b 100644
--- a/test/strscan/test_stringscanner.rb
+++ b/test/strscan/test_stringscanner.rb
@@ -282,6 +282,22 @@ def test_scan
assert_equal "", s.scan(//)
end
+ def test_scan_string
+ s = StringScanner.new('stra strb strc')
+ assert_equal 'str', s.scan('str')
+ assert_equal 'str', s[0]
+ assert_equal 3, s.pos
+ assert_equal false, s.tainted?
+ assert_equal 'a ', s.scan('a ')
+
+ str = 'stra strb strc'.dup
+ str.taint
+ s = StringScanner.new(str, false)
+ matched = s.scan('str')
+ assert_equal 'str', matched
+ assert_equal true, matched.tainted?
+ end
+
def test_skip
s = StringScanner.new('stra strb strc', true)
assert_equal 4, s.skip(/\w+/)
@@ -367,8 +383,10 @@ def test_matched
assert_equal false, s.matched.tainted?
s.scan(/\s+/)
assert_equal ' ', s.matched
+ s.scan('st')
+ assert_equal 'st', s.matched
s.scan(/\w+/)
- assert_equal 'strb', s.matched
+ assert_equal 'rb', s.matched
s.scan(/\s+/)
assert_equal ' ', s.matched
s.scan(/\w+/)
@@ -483,7 +501,7 @@ def test_pre_match
s.skip(/\s/)
assert_equal 'a', s.pre_match
assert_equal false, s.pre_match.tainted?
- s.scan(/\w/)
+ s.scan('b')
assert_equal 'a ', s.pre_match
s.scan_until(/c/)
assert_equal 'a b ', s.pre_match
@@ -513,7 +531,7 @@ def test_post_match
assert_equal ' b c d e', s.post_match
s.skip(/\s/)
assert_equal 'b c d e', s.post_match
- s.scan(/\w/)
+ s.scan('b')
assert_equal ' c d e', s.post_match
s.scan_until(/c/)
assert_equal ' d e', s.post_match
@@ -589,6 +607,20 @@ def test_encoding
assert_equal(Encoding::EUC_JP, ss.scan(/./e).encoding)
end
+ def test_encoding_string
+ str = "\xA1\xA2".dup.force_encoding("euc-jp")
+ ss = StringScanner.new(str)
+ assert_equal(str.dup, ss.scan(str.dup))
+ end
+
+ def test_invalid_encoding_string
+ str = "\xA1\xA2".dup.force_encoding("euc-jp")
+ ss = StringScanner.new(str)
+ assert_raise(Encoding::CompatibilityError) do
+ ss.scan(str.encode("UTF-8"))
+ end
+ end
+
def test_generic_regexp
ss = StringScanner.new("\xA1\xA2".dup.force_encoding("euc-jp"))
t = ss.scan(/./)
@@ -643,6 +675,13 @@ def test_exist_p
assert_equal(nil, s.exist?(/e/))
end
+ def test_exist_p_string
+ s = StringScanner.new("test string")
+ assert_raise(TypeError) do
+ s.exist?(" ")
+ end
+ end
+
def test_skip_until
s = StringScanner.new("Foo Bar Baz")
assert_equal(3, s.skip_until(/Foo/))

@ -1,44 +0,0 @@
From bb0f57aeb4de36a3b2b8b8cb01d25b32af0357d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADt=20Ondruch?= <vondruch@redhat.com>
Date: Wed, 27 Oct 2021 16:28:24 +0200
Subject: [PATCH] Provide distinguished name which will be correctly parsed.
It seems that since ruby openssl 2.1.0 [[1]], the distinguished name
submitted to `OpenSSL::X509::Name.parse` is not correctly parsed if it
does not contain the first slash:
~~~
$ ruby -v
ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux]
$ gem list | grep openssl
openssl (default: 2.2.0)
$ irb -r openssl
irb(main):001:0> OpenSSL::X509::Name.parse("CN=nobody/DC=example").to_s(OpenSSL::X509::Name::ONELINE)
=> "CN = nobody/DC=example"
irb(main):002:0> OpenSSL::X509::Name.parse("/CN=nobody/DC=example").to_s(OpenSSL::X509::Name::ONELINE)
=> "CN = nobody, DC = example"
~~~
[1]: https://github.com/ruby/openssl/commit/19c67cd10c57f3ab7b13966c36431ebc3fdd653b
---
lib/rubygems/security.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb
index c80639af6d..12de141f36 100644
--- a/lib/rubygems/security.rb
+++ b/lib/rubygems/security.rb
@@ -510,7 +510,7 @@ def self.email_to_name(email_address)
dcs = dcs.split '.'
- name = "CN=#{cn}/#{dcs.map {|dc| "DC=#{dc}" }.join '/'}"
+ name = "/CN=#{cn}/#{dcs.map {|dc| "DC=#{dc}" }.join '/'}"
OpenSSL::X509::Name.parse name
end
--
2.32.0

@ -1,261 +0,0 @@
From e80e7a3d0b3d72f7af7286b935702b3fab117008 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <deivid.rodriguez@riseup.net>
Date: Wed, 8 Dec 2021 21:12:24 +0100
Subject: [PATCH 1/5] More explicit require
This class does not use `rubygems/deprecate`. It uses
`rubygems/version`, which in turn uses `rubygems/deprecate`. Make this
explicit.
---
lib/rubygems/requirement.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb
index d2e28fab5b4..9edd6aa7d3c 100644
--- a/lib/rubygems/requirement.rb
+++ b/lib/rubygems/requirement.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-require_relative "deprecate"
+require_relative "version"
##
# A Requirement is a set of one or more version restrictions. It supports a
From 4e46dcc17ee5cabbde43b8a34063b8ab042536f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <deivid.rodriguez@riseup.net>
Date: Wed, 8 Dec 2021 21:17:30 +0100
Subject: [PATCH 2/5] Remove ineffective autoloads
These files are loaded on startup unconditionally, so we can require
them relatively when needed.
---
lib/rubygems.rb | 4 +---
lib/rubygems/specification.rb | 2 ++
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index f803e47628e..b8747409304 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -1310,19 +1310,17 @@ def default_gem_load_paths
autoload :Licenses, File.expand_path('rubygems/util/licenses', __dir__)
autoload :NameTuple, File.expand_path('rubygems/name_tuple', __dir__)
autoload :PathSupport, File.expand_path('rubygems/path_support', __dir__)
- autoload :Platform, File.expand_path('rubygems/platform', __dir__)
autoload :RequestSet, File.expand_path('rubygems/request_set', __dir__)
- autoload :Requirement, File.expand_path('rubygems/requirement', __dir__)
autoload :Resolver, File.expand_path('rubygems/resolver', __dir__)
autoload :Source, File.expand_path('rubygems/source', __dir__)
autoload :SourceList, File.expand_path('rubygems/source_list', __dir__)
autoload :SpecFetcher, File.expand_path('rubygems/spec_fetcher', __dir__)
- autoload :Specification, File.expand_path('rubygems/specification', __dir__)
autoload :Util, File.expand_path('rubygems/util', __dir__)
autoload :Version, File.expand_path('rubygems/version', __dir__)
end
require_relative 'rubygems/exceptions'
+require_relative 'rubygems/specification'
# REFACTOR: This should be pulled out into some kind of hacks file.
begin
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index d3b96491a28..dc5e5ba0138 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -9,6 +9,8 @@
require_relative 'deprecate'
require_relative 'basic_specification'
require_relative 'stub_specification'
+require_relative 'platform'
+require_relative 'requirement'
require_relative 'specification_policy'
require_relative 'util/list'
From 96b6b3e04e8e4fec17f63079a0caf999a2709d71 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <deivid.rodriguez@riseup.net>
Date: Wed, 8 Dec 2021 21:45:16 +0100
Subject: [PATCH 3/5] Load `operating_system.rb` customizations before setting
up default gems
It's very common for packagers to configure gem paths in this file, for
example, `Gem.default_dir`. Also, setting up default gems requires these
paths to be set, so that we know which default gems need to be setup.
If we setup default gems before loading `operatin_system.rb`
customizations, the wrong default gems will be setup.
Unfortunately, default gems loaded by `operating_system.rb` can't be
upgraded if we do this, but it seems much of a smaller issue. I wasn't
even fully sure it was the right thing to do when I added that, and it
was not the culprit of the end user issue that led to making that
change.
---
lib/rubygems.rb | 32 ++++++++++++++++----------------
test/rubygems/test_rubygems.rb | 23 +++++++++++++++++++++++
2 files changed, 39 insertions(+), 16 deletions(-)
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index b8747409304..11474b6554c 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -1323,22 +1323,6 @@ def default_gem_load_paths
require_relative 'rubygems/specification'
# REFACTOR: This should be pulled out into some kind of hacks file.
-begin
- ##
- # Defaults the Ruby implementation wants to provide for RubyGems
-
- require "rubygems/defaults/#{RUBY_ENGINE}"
-rescue LoadError
-end
-
-##
-# Loads the default specs.
-Gem::Specification.load_defaults
-
-require_relative 'rubygems/core_ext/kernel_gem'
-require_relative 'rubygems/core_ext/kernel_require'
-require_relative 'rubygems/core_ext/kernel_warn'
-
begin
##
# Defaults the operating system (or packager) wants to provide for RubyGems.
@@ -1354,3 +1338,19 @@ def default_gem_load_paths
"the problem and ask for help."
raise e.class, msg
end
+
+begin
+ ##
+ # Defaults the Ruby implementation wants to provide for RubyGems
+
+ require "rubygems/defaults/#{RUBY_ENGINE}"
+rescue LoadError
+end
+
+##
+# Loads the default specs.
+Gem::Specification.load_defaults
+
+require_relative 'rubygems/core_ext/kernel_gem'
+require_relative 'rubygems/core_ext/kernel_require'
+require_relative 'rubygems/core_ext/kernel_warn'
diff --git a/test/rubygems/test_rubygems.rb b/test/rubygems/test_rubygems.rb
index 493b9fdf4a3..fa77a299322 100644
--- a/test/rubygems/test_rubygems.rb
+++ b/test/rubygems/test_rubygems.rb
@@ -22,6 +22,29 @@ def test_operating_system_other_exceptions
"the problem and ask for help."
end
+ def test_operating_system_customizing_default_dir
+ pend "does not apply to truffleruby" if RUBY_ENGINE == 'truffleruby'
+ pend "loads a custom defaults/jruby file that gets in the middle" if RUBY_ENGINE == 'jruby'
+
+ # On a non existing default dir, there should be no gems
+
+ path = util_install_operating_system_rb <<-RUBY
+ module Gem
+ def self.default_dir
+ File.expand_path("foo")
+ end
+ end
+ RUBY
+
+ output = Gem::Util.popen(
+ *ruby_with_rubygems_and_fake_operating_system_in_load_path(path),
+ '-e',
+ "require \"rubygems\"; puts Gem::Specification.stubs.map(&:full_name)",
+ {:err => [:child, :out]}
+ ).strip
+ assert_empty output
+ end
+
private
def util_install_operating_system_rb(content)
From 52cfdd14fd1213a97aac12f01177e27779de9035 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <deivid.rodriguez@riseup.net>
Date: Thu, 9 Dec 2021 06:08:31 +0100
Subject: [PATCH 4/5] Install default fiddle on latest ruby on specs that need
it
Otherwise first OS customizations load and activate that fiddle version,
but then when we change to `Gem.default_dir`, that fiddle version is no
longer there.
---
spec/bundler/commands/clean_spec.rb | 2 +-
spec/bundler/install/gems/standalone_spec.rb | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb
index ffaf22dbb32..65231b35fac 100644
--- a/spec/bundler/commands/clean_spec.rb
+++ b/spec/bundler/commands/clean_spec.rb
@@ -638,7 +638,7 @@ def should_not_have_gems(*gems)
s.executables = "irb"
end
- realworld_system_gems "fiddle --version 1.0.6", "tsort --version 0.1.0", "pathname --version 0.1.0", "set --version 1.0.1"
+ realworld_system_gems "fiddle --version 1.0.8", "tsort --version 0.1.0", "pathname --version 0.1.0", "set --version 1.0.1"
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb
index db16a1b0e13..faefda25f45 100644
--- a/spec/bundler/install/gems/standalone_spec.rb
+++ b/spec/bundler/install/gems/standalone_spec.rb
@@ -113,7 +113,7 @@
skip "does not work on rubygems versions where `--install_dir` doesn't respect --default" unless Gem::Installer.for_spec(loaded_gemspec, :install_dir => "/foo").default_spec_file == "/foo/specifications/default/bundler-#{Bundler::VERSION}.gemspec" # Since rubygems 3.2.0.rc.2
skip "does not work on old rubies because the realworld gems that need to be installed don't support them" if RUBY_VERSION < "2.7.0"
- realworld_system_gems "fiddle --version 1.0.6", "tsort --version 0.1.0"
+ realworld_system_gems "fiddle --version 1.0.8", "tsort --version 0.1.0"
necessary_system_gems = ["optparse --version 0.1.1", "psych --version 3.3.2", "yaml --version 0.1.1", "logger --version 1.4.3", "etc --version 1.2.0", "stringio --version 3.0.0"]
necessary_system_gems += ["shellwords --version 0.1.0", "base64 --version 0.1.0", "resolv --version 0.2.1"] if Gem.rubygems_version < Gem::Version.new("3.3.3.a")
From c6a9c81021092c9157f5616a2bbe1323411a5bf8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <deivid.rodriguez@riseup.net>
Date: Thu, 9 Dec 2021 12:46:23 +0100
Subject: [PATCH 5/5] Resolve symlinks in LOAD_PATH when activating
pre-required default gems
Some double load issues were reported a while ago by OS packagers where
if a gem has been required before rubygems, and then after, rubygems
require would cause a double load.
We avoid this issue by activating the corresponding gem if we detect
that a file in the default LOAD_PATH that belongs to a default gem has
already been required when rubygems registers default gems.
However, the fix does not take into account that the default LOAD_PATH
could potentially include symlinks. This change fixes the same double
load issue described above but for situations where the default
LOAD_PATH includes symlinks.
---
lib/rubygems.rb | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index 11474b6554c..b7dda38d522 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -1293,7 +1293,12 @@ def already_loaded?(file)
end
def default_gem_load_paths
- @default_gem_load_paths ||= $LOAD_PATH[load_path_insert_index..-1]
+ @default_gem_load_paths ||= $LOAD_PATH[load_path_insert_index..-1].map do |lp|
+ expanded = File.expand_path(lp)
+ next expanded unless File.exist?(expanded)
+
+ File.realpath(expanded)
+ end
end
end

@ -1,105 +0,0 @@
From 558128594de16add5b453833fd5b043a24c1b7f5 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Wed, 22 Dec 2021 01:38:47 +0900
Subject: [PATCH 1/3] Use OpenSSL::PKey::EC.generate to generate ECC key pairs
When Ruby/OpenSSL is built against OpenSSL 3.0, OpenSSL::PKey::PKey
instances are immutable and OpenSSL::PKey::EC#generate_key cannot work
because it modifies the receiver.
OpenSSL::PKey::EC.generate is available on Ruby 2.4 (Ruby/OpenSSL 2.0)
or later.
---
lib/rubygems/security.rb | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb
index 22759972070..2aa07381d69 100644
--- a/lib/rubygems/security.rb
+++ b/lib/rubygems/security.rb
@@ -490,9 +490,13 @@ def self.create_key(algorithm)
when 'rsa'
OpenSSL::PKey::RSA.new(RSA_DSA_KEY_LENGTH)
when 'ec'
- domain_key = OpenSSL::PKey::EC.new(EC_NAME)
- domain_key.generate_key
- domain_key
+ if RUBY_VERSION >= "2.4.0"
+ OpenSSL::PKey::EC.generate(EC_NAME)
+ else
+ domain_key = OpenSSL::PKey::EC.new(EC_NAME)
+ domain_key.generate_key
+ domain_key
+ end
else
raise Gem::Security::Exception,
"#{algorithm} algorithm not found. RSA, DSA, and EC algorithms are supported."
From 60067d4f09b7fb9c23bed38e91acfde0293f29a0 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Wed, 22 Dec 2021 01:49:05 +0900
Subject: [PATCH 2/3] Use OpenSSL::X509::Certificate#check_private_key
The method is for the exact purpose: to check that an instance of
OpenSSL::PKey::PKey matches the public key in a certificate.
---
lib/rubygems/security.rb | 2 +-
lib/rubygems/security/policy.rb | 4 +---
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb
index 2aa07381d69..2906819bd34 100644
--- a/lib/rubygems/security.rb
+++ b/lib/rubygems/security.rb
@@ -530,7 +530,7 @@ def self.re_sign(expired_certificate, private_key, age = ONE_YEAR,
raise Gem::Security::Exception,
"incorrect signing key for re-signing " +
"#{expired_certificate.subject}" unless
- expired_certificate.public_key.to_pem == get_public_key(private_key).to_pem
+ expired_certificate.check_private_key(private_key)
unless expired_certificate.subject.to_s ==
expired_certificate.issuer.to_s
diff --git a/lib/rubygems/security/policy.rb b/lib/rubygems/security/policy.rb
index 3c3cb647ee3..06eae073f4a 100644
--- a/lib/rubygems/security/policy.rb
+++ b/lib/rubygems/security/policy.rb
@@ -115,11 +115,9 @@ def check_key(signer, key)
raise Gem::Security::Exception, 'missing key or signature'
end
- public_key = Gem::Security.get_public_key(key)
-
raise Gem::Security::Exception,
"certificate #{signer.subject} does not match the signing key" unless
- signer.public_key.to_pem == public_key.to_pem
+ signer.check_private_key(key)
true
end
From 6819e3d0fadc10ce8d10919402eedb730cf0e43f Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@rhe.jp>
Date: Wed, 22 Dec 2021 01:54:10 +0900
Subject: [PATCH 3/3] Fix Gem::Security.get_public_key on OpenSSL 3.0
Ruby/OpenSSL 2.2 added OpenSSL::PKey::PKey#public_to_der for serializing
only the public key components contained in the instance. This works
for all possible key types.
---
lib/rubygems/security.rb | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb
index 2906819bd34..f21c1756422 100644
--- a/lib/rubygems/security.rb
+++ b/lib/rubygems/security.rb
@@ -424,6 +424,8 @@ def self.create_cert(subject, key, age = ONE_YEAR, extensions = EXTENSIONS,
# Gets the right public key from a PKey instance
def self.get_public_key(key)
+ # Ruby 3.0 (Ruby/OpenSSL 2.2) or later
+ return OpenSSL::PKey.read(key.public_to_der) if key.respond_to?(:public_to_der)
return key.public_key unless key.is_a?(OpenSSL::PKey::EC)
ec_key = OpenSSL::PKey::EC.new(key.group.curve_name)

@ -9,9 +9,9 @@ module RubyGemsProv
def self.normalize_prerelease(version)
if version.prerelease?
prerelease = version.version.sub /^#{version.release}\./, ''
"#{version.release}~#{prerelease}"
"#{version.release}-0.1.#{prerelease}"
else
version.release
"#{version.release}-1"
end
end
end

@ -35,35 +35,31 @@ module RubyGemsReq
# with RPM .spec file.
def self.requirement_versions_to_rpm(requirement)
self.expand_requirement(requirement.requirements).map do |op, version|
version == Gem::Version.new(0) ? "" : " #{op} #{version}"
version == Gem::Version.new(0) ? "" : "#{op} #{version}"
end
end
# Compose dependency together with its requirements in RPM rich dependency
# string.
def self.compose_dependency_string(name, requirements)
dependency_strings = requirements.map { |requirement| name + requirement }
dependency_string = dependency_strings.join(' with ')
dependency_string.prepend('(').concat(')') if dependency_strings.length > 1
dependency_string
end
end
# Report RubyGems dependency, versioned if required.
def self.rubygems_dependency(specification)
dependency_name = "ruby(rubygems)"
requirements = Helpers::requirement_versions_to_rpm(specification.required_rubygems_version)
puts Helpers::compose_dependency_string(dependency_name, requirements)
Helpers::requirement_versions_to_rpm(specification.required_rubygems_version).each do |requirement|
dependency_string = "ruby(rubygems)"
dependency_string += " #{specification.required_rubygems_version}" if requirement&.length > 0
puts dependency_string
end
end
# Report all gem dependencies including their version.
def self.gem_depenencies(specification)
specification.runtime_dependencies.each do |dependency|
dependency_name = "rubygem(#{dependency.name})"
requirements = Helpers::requirement_versions_to_rpm(dependency.requirement)
puts Helpers::compose_dependency_string(dependency_name, requirements)
dependency_strings = Helpers::requirement_versions_to_rpm(dependency.requirement).map do |requirement|
requirement_string = "rubygem(#{dependency.name})"
requirement_string += " #{requirement}" if requirement&.length > 0
requirement_string
end
dependency_string = dependency_strings.join(' with ')
dependency_string.prepend('(').concat(')') if dependency_strings.length > 1
puts dependency_string
end
end

@ -1,34 +0,0 @@
require 'openssl'
# Run openssl tests in OpenSSL FIPS. See the link below for how to test.
# https://github.com/ruby/openssl/blob/master/.github/workflows/test.yml
# - step name: test on fips module
# Listing the testing files by an array explicitly rather than the `Dir.glob`
# to prevent the test files from not loading unintentionally.
TEST_FILES = %w[
test/openssl/test_fips.rb
test/openssl/test_pkey.rb
].freeze
if ARGV.empty?
puts 'ERROR: Argument base_dir required.'
puts "Usage: #{__FILE__} base_dir [options]"
exit false
end
BASE_DIR = ARGV[0]
abs_test_files = TEST_FILES.map { |file| File.join(BASE_DIR, file) }
# Set Fedora/RHEL downstream OpenSSL downstream environment variable to enable
# FIPS module in non-FIPS OS environment. It is available in Fedora 38 or later
# versions.
# https://src.fedoraproject.org/rpms/openssl/blob/rawhide/f/0009-Add-Kernel-FIPS-mode-flag-support.patch
ENV['OPENSSL_FORCE_FIPS_MODE'] = '1'
# A flag to tell the tests the current environment is FIPS enabled.
# https://github.com/ruby/openssl/blob/master/test/openssl/test_fips.rb
ENV['TEST_RUBY_OPENSSL_FIPS_ENABLED'] = 'true'
abs_test_files.each do |file|
puts "INFO: Loading #{file}."
require file
end

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save