commit 230258285f115501094b5e2d52adc13be11cb488 Author: James Antill Date: Mon Feb 20 02:13:51 2023 -0500 Import rpm: 8f5b96d7370661048218ca7076f49c2842d75831 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b15669c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/ruby-2.6.10.tar.xz diff --git a/.gitlab/merge_request_templates/default.md b/.gitlab/merge_request_templates/default.md new file mode 100644 index 0000000..25f37cc --- /dev/null +++ b/.gitlab/merge_request_templates/default.md @@ -0,0 +1,41 @@ + + +# Merge Request Required Information + +## Summary of Changes + +**Context of the pull-request:** + + + +**Pull-request or commit in Fedora Rawhide:** + + + +**Select priority:** + +* [ ] urgent +* [ ] high +* [ ] medium +* [ ] low +* [ ] unspecified + +**Do you need someone's review?:** + +* [x] Yes + +* [ ] No, because: + +## Approved Bugzilla Ticket +All submissions to CentOS Stream are required to have an approved [Red Hat Bugzilla](https://bugzilla.redhat.com/) ticket in a commit message, except only changing dot or yaml files. Please follow the CentOS Stream [contribution documentation](https://docs.centos.org/en-US/stream-contrib/quickstart/). diff --git a/abrt_prelude.rb b/abrt_prelude.rb new file mode 100644 index 0000000..587c6a6 --- /dev/null +++ b/abrt_prelude.rb @@ -0,0 +1,8 @@ +if defined?(Gem) + require 'rubygems.rb' + + begin + require 'abrt' + rescue LoadError + end +end diff --git a/gating.yaml b/gating.yaml new file mode 100644 index 0000000..c190bde --- /dev/null +++ b/gating.yaml @@ -0,0 +1,6 @@ +--- !Policy +product_versions: + - rhel-9 +decision_context: osci_compose_gate +rules: + - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tier1.functional} diff --git a/libruby.stp b/libruby.stp new file mode 100644 index 0000000..098b39d --- /dev/null +++ b/libruby.stp @@ -0,0 +1,303 @@ +/* SystemTap tapset to make it easier to trace Ruby 2.0 + * + * All probes provided by Ruby can be listed using following command + * (the path to the library must be adjuste appropriately): + * + * stap -L 'process("@LIBRARY_PATH@").mark("*")' + */ + +/** + * probe ruby.array.create - Allocation of new array. + * + * @size: Number of elements (an int) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.array.create = + process("@LIBRARY_PATH@").mark("array__create") +{ + size = $arg1 + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.cmethod.entry - Fired just before a method implemented in C is entered. + * + * @classname: Name of the class (string) + * @methodname: The method about bo be executed (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.cmethod.entry = + process("@LIBRARY_PATH@").mark("cmethod__entry") +{ + classname = user_string($arg1) + methodname = user_string($arg2) + file = user_string($arg3) + line = $arg4 +} + +/** + * probe ruby.cmethod.return - Fired just after a method implemented in C has returned. + * + * @classname: Name of the class (string) + * @methodname: The executed method (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.cmethod.return = + process("@LIBRARY_PATH@").mark("cmethod__return") +{ + classname = user_string($arg1) + methodname = user_string($arg2) + file = user_string($arg3) + line = $arg4 +} + +/** + * probe ruby.find.require.entry - Fired when require starts to search load + * path for suitable file to require. + * + * @requiredfile: The name of the file to be required (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.find.require.entry = + process("@LIBRARY_PATH@").mark("find__require__entry") +{ + requiredfile = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.find.require.return - Fired just after require has finished + * search of load path for suitable file to require. + * + * @requiredfile: The name of the file to be required (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.find.require.return = + process("@LIBRARY_PATH@").mark("find__require__return") +{ + requiredfile = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.gc.mark.begin - Fired when a GC mark phase is about to start. + * + * It takes no arguments. + */ +probe ruby.gc.mark.begin = + process("@LIBRARY_PATH@").mark("gc__mark__begin") +{ +} + +/** + * probe ruby.gc.mark.end - Fired when a GC mark phase has ended. + * + * It takes no arguments. + */ +probe ruby.gc.mark.end = + process("@LIBRARY_PATH@").mark("gc__mark__end") +{ +} + +/** + * probe ruby.gc.sweep.begin - Fired when a GC sweep phase is about to start. + * + * It takes no arguments. + */ +probe ruby.gc.sweep.begin = + process("@LIBRARY_PATH@").mark("gc__sweep__begin") +{ +} + +/** + * probe ruby.gc.sweep.end - Fired when a GC sweep phase has ended. + * + * It takes no arguments. + */ +probe ruby.gc.sweep.end = + process("@LIBRARY_PATH@").mark("gc__sweep__end") +{ +} + +/** + * probe ruby.hash.create - Allocation of new hash. + * + * @size: Number of elements (int) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.hash.create = + process("@LIBRARY_PATH@").mark("hash__create") +{ + size = $arg1 + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.load.entry - Fired when calls to "load" are made. + * + * @loadedfile: The name of the file to be loaded (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.load.entry = + process("@LIBRARY_PATH@").mark("load__entry") +{ + loadedfile = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.load.return - Fired just after require has finished + * search of load path for suitable file to require. + * + * @loadedfile: The name of the file that was loaded (string) + */ +probe ruby.load.return = + process("@LIBRARY_PATH@").mark("load__return") +{ + loadedfile = user_string($arg1) +} + +/** + * probe ruby.method.entry - Fired just before a method implemented in Ruby is entered. + * + * @classname: Name of the class (string) + * @methodname: The method about bo be executed (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.method.entry = + process("@LIBRARY_PATH@").mark("method__entry") +{ + classname = user_string($arg1) + methodname = user_string($arg2) + file = user_string($arg3) + line = $arg4 +} + +/** + * probe ruby.method.return - Fired just after a method implemented in Ruby has returned. + * + * @classname: Name of the class (string) + * @methodname: The executed method (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.method.return = + process("@LIBRARY_PATH@").mark("method__return") +{ + classname = user_string($arg1) + methodname = user_string($arg2) + file = user_string($arg3) + line = $arg4 +} + +/** + * probe ruby.object.create - Allocation of new object. + * + * @classname: Name of the class (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.object.create = + process("@LIBRARY_PATH@").mark("object__create") +{ + classname = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.parse.begin - Fired just before a Ruby source file is parsed. + * + * @parsedfile: The name of the file to be parsed (string) + * @parsedline: The line number of beginning of parsing (int) + */ +probe ruby.parse.begin = + process("@LIBRARY_PATH@").mark("parse__begin") +{ + parsedfile = user_string($arg1) + parsedline = $arg2 +} + +/** + * probe ruby.parse.end - Fired just after a Ruby source file was parsed. + * + * @parsedfile: The name of parsed the file (string) + * @parsedline: The line number of beginning of parsing (int) + */ +probe ruby.parse.end = + process("@LIBRARY_PATH@").mark("parse__end") +{ + parsedfile = user_string($arg1) + parsedline = $arg2 +} + +/** + * probe ruby.raise - Fired when an exception is raised. + * + * @classname: The class name of the raised exception (string) + * @file: The name of the file where the exception was raised (string) + * @line: The line number in the file where the exception was raised (int) + */ +probe ruby.raise = + process("@LIBRARY_PATH@").mark("raise") +{ + classname = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.require.entry - Fired on calls to rb_require_safe (when a file + * is required). + * + * @requiredfile: The name of the file to be required (string) + * @file: The file that called "require" (string) + * @line: The line number where the call to require was made(int) + */ +probe ruby.require.entry = + process("@LIBRARY_PATH@").mark("require__entry") +{ + requiredfile = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.require.return - Fired just after require has finished + * search of load path for suitable file to require. + * + * @requiredfile: The file that was required (string) + */ +probe ruby.require.return = + process("@LIBRARY_PATH@").mark("require__return") +{ + requiredfile = user_string($arg1) +} + +/** + * probe ruby.string.create - Allocation of new string. + * + * @size: Number of elements (an int) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.string.create = + process("@LIBRARY_PATH@").mark("string__create") +{ + size = $arg1 + file = user_string($arg2) + line = $arg3 +} diff --git a/macros.ruby b/macros.ruby new file mode 100644 index 0000000..36f4077 --- /dev/null +++ b/macros.ruby @@ -0,0 +1,22 @@ +%ruby_libdir %{_datadir}/%{name} +%ruby_libarchdir %{_libdir}/%{name} + +# This is the local lib/arch and should not be used for packaging. +%ruby_sitedir site_ruby +%ruby_sitelibdir %{_prefix}/local/share/%{name}/%{ruby_sitedir} +%ruby_sitearchdir %{_prefix}/local/%{_lib}/%{name}/%{ruby_sitedir} + +# This is the general location for libs/archs compatible with all +# or most of the Ruby versions available in the Fedora repositories. +%ruby_vendordir vendor_ruby +%ruby_vendorlibdir %{ruby_libdir}/%{ruby_vendordir} +%ruby_vendorarchdir %{ruby_libarchdir}/%{ruby_vendordir} + +# For ruby packages we want to filter out any provides caused by private +# libs in %%{ruby_vendorarchdir}/%%{ruby_sitearchdir}. +# +# Note that this must be invoked in the spec file, preferably as +# "%{?ruby_default_filter}", before any %description block. +%ruby_default_filter %{expand: \ +%global __provides_exclude_from %{?__provides_exclude_from:%{__provides_exclude_from}|}^(%{ruby_vendorarchdir}|%{ruby_sitearchdir})/.*\\\\.so$ \ +} diff --git a/macros.rubygems b/macros.rubygems new file mode 100644 index 0000000..2552780 --- /dev/null +++ b/macros.rubygems @@ -0,0 +1,195 @@ +# The RubyGems root folder. +%gem_dir %{_datadir}/gems +%gem_archdir %{_libdir}/gems + +# Common gem locations and files. +%gem_instdir %{gem_dir}/gems/%{gem_name}-%{version}%{?prerelease} +%gem_extdir_mri %{gem_archdir}/%{name}/%{gem_name}-%{version}%{?prerelease} +%gem_libdir %{gem_instdir}/lib +%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_install - Install gem into appropriate directory. +# +# Usage: %gem_install [options] +# +# -n Overrides gem file name for installation. +# -d Set installation directory. +# +%gem_install(d:n:) \ +mkdir -p %{-d*}%{!?-d:.%{gem_dir}} \ +\ +CONFIGURE_ARGS="--with-cflags='%{optflags}' --with-cxxflags='%{optflags}' $CONFIGURE_ARGS" \\\ +gem install \\\ + -V \\\ + --local \\\ + --build-root %{-d*}%{!?-d:.} \\\ + --force \\\ + --document=ri,rdoc \\\ + %{-n*}%{!?-n:%{gem_name}-%{version}%{?prerelease}.gem} \ +%{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. + + +# %gemspec_add_dep - Add dependency into .gemspec. +# +# Usage: %gemspec_add_dep -g [options] [requirements] +# +# Add dependency named to .gemspec file. The macro adds runtime +# dependency by default. The [requirements] argument can be used to specify +# the dependency constraints more precisely. It is expected to be valid Ruby +# code. +# +# -s Overrides the default .gemspec location. +# -d Add development dependecy. +# +%gemspec_add_dep(g:s:d) \ +read -d '' gemspec_add_dep_script << 'EOR' || : \ + gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}%{?prerelease}.gemspec}' \ + \ + name = '%{-g*}' \ + requirements = %{*}%{!?1:nil} \ + \ + type = :%{!?-d:runtime}%{?-d:development} \ + \ + spec = Gem::Specification.load(gemspec_file) \ + abort("#{gemspec_file} is not accessible.") unless spec \ + \ + dep = spec.dependencies.detect { |d| d.type == type && d.name == name } \ + if dep \ + dep.requirement.concat requirements \ + else \ + spec.public_send "add_#{type}_dependency", name, requirements \ + end \ + File.write gemspec_file, spec.to_ruby \ +EOR\ +echo "$gemspec_add_dep_script" | ruby \ +unset -v gemspec_add_dep_script \ +%{nil} + + +# %gemspec_remove_dep - Remove dependency from .gemspec. +# +# Usage: %gemspec_remove_dep -g [options] [requirements] +# +# Remove dependency named from .gemspec file. The macro removes runtime +# dependency by default. The [requirements] argument can be used to specify +# the dependency constraints more precisely. It is expected to be valid Ruby +# code. The macro fails if these specific requirements can't be removed. +# +# -s Overrides the default .gemspec location. +# -d Remove development dependecy. +# +%gemspec_remove_dep(g:s:d) \ +read -d '' gemspec_remove_dep_script << 'EOR' || : \ + gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}%{?prerelease}.gemspec}' \ + \ + name = '%{-g*}' \ + requirements = %{*}%{!?1:nil} \ + \ + type = :%{!?-d:runtime}%{?-d:development} \ + \ + spec = Gem::Specification.load(gemspec_file) \ + abort("#{gemspec_file} is not accessible.") unless spec \ + \ + dep = spec.dependencies.detect { |d| d.type == type && d.name == name } \ + if dep \ + if requirements \ + requirements = Gem::Requirement.create(requirements).requirements \ + requirements.each do |r| \ + unless dep.requirement.requirements.reject! { |dependency_requirements| dependency_requirements == r } \ + abort("Requirement '#{r.first} #{r.last}' was not possible to remove for dependency '#{dep}'!") \ + end \ + end \ + spec.dependencies.delete dep if dep.requirement.requirements.empty? \ + else \ + spec.dependencies.delete dep \ + end \ + else \ + abort("Dependency '#{name}' was not found!") \ + end \ + File.write gemspec_file, spec.to_ruby \ +EOR\ +echo "$gemspec_remove_dep_script" | ruby \ +unset -v gemspec_remove_dep_script \ +%{nil} + + +# %%gemspec_add_file - Add files to various files lists in .gemspec. +# +# Usage: %%gemspec_add_file [options] +# +# Add files to .gemspec file. is expected to be valid Ruby code. +# Path to file is expected. Does not check real files in any way. +# By default, `files` list is edited. +# +# -s Overrides the default .gemspec location. +# -t Edit test_files only. +# -r Edit extra_rdoc_files only. +# +%gemspec_add_file(s:tr) \ +read -d '' gemspec_add_file_script << 'EOR' || : \ + gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}%{?prerelease}.gemspec}' \ + \ + abort("gemspec_add_file: Use only one '-t' or '-r' at a time.") if "%{?-t}%{?-r}" == "-t-r" \ + \ + filenames = %{*}%{!?1:nil} \ + filenames = Array(filenames) \ + \ + spec = Gem::Specification.load(gemspec_file) \ + abort("#{gemspec_file} is not accessible.") unless spec \ + \ + spec.%{?-t:test_}%{?-r:extra_rdoc_}files += filenames \ + File.write gemspec_file, spec.to_ruby \ +EOR\ +echo "$gemspec_add_file_script" | ruby \ +unset -v gemspec_add_file_script \ +%{nil} + + +# %%gemspec_remove_file - Remove files from various files lists in .gemspec. +# +# Usage: %%gemspec_remove_file [options] +# +# Remove files from .gemspec file. is expected to be valid Ruby code. +# Path to file is expected. Does not check/remove real files in any way. +# By default, `files` list is edited. File has to be removed from `test_files` +# first in order to be removable from `files`. +# +# -s Overrides the default .gemspec location. +# -t Edit test_files only. +# -r Edit extra_rdoc_files only. +# +%gemspec_remove_file(s:tr) \ +read -d '' gemspec_remove_file_script << 'EOR' || : \ + gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}%{?prerelease}.gemspec}' \ + \ + abort("gemspec_remove_file: Use only one '-t' or '-r' at a time.") if "%{?-t}%{?-r}" == "-t-r" \ + \ + filenames = %{*}%{!?1:nil} \ + filenames = Array(filenames) \ + \ + spec = Gem::Specification.load(gemspec_file) \ + abort("#{gemspec_file} is not accessible.") unless spec \ + \ + spec.%{?-t:test_}%{?-r:extra_rdoc_}files -= filenames \ + File.write gemspec_file, spec.to_ruby \ +EOR\ +echo "$gemspec_remove_file_script" | ruby \ +unset -v gemspec_remove_file_script \ +%{nil} diff --git a/operating_system.rb b/operating_system.rb new file mode 100644 index 0000000..d95b303 --- /dev/null +++ b/operating_system.rb @@ -0,0 +1,148 @@ +module Gem + class << self + + ## + # Returns full path of previous but one directory of dir in path + # E.g. for '/usr/share/ruby', 'ruby', it returns '/usr' + + def previous_but_one_dir_to(path, dir) + return unless path + + split_path = path.split(File::SEPARATOR) + File.join(split_path.take_while { |one_dir| one_dir !~ /^#{dir}$/ }[0..-2]) + end + private :previous_but_one_dir_to + + ## + # Detects --install-dir option specified on command line. + + def opt_install_dir? + @opt_install_dir ||= ARGV.include?('--install-dir') || ARGV.include?('-i') + end + private :opt_install_dir? + + ## + # Detects --build-root option specified on command line. + + def opt_build_root? + @opt_build_root ||= ARGV.include?('--build-root') + end + private :opt_build_root? + + ## + # Tries to detect, if arguments and environment variables suggest that + # 'gem install' is executed from rpmbuild. + + def rpmbuild? + @rpmbuild ||= ENV['RPM_PACKAGE_NAME'] && (opt_install_dir? || opt_build_root?) + end + private :rpmbuild? + + ## + # Default gems locations allowed on FHS system (/usr, /usr/share). + # The locations are derived from directories specified during build + # configuration. + + def default_locations + @default_locations ||= { + :system => previous_but_one_dir_to(RbConfig::CONFIG['vendordir'], RbConfig::CONFIG['RUBY_INSTALL_NAME']), + :local => previous_but_one_dir_to(RbConfig::CONFIG['sitedir'], RbConfig::CONFIG['RUBY_INSTALL_NAME']) + } + end + + ## + # For each location provides set of directories for binaries (:bin_dir) + # platform independent (:gem_dir) and dependent (:ext_dir) files. + + def default_dirs + @libdir ||= case RUBY_PLATFORM + when 'java' + RbConfig::CONFIG['datadir'] + else + RbConfig::CONFIG['libdir'] + end + + @default_dirs ||= default_locations.inject(Hash.new) do |hash, location| + destination, path = location + + hash[destination] = if path + { + :bin_dir => File.join(path, RbConfig::CONFIG['bindir'].split(File::SEPARATOR).last), + :gem_dir => File.join(path, RbConfig::CONFIG['datadir'].split(File::SEPARATOR).last, 'gems'), + :ext_dir => File.join(path, @libdir.split(File::SEPARATOR).last, 'gems') + } + else + { + :bin_dir => '', + :gem_dir => '', + :ext_dir => '' + } + end + + hash + end + end + + ## + # Remove methods we are going to override. This avoids "method redefined;" + # warnings otherwise issued by Ruby. + + remove_method :operating_system_defaults if method_defined? :operating_system_defaults + remove_method :default_dir if method_defined? :default_dir + remove_method :default_path if method_defined? :default_path + remove_method :default_ext_dir_for if method_defined? :default_ext_dir_for + + ## + # Regular user installs into user directory, root manages /usr/local. + + def operating_system_defaults + unless opt_build_root? + options = if Process.uid == 0 + "--install-dir=#{Gem.default_dirs[:local][:gem_dir]} --bindir #{Gem.default_dirs[:local][:bin_dir]}" + else + "--user-install --bindir #{File.join [Dir.home, 'bin']}" + end + + {"gem" => options} + else + {} + end + end + + ## + # RubyGems default overrides. + + def default_dir + Gem.default_dirs[:system][:gem_dir] + end + + def default_path + path = default_dirs.collect {|location, paths| paths[:gem_dir]} + path.unshift Gem.user_dir if File.exist? Gem.user_home + path + end + + def default_ext_dir_for base_dir + dir = if rpmbuild? + build_dir = base_dir.chomp Gem.default_dirs[:system][:gem_dir] + if build_dir != base_dir + File.join build_dir, Gem.default_dirs[:system][:ext_dir] + end + else + dirs = Gem.default_dirs.detect {|location, paths| paths[:gem_dir] == base_dir} + dirs && dirs.last[:ext_dir] + end + dir && File.join(dir, RbConfig::CONFIG['RUBY_INSTALL_NAME']) + end + + # This method should be available since RubyGems 2.2 until RubyGems 3.0. + # https://github.com/rubygems/rubygems/issues/749 + if method_defined? :install_extension_in_lib + remove_method :install_extension_in_lib + + def install_extension_in_lib + false + end + end + end +end diff --git a/ruby-1.9.3-mkmf-verbose.patch b/ruby-1.9.3-mkmf-verbose.patch new file mode 100644 index 0000000..dc8e9da --- /dev/null +++ b/ruby-1.9.3-mkmf-verbose.patch @@ -0,0 +1,25 @@ +From 28cc0749d6729aa2444661ee7b411e183fe220b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Mon, 19 Nov 2012 15:14:51 +0100 +Subject: [PATCH] Verbose mkmf. + +--- + lib/mkmf.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/mkmf.rb b/lib/mkmf.rb +index 682eb46..e6b1445 100644 +--- a/lib/mkmf.rb ++++ b/lib/mkmf.rb +@@ -1911,7 +1911,7 @@ def configuration(srcdir) + SHELL = /bin/sh + + # V=0 quiet, V=1 verbose. other values don't work. +-V = 0 ++V = 1 + Q1 = $(V:1=) + Q = $(Q1:0=@) + ECHO1 = $(V:1=@ #{CONFIG['NULLCMD']}) +-- +1.8.3.1 + diff --git a/ruby-2.1.0-Allow-to-specify-additional-preludes-by-configuratio.patch b/ruby-2.1.0-Allow-to-specify-additional-preludes-by-configuratio.patch new file mode 100644 index 0000000..14da77e --- /dev/null +++ b/ruby-2.1.0-Allow-to-specify-additional-preludes-by-configuratio.patch @@ -0,0 +1,58 @@ +From 996012f6abe0ce4d68a2de9f249935c6d5b467bc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +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 +@@ -154,6 +154,8 @@ BOOTSTRAPRUBY = @BOOTSTRAPRUBY@ + COROUTINE_H = @X_FIBER_COROUTINE_H@ + COROUTINE_OBJ = $(COROUTINE_H:.h=.@OBJEXT@) + ++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 +@@ -156,7 +156,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 +@@ -3872,6 +3872,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 + diff --git a/ruby-2.1.0-Enable-configuration-of-archlibdir.patch b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch new file mode 100644 index 0000000..d5ecc34 --- /dev/null +++ b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch @@ -0,0 +1,28 @@ +From 07c666ba5c3360dd6f43605a8ac7c85c99c1721f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Tue, 1 Oct 2013 12:22:40 +0200 +Subject: [PATCH] Allow to configure libruby.so placement. + +--- + configure.ac | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 11fc237552..b77e88fc37 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3102,6 +3102,11 @@ AS_IF([test ${multiarch+set}], [ + ]) + + archlibdir='${libdir}/${arch}' ++AC_ARG_WITH(archlibdir, ++ AS_HELP_STRING([--with-archlibdir=DIR], ++ [prefix for libruby [[LIBDIR/ARCH]]]), ++ [archlibdir="$withval"]) ++ + sitearchlibdir='${libdir}/${sitearch}' + archincludedir='${includedir}/${arch}' + sitearchincludedir='${includedir}/${sitearch}' +-- +1.8.3.1 + diff --git a/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch b/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch new file mode 100644 index 0000000..f7f364f --- /dev/null +++ b/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch @@ -0,0 +1,80 @@ +From e24d97c938c481450ed80ec83e5399595946c1ae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Fri, 8 Feb 2013 22:48:41 +0100 +Subject: [PATCH] Prevent duplicated paths when empty version string is + configured. + +--- + configure.ac | 3 ++- + loadpath.c | 12 ++++++++++++ + tool/mkconfig.rb | 2 +- + 3 files changed, 15 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 999e2d6d5d..11fc237552 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3727,7 +3727,8 @@ AS_CASE(["$ruby_version_dir_name"], + ruby_version_dir=/'${ruby_version_dir_name}' + + if test -z "${ruby_version_dir_name}"; then +- AC_MSG_ERROR([No ruby version, No place for bundled libraries]) ++ unset ruby_version_dir ++ AC_DEFINE(RUBY_LIB_VERSION_BLANK, 1) + fi + + rubylibdir='${rubylibprefix}'${ruby_version_dir} +diff --git a/loadpath.c b/loadpath.c +index 9160031..0d4d953 100644 +--- a/loadpath.c ++++ b/loadpath.c +@@ -65,21 +65,33 @@ const char ruby_initial_load_paths[] = + RUBY_SEARCH_PATH "\0" + #endif + #ifndef NO_RUBY_SITE_LIB ++#ifdef RUBY_LIB_VERSION_BLANK ++ RUBY_SITE_LIB "\0" ++#else + RUBY_SITE_LIB2 "\0" ++#endif + #ifdef RUBY_THINARCH + RUBY_SITE_ARCH_LIB_FOR(RUBY_THINARCH) "\0" + #endif + RUBY_SITE_ARCH_LIB_FOR(RUBY_SITEARCH) "\0" ++#ifndef RUBY_LIB_VERSION_BLANK + RUBY_SITE_LIB "\0" + #endif ++#endif + + #ifndef NO_RUBY_VENDOR_LIB ++#ifdef RUBY_LIB_VERSION_BLANK ++ RUBY_VENDOR_LIB "\0" ++#else + RUBY_VENDOR_LIB2 "\0" ++#endif + #ifdef RUBY_THINARCH + RUBY_VENDOR_ARCH_LIB_FOR(RUBY_THINARCH) "\0" + #endif + RUBY_VENDOR_ARCH_LIB_FOR(RUBY_SITEARCH) "\0" ++#ifndef RUBY_LIB_VERSION_BLANK + RUBY_VENDOR_LIB "\0" ++#endif + #endif + + RUBY_LIB "\0" +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 @@ + val = val.gsub(/\$(?:\$|\{?(\w+)\}?)/) {$1 ? "$(#{$1})" : $&}.dump + case name + when /^prefix$/ +- val = "(TOPDIR || DESTDIR + #{val})" ++ val = "(((TOPDIR && TOPDIR.empty?) ? nil : TOPDIR) || DESTDIR + #{val})" + when /^ARCH_FLAG$/ + val = "arch_flag || #{val}" if universal + when /^UNIVERSAL_ARCHNAMES$/ +-- +1.9.0 + diff --git a/ruby-2.1.0-always-use-i386.patch b/ruby-2.1.0-always-use-i386.patch new file mode 100644 index 0000000..cde4302 --- /dev/null +++ b/ruby-2.1.0-always-use-i386.patch @@ -0,0 +1,25 @@ +From 2089cab72b38d6d5e7ba2b596e41014209acad30 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Mon, 19 Nov 2012 14:37:28 +0100 +Subject: [PATCH] Always use i386. + +--- + configure.ac | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/configure.ac b/configure.ac +index b77e88fc37..6bba453e3c 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3791,6 +3791,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 + ++target_cpu=`echo $target_cpu | sed s/i.86/i386/` ++ + AS_IF([test "${universal_binary-no}" = yes ], [ + arch="universal-${target_os}" + AS_IF([test "${rb_cv_architecture_available}" = yes], [ +-- +1.8.3.1 + diff --git a/ruby-2.1.0-custom-rubygems-location.patch b/ruby-2.1.0-custom-rubygems-location.patch new file mode 100644 index 0000000..d9b6915 --- /dev/null +++ b/ruby-2.1.0-custom-rubygems-location.patch @@ -0,0 +1,97 @@ +From 94da59aafacc6a9efe829529eb51385588d6f149 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Fri, 11 Nov 2011 13:14:45 +0100 +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(+) + +diff --git a/configure.ac b/configure.ac +index 6bba453e3c..028ef7ca3e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3763,6 +3763,10 @@ AC_ARG_WITH(vendorarchdir, + [vendorarchdir=$withval], + [vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby'${ruby_version_dir}}${multiarch-'${vendorlibdir}/${sitearch}'}]) + ++AC_ARG_WITH(rubygemsdir, ++ AS_HELP_STRING([--with-rubygemsdir=DIR], [custom rubygems directory]), ++ [rubygemsdir=$withval]) ++ + AS_IF([test "${LOAD_RELATIVE+set}"], [ + AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) + RUBY_EXEC_PREFIX='' +@@ -3787,6 +3787,7 @@ AC_SUBST(sitearchdir)dnl + AC_SUBST(vendordir)dnl + AC_SUBST(vendorlibdir)dnl + AC_SUBST(vendorarchdir)dnl ++AC_SUBST(rubygemsdir)dnl + + AC_SUBST(CONFIGURE, "`echo $0 | sed 's|.*/||'`")dnl + AC_SUBST(configure_args, "`echo "${ac_configure_args}" | sed 's/\\$/$$/g'`")dnl +diff --git a/loadpath.c b/loadpath.c +index 623dc9d..74c5d9e 100644 +--- a/loadpath.c ++++ b/loadpath.c +@@ -94,6 +94,10 @@ const char ruby_initial_load_paths[] = + #endif + #endif + ++#ifdef RUBYGEMS_DIR ++ RUBYGEMS_DIR "\0" ++#endif ++ + RUBY_LIB "\0" + #ifdef RUBY_THINARCH + RUBY_ARCH_LIB_FOR(RUBY_THINARCH) "\0" +diff --git a/template/verconf.h.tmpl b/template/verconf.h.tmpl +index 79c003e..34f2382 100644 +--- a/template/verconf.h.tmpl ++++ b/template/verconf.h.tmpl +@@ -36,6 +36,9 @@ + % if C["RUBY_SEARCH_PATH"] + #define RUBY_SEARCH_PATH "${RUBY_SEARCH_PATH}" + % end ++% if C["rubygemsdir"] ++#define RUBYGEMS_DIR "${rubygemsdir}" ++% end + % + % R = {} + % R["ruby_version"] = '"RUBY_LIB_VERSION"' +diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb +index d8987af..1efbd33 100755 +--- a/tool/rbinstall.rb ++++ b/tool/rbinstall.rb +@@ -338,6 +338,7 @@ if CONFIG["vendordir"] + vendorlibdir = CONFIG["vendorlibdir"] + vendorarchlibdir = CONFIG["vendorarchdir"] + end ++rubygemsdir = CONFIG["rubygemsdir"] + mandir = CONFIG["mandir", true] + docdir = CONFIG["docdir", true] + enable_shared = CONFIG["ENABLE_SHARED"] == 'yes' +@@ -564,7 +565,16 @@ end + 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 + 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) ++ 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 + + install?(:local, :comm, :hdr, :'comm-hdr') do +-- +1.8.3.1 + diff --git a/ruby-2.2.3-Generate-preludes-using-miniruby.patch b/ruby-2.2.3-Generate-preludes-using-miniruby.patch new file mode 100644 index 0000000..e8107d7 --- /dev/null +++ b/ruby-2.2.3-Generate-preludes-using-miniruby.patch @@ -0,0 +1,28 @@ +From 07eb5f5e775dec01a92a8b13910eaced9e8ee0cd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +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 +@@ -1053,9 +1053,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) + + $(GOLF_PRELUDE_C): $(COMPILE_PRELUDE) {$(srcdir)}golf_prelude.rb +-- +2.6.3 + diff --git a/ruby-2.3.0-ruby_version.patch b/ruby-2.3.0-ruby_version.patch new file mode 100644 index 0000000..e46915c --- /dev/null +++ b/ruby-2.3.0-ruby_version.patch @@ -0,0 +1,296 @@ +From 4fc1be3af3f58621bb751c9e63c208b15c0e8d16 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Tue, 31 Mar 2015 16:21:04 +0200 +Subject: [PATCH 1/4] Use ruby_version_dir_name for versioned directories. + +This disallows changing the ruby_version constant by --with-ruby-version +configuration options. The two places version numbers are disallowed as +well, since there are a lot of places which cannot handle this format +properly. + +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 ++++++++++++++++++++++++--------------------- + template/ruby.pc.in | 1 + + 2 files changed, 35 insertions(+), 30 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 8ea969412f..a00f2b6776 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3678,9 +3678,6 @@ AS_CASE(["$target_os"], + rubyw_install_name='$(RUBYW_INSTALL_NAME)' + ]) + +-rubylibdir='${rubylibprefix}/${ruby_version}' +-rubyarchdir=${multiarch+'${rubyarchprefix}/${ruby_version}'}${multiarch-'${rubylibdir}/${arch}'} +- + rubyarchprefix=${multiarch+'${archlibdir}/${RUBY_BASE_NAME}'}${multiarch-'${rubylibprefix}/${arch}'} + AC_ARG_WITH(rubyarchprefix, + AS_HELP_STRING([--with-rubyarchprefix=DIR], +@@ -3703,56 +3703,62 @@ AC_ARG_WITH(ridir, + AC_SUBST(ridir) + AC_SUBST(RI_BASE_NAME) + +-AC_ARG_WITH(ruby-version, +- AS_HELP_STRING([--with-ruby-version=STR], [ruby version string for version specific directories [[full]] (full|minor|STR)]), +- [ruby_version=$withval], +- [ruby_version=full]) + unset RUBY_LIB_VERSION +-unset RUBY_LIB_VERSION_STYLE +-AS_CASE(["$ruby_version"], +- [full], [RUBY_LIB_VERSION_STYLE='3 /* full */'], +- [minor], [RUBY_LIB_VERSION_STYLE='2 /* minor */']) +-AS_IF([test ${RUBY_LIB_VERSION_STYLE+set}], [ +- { +- echo "#define RUBY_LIB_VERSION_STYLE $RUBY_LIB_VERSION_STYLE" +- echo '#define STRINGIZE(x) x' +- test -f revision.h -o -f "${srcdir}/revision.h" || echo '#define RUBY_REVISION 0' +- echo '#include "version.h"' +- echo 'ruby_version=RUBY_LIB_VERSION' +- } > conftest.c +- ruby_version="`$CPP -I. -I"${srcdir}" -I"${srcdir}/include" conftest.c | sed '/^ruby_version=/!d;s/ //g'`" +- eval $ruby_version +-], [test -z "${ruby_version}"], [ +- AC_MSG_ERROR([No ruby version, No place for bundled libraries]) +-], [ +- RUBY_LIB_VERSION="${ruby_version}" +-]) ++RUBY_LIB_VERSION_STYLE='3 /* full */' ++{ ++echo "#define RUBY_LIB_VERSION_STYLE $RUBY_LIB_VERSION_STYLE" ++echo '#define STRINGIZE(x) x' ++test -f revision.h -o -f "${srcdir}/revision.h" || echo '#define RUBY_REVISION 0' ++echo '#include "version.h"' ++echo 'ruby_version=RUBY_LIB_VERSION' ++} > conftest.c ++ruby_version="`$CPP -I. -I"${srcdir}" -I"${srcdir}/include" conftest.c | sed '/^ruby_version=/!d;s/ //g'`" ++eval $ruby_version ++ ++RUBY_LIB_VERSION="${ruby_version}" ++ + AC_SUBST(RUBY_LIB_VERSION_STYLE) + AC_SUBST(RUBY_LIB_VERSION) + ++AC_ARG_WITH(ruby-version, ++ AS_HELP_STRING([--with-ruby-version=STR], [ruby version string for version specific directories [[full]] (full|STR)]), ++ [ruby_version_dir_name=$withval], ++ [ruby_version_dir_name=full]) ++AS_CASE(["$ruby_version_dir_name"], ++ [full], [ruby_version_dir_name='${ruby_version}']) ++ ++ruby_version_dir=/'${ruby_version_dir_name}' ++ ++if test -z "${ruby_version_dir_name}"; then ++ AC_MSG_ERROR([No ruby version, No place for bundled libraries]) ++fi ++ ++rubylibdir='${rubylibprefix}'${ruby_version_dir} ++rubyarchdir=${multiarch+'${rubyarchprefix}'${ruby_version_dir}}${multiarch-'${rubylibdir}/${arch}'} ++ + AC_ARG_WITH(sitedir, + AS_HELP_STRING([--with-sitedir=DIR], [site libraries in DIR [[RUBY_LIB_PREFIX/site_ruby]], "no" to disable site directory]), + [sitedir=$withval], + [sitedir='${rubylibprefix}/site_ruby']) +-sitelibdir='${sitedir}/${ruby_version}' ++sitelibdir='${sitedir}'${ruby_version_dir} + + AC_ARG_WITH(sitearchdir, + AS_HELP_STRING([--with-sitearchdir=DIR], + [architecture dependent site libraries in DIR [[SITEDIR/SITEARCH]], "no" to disable site directory]), + [sitearchdir=$withval], +- [sitearchdir=${multiarch+'${rubysitearchprefix}/site_ruby/${ruby_version}'}${multiarch-'${sitelibdir}/${sitearch}'}]) ++ [sitearchdir=${multiarch+'${rubysitearchprefix}/site_ruby'${ruby_version_dir}}${multiarch-'${sitelibdir}/${sitearch}'}]) + + AC_ARG_WITH(vendordir, + AS_HELP_STRING([--with-vendordir=DIR], [vendor libraries in DIR [[RUBY_LIB_PREFIX/vendor_ruby]], "no" to disable vendor directory]), + [vendordir=$withval], + [vendordir='${rubylibprefix}/vendor_ruby']) +-vendorlibdir='${vendordir}/${ruby_version}' ++vendorlibdir='${vendordir}'${ruby_version_dir} + + AC_ARG_WITH(vendorarchdir, + AS_HELP_STRING([--with-vendorarchdir=DIR], + [architecture dependent vendor libraries in DIR [[VENDORDIR/SITEARCH]], "no" to disable vendor directory]), + [vendorarchdir=$withval], +- [vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby/${ruby_version}'}${multiarch-'${vendorlibdir}/${sitearch}'}]) ++ [vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby'${ruby_version_dir}}${multiarch-'${vendorlibdir}/${sitearch}'}]) + + AS_IF([test "${LOAD_RELATIVE+set}"], [ + AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) +@@ -3769,6 +3769,7 @@ AC_SUBST(sitearchincludedir)dnl + AC_SUBST(arch)dnl + AC_SUBST(sitearch)dnl + AC_SUBST(ruby_version)dnl ++AC_SUBST(ruby_version_dir_name)dnl + AC_SUBST(rubylibdir)dnl + AC_SUBST(rubyarchdir)dnl + AC_SUBST(sitedir)dnl +diff --git a/template/ruby.pc.in b/template/ruby.pc.in +index 8a2c066..c81b211 100644 +--- a/template/ruby.pc.in ++++ b/template/ruby.pc.in +@@ -9,6 +9,7 @@ MAJOR=@MAJOR@ + MINOR=@MINOR@ + TEENY=@TEENY@ + ruby_version=@ruby_version@ ++ruby_version_dir_name=@ruby_version_dir_name@ + RUBY_API_VERSION=@RUBY_API_VERSION@ + RUBY_PROGRAM_VERSION=@RUBY_PROGRAM_VERSION@ + RUBY_BASE_NAME=@RUBY_BASE_NAME@ +-- +2.1.0 + + +From 518850aba6eee76de7715aae8d37330e34b01983 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Tue, 31 Mar 2015 16:37:26 +0200 +Subject: [PATCH 2/4] Add ruby_version_dir_name support for RDoc. + +--- + lib/rdoc/ri/paths.rb | 2 +- + tool/rbinstall.rb | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/rdoc/ri/paths.rb b/lib/rdoc/ri/paths.rb +index 970cb91..5bf8230 100644 +--- a/lib/rdoc/ri/paths.rb ++++ b/lib/rdoc/ri/paths.rb +@@ -10,7 +10,7 @@ module RDoc::RI::Paths + #:stopdoc: + require 'rbconfig' + +- version = RbConfig::CONFIG['ruby_version'] ++ version = RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_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 +@@ -428,7 +428,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) + end +-- +2.1.0 + + +From f8d136f9a46d1fe87eba622ab9665935d05e981b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +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 | 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 55ca080..75eea2b 100644 +--- a/lib/rubygems/defaults.rb ++++ b/lib/rubygems/defaults.rb +@@ -32,20 +32,20 @@ def self.default_dir + [ + File.dirname(RbConfig::CONFIG['sitedir']), + 'Gems', +- RbConfig::CONFIG['ruby_version'] ++ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] + ] + elsif RbConfig::CONFIG['rubylibprefix'] + [ + RbConfig::CONFIG['rubylibprefix'], + 'gems', +- RbConfig::CONFIG['ruby_version'] ++ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] + ] + else + [ + RbConfig::CONFIG['libdir'], + ruby_engine, + 'gems', +- RbConfig::CONFIG['ruby_version'] ++ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] + ] + end + +@@ -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 + +@@ -172,7 +173,7 @@ def self.vendor_dir # :nodoc: + return nil unless RbConfig::CONFIG.key? 'vendordir' + + File.join RbConfig::CONFIG['vendordir'], 'gems', +- RbConfig::CONFIG['ruby_version'] ++ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] + end + + ## +diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb +index 0428bea..b6e090e 100644 +--- a/test/rubygems/test_gem.rb ++++ b/test/rubygems/test_gem.rb +@@ -1288,7 +1288,8 @@ def test_self_use_paths + + def test_self_user_dir + parts = [@userhome, '.gem', 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? + + assert_equal File.join(parts), Gem.user_dir + end +@@ -1365,7 +1366,7 @@ def test_self_gzip + 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 + + +From 88c38a030c22dbf9422ece847bdfbf87d6659313 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Wed, 1 Apr 2015 14:55:37 +0200 +Subject: [PATCH 4/4] Let headers directories follow the configured version + name. + +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index a00f2b6776..999e2d6d5d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -101,7 +101,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}') + + AC_CANONICAL_TARGET + test x"$target_alias" = x && +-- +2.1.0 + diff --git a/ruby-2.6.0-config-support-include-directive.patch b/ruby-2.6.0-config-support-include-directive.patch new file mode 100644 index 0000000..5b2024b --- /dev/null +++ b/ruby-2.6.0-config-support-include-directive.patch @@ -0,0 +1,182 @@ +From f46bac1f3e8634e24c747d06b28e11b874f1e488 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 (\s*=\s*)?(.+)\z/ ++ path = $2 ++ 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 diff --git a/ruby-2.6.3-fiddle-1.0.0-ffi-closure-alloc-default.patch b/ruby-2.6.3-fiddle-1.0.0-ffi-closure-alloc-default.patch new file mode 100644 index 0000000..ec99472 --- /dev/null +++ b/ruby-2.6.3-fiddle-1.0.0-ffi-closure-alloc-default.patch @@ -0,0 +1,58 @@ +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,22 +13,11 @@ typedef struct { + ffi_type **argv; + } fiddle_closure; + +-#if defined(USE_FFI_CLOSURE_ALLOC) +-#elif !defined(HAVE_FFI_CLOSURE_ALLOC) +-# 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); + } +@@ -202,12 +188,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; + } +@@ -254,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); diff --git a/ruby-2.7.0-Initialize-ABRT-hook.patch b/ruby-2.7.0-Initialize-ABRT-hook.patch new file mode 100644 index 0000000..2b90d9e --- /dev/null +++ b/ruby-2.7.0-Initialize-ABRT-hook.patch @@ -0,0 +1,77 @@ +From eca084e4079c77c061045df9c21b219175b05228 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +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 +@@ -1489,10 +1489,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 + diff --git a/ruby-2.7.0-bundler-use-bundle-gem-instead-of-gem-command.patch b/ruby-2.7.0-bundler-use-bundle-gem-instead-of-gem-command.patch new file mode 100644 index 0000000..e5a8f77 --- /dev/null +++ b/ruby-2.7.0-bundler-use-bundle-gem-instead-of-gem-command.patch @@ -0,0 +1,107 @@ +From 745899dec8f28d50a37dc03a96bbea972caaef58 Mon Sep 17 00:00:00 2001 +From: SHIBATA Hiroshi +Date: Tue, 19 Feb 2019 22:41:56 +0900 +Subject: [PATCH] Use ENV["BUNDLE_GEM"] instead of gem command provided by + system ruby. + + It break the examples of bundler. Because some examples detect the + different version of system ruby than test target version like trunk. +--- + lib/bundler/gem_helper.rb | 8 ++++++-- + spec/bundler/commands/clean_spec.rb | 14 +++++++++----- + spec/bundler/support/rubygems_ext.rb | 7 ++----- + 3 files changed, 17 insertions(+), 12 deletions(-) + +diff --git a/lib/bundler/gem_helper.rb b/lib/bundler/gem_helper.rb +index e7673cba88..c54259b5b6 100644 +--- a/lib/bundler/gem_helper.rb ++++ b/lib/bundler/gem_helper.rb +@@ -74,7 +74,8 @@ def install + + def build_gem + file_name = nil +- sh("gem build -V '#{spec_path}'") do ++ gem = ENV["BUNDLE_GEM"] ? ENV["BUNDLE_GEM"] : "gem" ++ sh("#{gem} build -V #{spec_path}") do + file_name = File.basename(built_gem_path) + SharedHelpers.filesystem_access(File.join(base, "pkg")) {|p| FileUtils.mkdir_p(p) } + FileUtils.mv(built_gem_path, "pkg") +@@ -85,7 +86,10 @@ def build_gem + + def install_gem(built_gem_path = nil, local = false) + built_gem_path ||= build_gem +- out, _ = sh_with_code("gem install '#{built_gem_path}'#{" --local" if local}") ++ gem = ENV["BUNDLE_GEM"] ? ENV["BUNDLE_GEM"] : "gem" ++ cmd = "#{gem} install #{built_gem_path}" ++ cmd = "#{cmd} --local" if local ++ out, _ = sh_with_code(cmd) + raise "Couldn't install gem, run `gem install #{built_gem_path}' for more detailed output" unless out[/Successfully installed/] + Bundler.ui.confirm "#{name} (#{version}) installed." + end +diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb +index 37cbeeb4e7..74a5b86ec1 100644 +--- a/spec/bundler/commands/clean_spec.rb ++++ b/spec/bundler/commands/clean_spec.rb +@@ -339,7 +339,8 @@ def should_not_have_gems(*gems) + gem "rack" + G + +- sys_exec! "gem list" ++ gem = ruby_core? ? ENV["BUNDLE_GEM"] : "gem" ++ sys_exec! "#{gem} list" + expect(out).to include("rack (1.0.0)").and include("thin (1.0)") + end + +@@ -461,8 +462,9 @@ def should_not_have_gems(*gems) + end + bundle! :update, :all => bundle_update_requires_all? + +- sys_exec! "gem list" +- expect(out).to include("foo (1.0.1, 1.0)") ++ gem = ruby_core? ? ENV["BUNDLE_GEM"] : "gem" ++ sys_exec! "#{gem} list" ++ expect(out).to include("foo (1.0.1, 1.0)") + end + + it "cleans system gems when --force is used" do +@@ -485,7 +487,8 @@ def should_not_have_gems(*gems) + bundle "clean --force" + + expect(out).to include("Removing foo (1.0)") +- sys_exec "gem list" ++ gem = ruby_core? ? ENV["BUNDLE_GEM"] : "gem" ++ sys_exec "#{gem} list" + expect(out).not_to include("foo (1.0)") + expect(out).to include("rack (1.0.0)") + end +@@ -519,7 +522,8 @@ def should_not_have_gems(*gems) + expect(out).to include(system_gem_path.to_s) + expect(out).to include("grant write permissions") + +- sys_exec "gem list" ++ gem = ruby_core? ? ENV["BUNDLE_GEM"] : "gem" ++ sys_exec "#{gem} list" + expect(out).to include("foo (1.0)") + expect(out).to include("rack (1.0.0)") + end +diff --git a/spec/bundler/support/rubygems_ext.rb b/spec/bundler/support/rubygems_ext.rb +index c18f7650fc..408d715ecf 100644 +--- a/spec/bundler/support/rubygems_ext.rb ++++ b/spec/bundler/support/rubygems_ext.rb +@@ -59,11 +59,8 @@ def self.install_gems(gems) + no_reqs.map!(&:first) + reqs.map! {|name, req| "'#{name}:#{req}'" } + deps = reqs.concat(no_reqs).join(" ") +- cmd = if Gem::VERSION < "2.0.0" +- "gem install #{deps} --no-rdoc --no-ri --conservative" +- else +- "gem install #{deps} --no-document --conservative" +- end ++ gem = Spec::Path.ruby_core? ? ENV["BUNDLE_GEM"] : "#{Gem.ruby} -S gem" ++ cmd = "#{gem} install #{deps} --no-document --conservative" + puts cmd + system(cmd) || raise("Installing gems #{deps} for the tests to use failed!") + end +-- +2.31.1 + diff --git a/ruby-2.7.0-preview1-IO.select-on-all-platforms-to-wait-for-input-with-recvfr.patch b/ruby-2.7.0-preview1-IO.select-on-all-platforms-to-wait-for-input-with-recvfr.patch new file mode 100644 index 0000000..f5d01ce --- /dev/null +++ b/ruby-2.7.0-preview1-IO.select-on-all-platforms-to-wait-for-input-with-recvfr.patch @@ -0,0 +1,131 @@ +From 920b924e5652884064a9529ffbd80d458a46fbc6 Mon Sep 17 00:00:00 2001 +From: eregon +Date: Tue, 5 Feb 2019 09:58:50 +0000 +Subject: [PATCH] Make sure to wait with IO.select before using + Socket#recvfrom_nonblock + +* On all platforms, as this is the recommended code pattern. + +git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67010 b2dd03c8-39d4-4d8f-98ff-823fe69b080e +--- + spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb +index c1239ae637e0..74fd286c42ad 100644 +--- a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb ++++ b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb +@@ -36,12 +36,11 @@ + describe 'with data available' do + before do + @client.write('hello') +- +- platform_is(:darwin, :freebsd) { IO.select([@server]) } + end + + platform_is_not :windows do + it 'returns an Array containing the data and an Addrinfo' do ++ IO.select([@server]) + ret = @server.recvfrom_nonblock(1) + + ret.should be_an_instance_of(Array) +@@ -54,8 +53,7 @@ + 5.times do + @client.write('hello') + +- platform_is(:darwin, :freebsd) { IO.select([@server]) } +- ++ IO.select([@server]) + msg, _ = @server.recvfrom_nonblock(5) + + msg.should == 'hello' +@@ -66,6 +64,7 @@ + platform_is_not :windows do + describe 'the returned Array' do + before do ++ IO.select([@server]) + @array = @server.recvfrom_nonblock(1) + end + +@@ -80,6 +79,7 @@ + + describe 'the returned Addrinfo' do + before do ++ IO.select([@server]) + @addr = @server.recvfrom_nonblock(1)[1] + end + +From c1f0daeb6ac5c5414c9a4a58bb778a118006ae1f Mon Sep 17 00:00:00 2001 +From: eregon +Date: Tue, 5 Feb 2019 10:19:29 +0000 +Subject: [PATCH] Make sure to wait with IO.select before using + Socket#accept_nonblock and recvfrom_nonblock + +* On all platforms, as this is the recommended code pattern. + +git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67011 b2dd03c8-39d4-4d8f-98ff-823fe69b080e +--- + spec/ruby/library/socket/socket/accept_nonblock_spec.rb | 4 ++-- + spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb | 5 +++-- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/spec/ruby/library/socket/socket/accept_nonblock_spec.rb b/spec/ruby/library/socket/socket/accept_nonblock_spec.rb +index 3ef219ed05a9..cde9e6a4b669 100644 +--- a/spec/ruby/library/socket/socket/accept_nonblock_spec.rb ++++ b/spec/ruby/library/socket/socket/accept_nonblock_spec.rb +@@ -86,8 +86,6 @@ + @client = Socket.new(family, :STREAM, 0) + + @client.connect(addr) +- +- platform_is(:darwin, :freebsd, :solaris) { IO.select([@server]) } + end + + after do +@@ -96,6 +94,7 @@ + end + + it 'returns an Array containing a Socket and an Addrinfo' do ++ IO.select([@server]) + @socket, addrinfo = @server.accept_nonblock + + @socket.should be_an_instance_of(Socket) +@@ -104,6 +103,7 @@ + + describe 'the returned Addrinfo' do + before do ++ IO.select([@server]) + @socket, @addr = @server.accept_nonblock + end + +diff --git a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb +index 015109a05200..62bbaf0dc93a 100644 +--- a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb ++++ b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb +@@ -40,16 +40,16 @@ + describe 'with data available' do + before do + @client.write('hello') +- +- platform_is(:darwin, :freebsd) { IO.select([@server]) } + end + + it 'returns an Array containing the data and an Array' do ++ IO.select([@server]) + @server.recvfrom_nonblock(1).should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do ++ IO.select([@server]) + @array = @server.recvfrom_nonblock(1) + end + +@@ -64,6 +64,7 @@ + + describe 'the returned address Array' do + before do ++ IO.select([@server]) + @addr = @server.recvfrom_nonblock(1)[1] + end + diff --git a/ruby-2.7.0-update-location-of-bundler-gemspec.patch b/ruby-2.7.0-update-location-of-bundler-gemspec.patch new file mode 100644 index 0000000..0e4d9f8 --- /dev/null +++ b/ruby-2.7.0-update-location-of-bundler-gemspec.patch @@ -0,0 +1,37 @@ +From 8cca079d3be8d07c261baea72529628469938245 Mon Sep 17 00:00:00 2001 +From: hsbt +Date: Sat, 2 Feb 2019 10:41:22 +0000 +Subject: [PATCH] Fixup r66984. Update the location of bundler gemspec. + +git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66993 b2dd03c8-39d4-4d8f-98ff-823fe69b080e +--- + spec/bundler/support/path.rb | 2 +- + tool/sync_default_gems.rb | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb +index 38f7145dc72a..69efcba05175 100644 +--- a/spec/bundler/support/path.rb ++++ b/spec/bundler/support/path.rb +@@ -9,7 +9,7 @@ def root + end + + def gemspec +- @gemspec ||= root.join(ruby_core? ? "lib/bundler.gemspec" : "bundler.gemspec") ++ @gemspec ||= root.join(ruby_core? ? "lib/bundler/bundler.gemspec" : "bundler.gemspec") + end + + def bindir +diff --git a/tool/sync_default_gems.rb b/tool/sync_default_gems.rb +index bb4fcdd2cc12..26458147e5a3 100644 +--- a/tool/sync_default_gems.rb ++++ b/tool/sync_default_gems.rb +@@ -89,7 +89,7 @@ def sync_default_gems(gem) + `rm -rf lib/bundler* libexec/bundler libexec/bundle libexec/bundle_ruby spec/bundler man/bundle* man/gemfile*` + `cp -r ../../bundler/bundler/lib/bundler* ./lib` + `cp -r ../../bundler/bundler/exe/bundle* ./libexec` +- `cp ../../bundler/bundler/bundler.gemspec ./lib` ++ `cp ../../bundler/bundler/bundler.gemspec ./lib/bundler` + `cp -r ../../bundler/bundler/spec spec/bundler` + `cp -r ../../bundler/bundler/man/*.{1,5,1\.txt,5\.txt,ronn} ./man` + `rm -rf spec/bundler/support/artifice/vcr_cassettes` diff --git a/ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch b/ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch new file mode 100644 index 0000000..64e2114 --- /dev/null +++ b/ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch @@ -0,0 +1,34 @@ +From 9b42fce32bff25e0569581f76f532b9d57865aef Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +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 + diff --git a/ruby-3.0.0-Convert-ip-addresses-to-canonical-form.patch b/ruby-3.0.0-Convert-ip-addresses-to-canonical-form.patch new file mode 100644 index 0000000..99b0430 --- /dev/null +++ b/ruby-3.0.0-Convert-ip-addresses-to-canonical-form.patch @@ -0,0 +1,26 @@ +From 2becb920e431110c4afc4fa069b051c5940c2096 Mon Sep 17 00:00:00 2001 +From: Jeremy Evans +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 +@@ -762,6 +762,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 diff --git a/ruby-3.0.3-ext-openssl-extconf.rb-require-OpenSSL-version-1.0.1.patch b/ruby-3.0.3-ext-openssl-extconf.rb-require-OpenSSL-version-1.0.1.patch new file mode 100644 index 0000000..4b8e9ab --- /dev/null +++ b/ruby-3.0.3-ext-openssl-extconf.rb-require-OpenSSL-version-1.0.1.patch @@ -0,0 +1,84 @@ +From 202ff1372a40a8adf9aac74bfe8a39141b0c57e5 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 27 Sep 2021 00:38:38 +0900 +Subject: [PATCH] ext/openssl/extconf.rb: require OpenSSL version >= 1.0.1, < 3 + +Ruby/OpenSSL 2.1.x and 2.2.x will not support OpenSSL 3.0 API. Let's +make extconf.rb explicitly check the version number to be within the +acceptable range, since it will not compile anyway. + +Reference: https://bugs.ruby-lang.org/issues/18192 +--- + ext/openssl/extconf.rb | 43 ++++++++++++++++++++++++------------------ + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index 264130bb..7e817ae2 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -33,9 +33,6 @@ + have_library("ws2_32") + end + +-Logging::message "=== Checking for required stuff... ===\n" +-result = pkg_config("openssl") && have_header("openssl/ssl.h") +- + if $mingw + append_cflags '-D_FORTIFY_SOURCE=2' + append_ldflags '-fstack-protector' +@@ -92,19 +89,33 @@ def find_openssl_library + return false + end + +-unless result +- unless find_openssl_library +- Logging::message "=== Checking for required stuff failed. ===\n" +- Logging::message "Makefile wasn't created. Fix the errors above.\n" +- raise "OpenSSL library could not be found. You might want to use " \ +- "--with-openssl-dir= option to specify the prefix where OpenSSL " \ +- "is installed." +- end ++Logging::message "=== Checking for required stuff... ===\n" ++pkg_config_found = pkg_config("openssl") && have_header("openssl/ssl.h") ++ ++if !pkg_config_found && !find_openssl_library ++ Logging::message "=== Checking for required stuff failed. ===\n" ++ Logging::message "Makefile wasn't created. Fix the errors above.\n" ++ raise "OpenSSL library could not be found. You might want to use " \ ++ "--with-openssl-dir= option to specify the prefix where OpenSSL " \ ++ "is installed." + end + +-unless checking_for("OpenSSL version is 1.0.1 or later") { +- try_static_assert("OPENSSL_VERSION_NUMBER >= 0x10001000L", "openssl/opensslv.h") } +- raise "OpenSSL >= 1.0.1 or LibreSSL is required" ++version_ok = if have_macro("LIBRESSL_VERSION_NUMBER", "openssl/opensslv.h") ++ is_libressl = true ++ checking_for("LibreSSL version >= 2.5.0") { ++ try_static_assert("LIBRESSL_VERSION_NUMBER >= 0x20500000L", "openssl/opensslv.h") } ++else ++ checking_for("OpenSSL version >= 1.0.1 and < 3.0.0") { ++ try_static_assert("OPENSSL_VERSION_NUMBER >= 0x10001000L", "openssl/opensslv.h") && ++ !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" ++end ++ ++# Prevent wincrypt.h from being included, which defines conflicting macro with openssl/x509.h ++if is_libressl && ($mswin || $mingw) ++ $defs.push("-DNOCRYPT") + end + + Logging::message "=== Checking for OpenSSL features... ===\n" +@@ -116,10 +127,6 @@ def find_openssl_library + have_func("ENGINE_load_#{name}()", "openssl/engine.h") + } + +-if ($mswin || $mingw) && have_macro("LIBRESSL_VERSION_NUMBER", "openssl/opensslv.h") +- $defs.push("-DNOCRYPT") +-end +- + # added in 1.0.2 + have_func("EC_curve_nist2nid") + have_func("X509_REVOKED_dup") diff --git a/ruby-3.0.3-fiddle-1.0.8-Rely-on-hard-coded-lib-name-to-detect-glibc.patch b/ruby-3.0.3-fiddle-1.0.8-Rely-on-hard-coded-lib-name-to-detect-glibc.patch new file mode 100644 index 0000000..3fa0747 --- /dev/null +++ b/ruby-3.0.3-fiddle-1.0.8-Rely-on-hard-coded-lib-name-to-detect-glibc.patch @@ -0,0 +1,25 @@ +From a267a40be7844224c5f000530bd3e8e906f1acea Mon Sep 17 00:00:00 2001 +From: Jeremy Evans +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' diff --git a/ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch b/ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch new file mode 100644 index 0000000..cede1aa --- /dev/null +++ b/ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch @@ -0,0 +1,1004 @@ +From 6bbdaef1a578fdbfc6a5bf82402ba4d3fd733d4a Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 21 Mar 2017 18:23:53 +0900 +Subject: [PATCH 1/6] pkey: assume generic PKeys contain private components + +The EVP interface cannot tell whether if a pkey contains the private +components or not. Assume it does if it does not respond to #private?. +This fixes the NoMethodError on calling #sign on a generic PKey. +--- + ext/openssl/ossl_pkey.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 610a83fd2d..8d41623e80 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -252,12 +252,19 @@ GetPrivPKeyPtr(VALUE obj) + { + EVP_PKEY *pkey; + +- if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) { +- ossl_raise(rb_eArgError, "Private key is needed."); +- } + GetPKey(obj, pkey); ++ if (OSSL_PKEY_IS_PRIVATE(obj)) ++ return pkey; ++ /* ++ * The EVP API does not provide a way to check if the EVP_PKEY has private ++ * components. Assuming it does... ++ */ ++ if (!rb_respond_to(obj, id_private_q)) ++ return pkey; ++ if (RTEST(rb_funcallv(obj, id_private_q, 0, NULL))) ++ return pkey; + +- return pkey; ++ rb_raise(rb_eArgError, "private key is needed"); + } + + EVP_PKEY * +-- +2.32.0 + + +From 86508f74b3d41166ed6091b7b31f18a26478c347 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 20 Mar 2017 23:18:26 +0900 +Subject: [PATCH 2/6] pkey: add PKey.generate_parameters and .generate_key + +Add two methods to create a PKey using the generic EVP interface. This +is useful for the PKey types we don't have a dedicated class. +--- + ext/openssl/ossl_pkey.c | 222 ++++++++++++++++++++++++++++++++++++++ + test/openssl/test_pkey.rb | 43 ++++++++ + 2 files changed, 265 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 8d41623e80..1f3dd39b9b 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -197,6 +197,226 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) + return ossl_pkey_new(pkey); + } + ++static VALUE ++pkey_gen_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; ++ ++ if (SYMBOL_P(key)) ++ key = rb_sym2str(key); ++ value = rb_String(value); ++ ++ if (EVP_PKEY_CTX_ctrl_str(ctx, StringValueCStr(key), StringValueCStr(value)) <= 0) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_ctrl_str(ctx, %+"PRIsVALUE", %+"PRIsVALUE")", ++ key, value); ++ return Qnil; ++} ++ ++static VALUE ++pkey_gen_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]); ++ return Qnil; ++} ++ ++struct pkey_blocking_generate_arg { ++ EVP_PKEY_CTX *ctx; ++ EVP_PKEY *pkey; ++ int state; ++ int yield: 1; ++ int genparam: 1; ++ int stop: 1; ++}; ++ ++static VALUE ++pkey_gen_cb_yield(VALUE ctx_v) ++{ ++ EVP_PKEY_CTX *ctx = (void *)ctx_v; ++ int i, info_num; ++ VALUE *argv; ++ ++ info_num = EVP_PKEY_CTX_get_keygen_info(ctx, -1); ++ argv = ALLOCA_N(VALUE, info_num); ++ for (i = 0; i < info_num; i++) ++ argv[i] = INT2NUM(EVP_PKEY_CTX_get_keygen_info(ctx, i)); ++ ++ return rb_yield_values2(info_num, argv); ++} ++ ++static int ++pkey_gen_cb(EVP_PKEY_CTX *ctx) ++{ ++ struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx); ++ ++ if (arg->yield) { ++ int state; ++ rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state); ++ if (state) { ++ arg->stop = 1; ++ arg->state = state; ++ } ++ } ++ return !arg->stop; ++} ++ ++static void ++pkey_blocking_gen_stop(void *ptr) ++{ ++ struct pkey_blocking_generate_arg *arg = ptr; ++ arg->stop = 1; ++} ++ ++static void * ++pkey_blocking_gen(void *ptr) ++{ ++ struct pkey_blocking_generate_arg *arg = ptr; ++ ++ if (arg->genparam && EVP_PKEY_paramgen(arg->ctx, &arg->pkey) <= 0) ++ return NULL; ++ if (!arg->genparam && EVP_PKEY_keygen(arg->ctx, &arg->pkey) <= 0) ++ return NULL; ++ return arg->pkey; ++} ++ ++static VALUE ++pkey_generate(int argc, VALUE *argv, VALUE self, int genparam) ++{ ++ EVP_PKEY_CTX *ctx; ++ VALUE alg, options; ++ struct pkey_blocking_generate_arg gen_arg = { 0 }; ++ int state; ++ ++ rb_scan_args(argc, argv, "11", &alg, &options); ++ if (rb_obj_is_kind_of(alg, cPKey)) { ++ EVP_PKEY *base_pkey; ++ ++ GetPKey(alg, base_pkey); ++ ctx = EVP_PKEY_CTX_new(base_pkey, NULL/* engine */); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ } ++ else { ++ const EVP_PKEY_ASN1_METHOD *ameth; ++ ENGINE *tmpeng; ++ int pkey_id; ++ ++ StringValue(alg); ++ ameth = EVP_PKEY_asn1_find_str(&tmpeng, RSTRING_PTR(alg), ++ RSTRING_LENINT(alg)); ++ if (!ameth) ++ ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", alg); ++ EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); ++#if !defined(OPENSSL_NO_ENGINE) ++ if (tmpeng) ++ ENGINE_finish(tmpeng); ++#endif ++ ++ ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id"); ++ } ++ ++ if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_paramgen_init"); ++ } ++ if (!genparam && EVP_PKEY_keygen_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_keygen_init"); ++ } ++ ++ if (!NIL_P(options)) { ++ VALUE args[2]; ++ ++ args[0] = (VALUE)ctx; ++ args[1] = options; ++ rb_protect(pkey_gen_apply_options0, (VALUE)args, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ ++ gen_arg.genparam = genparam; ++ gen_arg.ctx = ctx; ++ gen_arg.yield = rb_block_given_p(); ++ EVP_PKEY_CTX_set_app_data(ctx, &gen_arg); ++ EVP_PKEY_CTX_set_cb(ctx, pkey_gen_cb); ++ if (gen_arg.yield) ++ pkey_blocking_gen(&gen_arg); ++ else ++ rb_thread_call_without_gvl(pkey_blocking_gen, &gen_arg, ++ pkey_blocking_gen_stop, &gen_arg); ++ EVP_PKEY_CTX_free(ctx); ++ if (!gen_arg.pkey) { ++ if (gen_arg.state) { ++ ossl_clear_error(); ++ rb_jump_tag(gen_arg.state); ++ } ++ else { ++ ossl_raise(ePKeyError, genparam ? "EVP_PKEY_paramgen" : "EVP_PKEY_keygen"); ++ } ++ } ++ ++ return ossl_pkey_new(gen_arg.pkey); ++} ++ ++/* ++ * call-seq: ++ * OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey ++ * ++ * Generates new parameters for the algorithm. _algo_name_ is a String that ++ * represents the algorithm. The optional argument _options_ is a Hash that ++ * specifies the options specific to the algorithm. The order of the options ++ * can be important. ++ * ++ * A block can be passed optionally. The meaning of the arguments passed to ++ * the block varies depending on the implementation of the algorithm. The block ++ * may be called once or multiple times, or may not even be called. ++ * ++ * For the supported options, see the documentation for the 'openssl genpkey' ++ * utility command. ++ * ++ * == Example ++ * pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048) ++ * p pkey.p.num_bits #=> 2048 ++ */ ++static VALUE ++ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self) ++{ ++ return pkey_generate(argc, argv, self, 1); ++} ++ ++/* ++ * call-seq: ++ * OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey ++ * OpenSSL::PKey.generate_key(pkey [, options]) -> pkey ++ * ++ * Generates a new key (pair). ++ * ++ * If a String is given as the first argument, it generates a new random key ++ * for the algorithm specified by the name just as ::generate_parameters does. ++ * If an OpenSSL::PKey::PKey is given instead, it generates a new random key ++ * for the same algorithm as the key, using the parameters the key contains. ++ * ++ * See ::generate_parameters for the details of _options_ and the given block. ++ * ++ * == Example ++ * pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048) ++ * pkey_params.priv_key #=> nil ++ * pkey = OpenSSL::PKey.generate_key(pkey_params) ++ * pkey.priv_key #=> # 512, ++ "dsa_paramgen_q_bits" => 256, ++ }) ++ 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 ++ ++ # Invalid options are checked ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ OpenSSL::PKey.generate_parameters("DSA", "invalid" => "option") ++ } ++ ++ # Parameter generation callback is called ++ cb_called = [] ++ assert_raise(RuntimeError) { ++ OpenSSL::PKey.generate_parameters("DSA") { |*args| ++ cb_called << args ++ raise "exit!" if cb_called.size == 3 ++ } ++ } ++ assert_not_empty cb_called ++ end ++ ++ def test_s_generate_key ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ # 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 = 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 ++ end + end +-- +2.32.0 + + +From 5713605e70c96e3215aab0e0341548af29b5088e Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 15 May 2017 23:47:47 +0900 +Subject: [PATCH 3/6] pkey: port PKey::PKey#sign and #verify to the EVP_Digest* + interface + +Use EVP_DigestSign*() and EVP_DigestVerify*() interface instead of the +old EVP_Sign*() and EVP_Verify*() functions. They were added in OpenSSL +1.0.0. + +Also, allow the digest to be specified as nil, as certain EVP_PKEY types +don't expect a digest algorithm. +--- + ext/openssl/ossl_pkey.c | 90 ++++++++++++++++++++++----------------- + test/openssl/test_pkey.rb | 12 ++++++ + 2 files changed, 63 insertions(+), 39 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 1f3dd39b9b..a0d73f5821 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -753,35 +753,47 @@ static VALUE + ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + { + EVP_PKEY *pkey; +- const EVP_MD *md; ++ const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; +- unsigned int buf_len; +- VALUE str; +- int result; ++ size_t siglen; ++ int state; ++ VALUE sig; + + pkey = GetPrivPKeyPtr(self); +- md = ossl_evp_get_digestbyname(digest); ++ if (!NIL_P(digest)) ++ md = ossl_evp_get_digestbyname(digest); + StringValue(data); +- str = rb_str_new(0, EVP_PKEY_size(pkey)); + + ctx = EVP_MD_CTX_new(); + if (!ctx) +- ossl_raise(ePKeyError, "EVP_MD_CTX_new"); +- if (!EVP_SignInit_ex(ctx, md, NULL)) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_SignInit_ex"); ++ ossl_raise(ePKeyError, "EVP_MD_CTX_new"); ++ if (EVP_DigestSignInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignInit"); ++ } ++ if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignUpdate"); ++ } ++ if (EVP_DigestSignFinal(ctx, NULL, &siglen) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignFinal"); + } +- if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_SignUpdate"); ++ if (siglen > LONG_MAX) ++ rb_raise(ePKeyError, "signature would be too large"); ++ sig = ossl_str_new(NULL, (long)siglen, &state); ++ if (state) { ++ EVP_MD_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(sig), ++ &siglen) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignFinal"); + } +- result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey); + EVP_MD_CTX_free(ctx); +- if (!result) +- ossl_raise(ePKeyError, "EVP_SignFinal"); +- rb_str_set_len(str, buf_len); +- +- return str; ++ rb_str_set_len(sig, siglen); ++ return sig; + } + + /* +@@ -809,38 +821,38 @@ static VALUE + ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + { + EVP_PKEY *pkey; +- const EVP_MD *md; ++ const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; +- int siglen, result; ++ int ret; + + GetPKey(self, pkey); + ossl_pkey_check_public_key(pkey); +- md = ossl_evp_get_digestbyname(digest); ++ if (!NIL_P(digest)) ++ md = ossl_evp_get_digestbyname(digest); + StringValue(sig); +- siglen = RSTRING_LENINT(sig); + StringValue(data); + + ctx = EVP_MD_CTX_new(); + if (!ctx) +- ossl_raise(ePKeyError, "EVP_MD_CTX_new"); +- if (!EVP_VerifyInit_ex(ctx, md, NULL)) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_VerifyInit_ex"); ++ ossl_raise(ePKeyError, "EVP_MD_CTX_new"); ++ if (EVP_DigestVerifyInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestVerifyInit"); + } +- if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_VerifyUpdate"); ++ if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate"); + } +- result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey); ++ ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), ++ RSTRING_LEN(sig)); + EVP_MD_CTX_free(ctx); +- switch (result) { +- case 0: +- ossl_clear_error(); +- return Qfalse; +- case 1: +- return Qtrue; +- default: +- ossl_raise(ePKeyError, "EVP_VerifyFinal"); ++ if (ret < 0) ++ ossl_raise(ePKeyError, "EVP_DigestVerifyFinal"); ++ if (ret) ++ return Qtrue; ++ else { ++ ossl_clear_error(); ++ return Qfalse; + } + } + +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index a325a1ea2b..247ba84f83 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -68,4 +68,16 @@ def test_s_generate_key + assert_equal 512, pkey.p.num_bits + assert_not_equal nil, pkey.priv_key + end ++ ++ def test_hmac_sign_verify ++ pkey = OpenSSL::PKey.generate_key("HMAC", { "key" => "abcd" }) ++ ++ hmac = OpenSSL::HMAC.new("abcd", "SHA256").update("data").digest ++ assert_equal hmac, pkey.sign("SHA256", "data") ++ ++ # EVP_PKEY_HMAC does not support verify ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ pkey.verify("SHA256", "data", hmac) ++ } ++ end + end +-- +2.32.0 + + +From 76566a2e1bab42a2e1587ecbec23779ee00020fc Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 15 May 2017 23:47:47 +0900 +Subject: [PATCH 4/6] pkey: support 'one-shot' signing and verification + +OpenSSL 1.1.1 added EVP_DigestSign() and EVP_DigestVerify() functions +to the interface. Some EVP_PKEY methods such as PureEdDSA algorithms +do not support the streaming mechanism and require us to use them. +--- + ext/openssl/ossl_pkey.c | 30 ++++++++++++++++++++++++++ + test/openssl/test_pkey.rb | 45 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 75 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index a0d73f5821..19544ec7f0 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -771,6 +771,26 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignInit"); + } ++#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER) ++ if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSign"); ++ } ++ if (siglen > LONG_MAX) ++ rb_raise(ePKeyError, "signature would be too large"); ++ sig = ossl_str_new(NULL, (long)siglen, &state); ++ if (state) { ++ EVP_MD_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSign"); ++ } ++#else + if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignUpdate"); +@@ -791,6 +811,7 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignFinal"); + } ++#endif + EVP_MD_CTX_free(ctx); + rb_str_set_len(sig, siglen); + return sig; +@@ -839,6 +860,14 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestVerifyInit"); + } ++#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), ++ RSTRING_LEN(data)); ++ EVP_MD_CTX_free(ctx); ++ if (ret < 0) ++ ossl_raise(ePKeyError, "EVP_DigestVerify"); ++#else + if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate"); +@@ -848,6 +877,7 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + EVP_MD_CTX_free(ctx); + if (ret < 0) + ossl_raise(ePKeyError, "EVP_DigestVerifyFinal"); ++#endif + if (ret) + return Qtrue; + else { +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index 247ba84f83..d811b9c75f 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -80,4 +80,49 @@ def test_hmac_sign_verify + pkey.verify("SHA256", "data", hmac) + } + end ++ ++ def test_ed25519 ++ # Test vector from RFC 8032 Section 7.1 TEST 2 ++ priv_pem = <<~EOF ++ -----BEGIN PRIVATE KEY----- ++ MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 ++ -----END PRIVATE KEY----- ++ EOF ++ pub_pem = <<~EOF ++ -----BEGIN PUBLIC KEY----- ++ MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= ++ -----END PUBLIC KEY----- ++ EOF ++ begin ++ priv = OpenSSL::PKey.read(priv_pem) ++ pub = OpenSSL::PKey.read(pub_pem) ++ rescue OpenSSL::PKey::PKeyError ++ # OpenSSL < 1.1.1 ++ pend "Ed25519 is not implemented" ++ end ++ assert_instance_of OpenSSL::PKey::PKey, priv ++ assert_instance_of OpenSSL::PKey::PKey, pub ++ assert_equal priv_pem, priv.private_to_pem ++ assert_equal pub_pem, priv.public_to_pem ++ assert_equal pub_pem, pub.public_to_pem ++ ++ sig = [<<~EOF.gsub(/[^0-9a-f]/, "")].pack("H*") ++ 92a009a9f0d4cab8720e820b5f642540 ++ a2b27b5416503f8fb3762223ebdb69da ++ 085ac1e43e15996e458f3613d0f11d8c ++ 387b2eaeb4302aeeb00d291612bb0c00 ++ EOF ++ data = ["72"].pack("H*") ++ assert_equal sig, priv.sign(nil, data) ++ assert_equal true, priv.verify(nil, sig, data) ++ assert_equal true, pub.verify(nil, sig, data) ++ assert_equal false, pub.verify(nil, sig, data.succ) ++ ++ # PureEdDSA wants nil as the message digest ++ assert_raise(OpenSSL::PKey::PKeyError) { priv.sign("SHA512", data) } ++ assert_raise(OpenSSL::PKey::PKeyError) { pub.verify("SHA512", sig, data) } ++ ++ # Ed25519 pkey type does not support key derivation ++ assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) } ++ end + end +-- +2.32.0 + + +From fabdd22bddc572ba3342ec0b09e3fef8ed6245b8 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 18 Mar 2017 21:58:46 +0900 +Subject: [PATCH 5/6] pkey: add PKey::PKey#derive + +Add OpenSSL::PKey::PKey#derive as the wrapper for EVP_PKEY_CTX_derive(). +This is useful for pkey types that we don't have dedicated classes, such +as X25519. +--- + ext/openssl/ossl_pkey.c | 52 ++++++++++++++++++++++++++++++++++++ + test/openssl/test_pkey.rb | 26 ++++++++++++++++++ + test/openssl/test_pkey_dh.rb | 13 +++++++++ + test/openssl/test_pkey_ec.rb | 16 +++++++++++ + 4 files changed, 107 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 19544ec7f0..df8b425a0f 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -886,6 +886,57 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + } + } + ++/* ++ * call-seq: ++ * pkey.derive(peer_pkey) -> string ++ * ++ * Derives a shared secret from _pkey_ and _peer_pkey_. _pkey_ must contain ++ * the private components, _peer_pkey_ must contain the public components. ++ */ ++static VALUE ++ossl_pkey_derive(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey, *peer_pkey; ++ EVP_PKEY_CTX *ctx; ++ VALUE peer_pkey_obj, str; ++ size_t keylen; ++ int state; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "1", &peer_pkey_obj); ++ GetPKey(peer_pkey_obj, peer_pkey); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_derive_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive_init"); ++ } ++ if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer"); ++ } ++ if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive"); ++ } ++ if (keylen > LONG_MAX) ++ rb_raise(ePKeyError, "derived key would be too large"); ++ str = ossl_str_new(NULL, (long)keylen, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive"); ++ } ++ EVP_PKEY_CTX_free(ctx); ++ rb_str_set_len(str, keylen); ++ return str; ++} ++ + /* + * INIT + */ +@@ -983,6 +1034,7 @@ Init_ossl_pkey(void) + + rb_define_method(cPKey, "sign", ossl_pkey_sign, 2); + rb_define_method(cPKey, "verify", ossl_pkey_verify, 3); ++ rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); + + id_private_q = rb_intern("private?"); + +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index d811b9c75f..5307fe5b08 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -125,4 +125,30 @@ def test_ed25519 + # Ed25519 pkey type does not support key derivation + assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) } + end ++ ++ def test_x25519 ++ # Test vector from RFC 7748 Section 6.1 ++ alice_pem = <<~EOF ++ -----BEGIN PRIVATE KEY----- ++ MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq ++ -----END PRIVATE KEY----- ++ EOF ++ bob_pem = <<~EOF ++ -----BEGIN PUBLIC KEY----- ++ MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08= ++ -----END PUBLIC KEY----- ++ EOF ++ shared_secret = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" ++ begin ++ alice = OpenSSL::PKey.read(alice_pem) ++ bob = OpenSSL::PKey.read(bob_pem) ++ rescue OpenSSL::PKey::PKeyError ++ # OpenSSL < 1.1.0 ++ pend "X25519 is not implemented" ++ end ++ assert_instance_of OpenSSL::PKey::PKey, alice ++ assert_equal alice_pem, alice.private_to_pem ++ assert_equal bob_pem, bob.public_to_pem ++ assert_equal [shared_secret].pack("H*"), alice.derive(bob) ++ end + end +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index 4a05626a12..9efc3ba68d 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -18,6 +18,19 @@ def test_new_break + end + end + ++ def test_derive_key ++ dh1 = Fixtures.pkey("dh1024").generate_key! ++ dh2 = Fixtures.pkey("dh1024").generate_key! ++ 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_equal z, dh1.compute_key(dh2.pub_key) ++ assert_equal z, dh2.compute_key(dh1.pub_key) ++ end ++ + def test_DHparams + dh1024 = Fixtures.pkey("dh1024") + asn1 = OpenSSL::ASN1::Sequence([ +diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb +index a0e6a23ff8..95d4338a51 100644 +--- a/test/openssl/test_pkey_ec.rb ++++ b/test/openssl/test_pkey_ec.rb +@@ -93,6 +93,22 @@ def test_sign_verify + assert_equal false, p256.verify("SHA256", signature1, data) + end + ++ def test_derive_key ++ # NIST CAVP, KAS_ECC_CDH_PrimitiveTest.txt, P-256 COUNT = 0 ++ qCAVSx = "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" ++ qCAVSy = "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac" ++ dIUT = "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534" ++ zIUT = "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b" ++ a = OpenSSL::PKey::EC.new("prime256v1") ++ a.private_key = OpenSSL::BN.new(dIUT, 16) ++ b = OpenSSL::PKey::EC.new("prime256v1") ++ uncompressed = OpenSSL::BN.new("04" + qCAVSx + qCAVSy, 16) ++ b.public_key = OpenSSL::PKey::EC::Point.new(b.group, uncompressed) ++ assert_equal [zIUT].pack("H*"), a.derive(b) ++ ++ assert_equal a.derive(b), a.dh_compute_key(b.public_key) ++ end ++ + def test_dsa_sign_verify + data1 = "foo" + data2 = "bar" +-- +2.32.0 + + +From 97078c7fa8a724c7c71f9850d31fc401239da228 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 18 Mar 2017 22:34:19 +0900 +Subject: [PATCH 6/6] pkey: reimplement PKey::DH#compute_key and + PKey::EC#dh_compute_key + +Use the new OpenSSL::PKey::PKey#derive instead of the raw +{EC,}DH_compute_key(), mainly to reduce amount of the C code. +--- + ext/openssl/lib/openssl/pkey.rb | 33 +++++++++++++++++++++++++++++++ + ext/openssl/ossl_pkey_dh.c | 35 --------------------------------- + ext/openssl/ossl_pkey_ec.c | 32 ------------------------------ + 3 files changed, 33 insertions(+), 67 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 9cc3276356..be60ac2beb 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -9,6 +9,24 @@ + module OpenSSL::PKey + class DH + include OpenSSL::Marshal ++ ++ # :call-seq: ++ # dh.compute_key(pub_bn) -> string ++ # ++ # Returns a String containing a shared secret computed from the other ++ # party's public value. ++ # ++ # This method is provided for backwards compatibility, and calls #derive ++ # internally. ++ # ++ # === Parameters ++ # * _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) ++ end + end + + class DSA +@@ -18,7 +36,22 @@ class DSA + if defined?(EC) + class EC + include OpenSSL::Marshal ++ ++ # :call-seq: ++ # ec.dh_compute_key(pubkey) -> string ++ # ++ # Derives a shared secret by ECDH. _pubkey_ must be an instance of ++ # OpenSSL::PKey::EC::Point and must belong to the same group. ++ # ++ # 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) ++ end + end ++ + class EC::Point + # :call-seq: + # point.to_bn([conversion_form]) -> OpenSSL::BN +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index bc50e5566b..5bc1c49ca1 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -476,40 +476,6 @@ ossl_dh_generate_key(VALUE self) + return self; + } + +-/* +- * call-seq: +- * dh.compute_key(pub_bn) -> aString +- * +- * Returns a String containing a shared secret computed from the other party's public value. +- * See DH_compute_key() for further information. +- * +- * === Parameters +- * * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by +- * DH#public_key as that contains the DH parameters only. +- */ +-static VALUE +-ossl_dh_compute_key(VALUE self, VALUE pub) +-{ +- DH *dh; +- const BIGNUM *pub_key, *dh_p; +- VALUE str; +- int len; +- +- GetDH(self, dh); +- DH_get0_pqg(dh, &dh_p, NULL, NULL); +- if (!dh_p) +- ossl_raise(eDHError, "incomplete DH"); +- pub_key = GetBNPtr(pub); +- len = DH_size(dh); +- str = rb_str_new(0, len); +- if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) { +- ossl_raise(eDHError, NULL); +- } +- rb_str_set_len(str, len); +- +- return str; +-} +- + /* + * Document-method: OpenSSL::PKey::DH#set_pqg + * call-seq: +@@ -587,7 +553,6 @@ Init_ossl_dh(void) + rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0); + rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0); + rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0); +- rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1); + + DEF_OSSL_PKEY_BN(cDH, dh, p); + DEF_OSSL_PKEY_BN(cDH, dh, q); +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index 6fe2533e2a..c2534251c3 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -487,37 +487,6 @@ static VALUE ossl_ec_key_check_key(VALUE self) + return Qtrue; + } + +-/* +- * call-seq: +- * key.dh_compute_key(pubkey) => String +- * +- * See the OpenSSL documentation for ECDH_compute_key() +- */ +-static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey) +-{ +- EC_KEY *ec; +- EC_POINT *point; +- int buf_len; +- VALUE str; +- +- GetEC(self, ec); +- GetECPoint(pubkey, point); +- +-/* BUG: need a way to figure out the maximum string size */ +- buf_len = 1024; +- str = rb_str_new(0, buf_len); +-/* BUG: take KDF as a block */ +- buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL); +- if (buf_len < 0) +- ossl_raise(eECError, "ECDH_compute_key"); +- +- rb_str_resize(str, buf_len); +- +- return str; +-} +- +-/* sign_setup */ +- + /* + * call-seq: + * key.dsa_sign_asn1(data) => String +@@ -1657,7 +1626,6 @@ void Init_ossl_ec(void) + rb_define_alias(cEC, "generate_key", "generate_key!"); + rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0); + +- rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1); + rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1); + rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2); + /* do_sign/do_verify */ +-- +2.32.0 + diff --git a/ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.patch b/ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.patch new file mode 100644 index 0000000..33789b4 --- /dev/null +++ b/ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.patch @@ -0,0 +1,630 @@ +From 316cb2a41f154e4663d7e7fead60cfc0bfa86af9 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 +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; + } + diff --git a/ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch b/ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch new file mode 100644 index 0000000..679411a --- /dev/null +++ b/ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch @@ -0,0 +1,358 @@ +From f2cf3afc6fa1e13e960f732c0bc658ad408ee219 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 +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 +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 + diff --git a/ruby-3.1.0-Deprecate-PKey-set_-and-PKey-DH-EC-generate_key.patch b/ruby-3.1.0-Deprecate-PKey-set_-and-PKey-DH-EC-generate_key.patch new file mode 100644 index 0000000..d8f936e --- /dev/null +++ b/ruby-3.1.0-Deprecate-PKey-set_-and-PKey-DH-EC-generate_key.patch @@ -0,0 +1,719 @@ +From 46ca47060ca8ef3419ec36c2326a81b442d9b43b Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 +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 +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. + # ++ # Deprecated in version 3.0. 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 +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 +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 diff --git a/ruby-3.1.0-Disable-test_no_private_exp-on-OpenSSL-3.0.patch b/ruby-3.1.0-Disable-test_no_private_exp-on-OpenSSL-3.0.patch new file mode 100644 index 0000000..2b640ea --- /dev/null +++ b/ruby-3.1.0-Disable-test_no_private_exp-on-OpenSSL-3.0.patch @@ -0,0 +1,27 @@ +From 47975ece4096cdab16b3f200f93ea2377dfb41ac Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 diff --git a/ruby-3.1.0-Don-t-query-RubyVM-FrozenCore-for-class-path.patch b/ruby-3.1.0-Don-t-query-RubyVM-FrozenCore-for-class-path.patch new file mode 100644 index 0000000..f32f306 --- /dev/null +++ b/ruby-3.1.0-Don-t-query-RubyVM-FrozenCore-for-class-path.patch @@ -0,0 +1,43 @@ +From 0ade5611df9f981005eed32b369d1e699e520221 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +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 + diff --git a/ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch b/ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch new file mode 100644 index 0000000..ae8f722 --- /dev/null +++ b/ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch @@ -0,0 +1,186 @@ +From 104b009e26c050584e4d186c8cc4e1496a14061b Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +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); + } +@@ -1023,6 +1025,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) { +@@ -1032,7 +1035,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)); +@@ -1076,9 +1080,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))) { +@@ -1104,12 +1109,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 { +@@ -1123,8 +1130,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); + } diff --git a/ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch b/ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch new file mode 100644 index 0000000..86f534d --- /dev/null +++ b/ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch @@ -0,0 +1,58 @@ +From 72317b333b85eed483ad00bcd4f40944019a7c13 Mon Sep 17 00:00:00 2001 +From: "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; */ + } + } diff --git a/ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch b/ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch new file mode 100644 index 0000000..a558cec --- /dev/null +++ b/ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch @@ -0,0 +1,1319 @@ +From 3e6cd88c621d8834712d2279f925b9af83c2bb34 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 18 May 2020 20:06:16 +0900 +Subject: [PATCH 1/6] pkey: implement PKey#encrypt and #decrypt + +Support public key encryption and decryption operations using the EVP +API. +--- + ext/openssl/ossl_pkey.c | 141 ++++++++++++++++++++++++++++++++++ + test/openssl/test_pkey_rsa.rb | 34 ++++++++ + 2 files changed, 175 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 21cd4b2cda..baf8ce9f20 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -986,6 +986,145 @@ ossl_pkey_derive(int argc, VALUE *argv, VALUE self) + return str; + } + ++/* ++ * call-seq: ++ * pkey.encrypt(data [, options]) -> string ++ * ++ * Performs a public key encryption operation using +pkey+. ++ * ++ * See #decrypt for the reverse operation. ++ * ++ * Added in version 3.0. See also the man page EVP_PKEY_encrypt(3). ++ * ++ * +data+:: ++ * A String to be encrypted. ++ * +options+:: ++ * A Hash that contains algorithm specific control operations to \OpenSSL. ++ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. ++ * ++ * Example: ++ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) ++ * data = "secret data" ++ * encrypted = pkey.encrypt(data, rsa_padding_mode: "oaep") ++ * decrypted = pkey.decrypt(data, rsa_padding_mode: "oaep") ++ * p decrypted #=> "secret data" ++ */ ++static VALUE ++ossl_pkey_encrypt(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey; ++ EVP_PKEY_CTX *ctx; ++ VALUE data, options, str; ++ size_t outlen; ++ int state; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "11", &data, &options); ++ StringValue(data); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_encrypt_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_encrypt_init"); ++ } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(ctx, options, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ if (EVP_PKEY_encrypt(ctx, NULL, &outlen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_encrypt"); ++ } ++ if (outlen > LONG_MAX) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_raise(ePKeyError, "encrypted data would be too large"); ++ } ++ str = ossl_str_new(NULL, (long)outlen, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_PKEY_encrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_encrypt"); ++ } ++ EVP_PKEY_CTX_free(ctx); ++ rb_str_set_len(str, outlen); ++ return str; ++} ++ ++/* ++ * call-seq: ++ * pkey.decrypt(data [, options]) -> string ++ * ++ * Performs a public key decryption operation using +pkey+. ++ * ++ * See #encrypt for a description of the parameters and an example. ++ * ++ * Added in version 3.0. See also the man page EVP_PKEY_decrypt(3). ++ */ ++static VALUE ++ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey; ++ EVP_PKEY_CTX *ctx; ++ VALUE data, options, str; ++ size_t outlen; ++ int state; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "11", &data, &options); ++ StringValue(data); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_decrypt_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_decrypt_init"); ++ } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(ctx, options, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ if (EVP_PKEY_decrypt(ctx, NULL, &outlen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_decrypt"); ++ } ++ if (outlen > LONG_MAX) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_raise(ePKeyError, "decrypted data would be too large"); ++ } ++ str = ossl_str_new(NULL, (long)outlen, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_PKEY_decrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_decrypt"); ++ } ++ EVP_PKEY_CTX_free(ctx); ++ rb_str_set_len(str, outlen); ++ return str; ++} ++ + /* + * INIT + */ +@@ -1085,6 +1224,8 @@ Init_ossl_pkey(void) + 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); ++ rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1); ++ rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1); + + id_private_q = rb_intern("private?"); + +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index 5f8d04e754..d6bfca3ac5 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -173,6 +173,40 @@ def test_sign_verify_pss + } + end + ++ def test_encrypt_decrypt ++ rsapriv = Fixtures.pkey("rsa-1") ++ rsapub = dup_public(rsapriv) ++ ++ # Defaults to PKCS #1 v1.5 ++ raw = "data" ++ enc = rsapub.encrypt(raw) ++ assert_equal raw, rsapriv.decrypt(enc) ++ ++ # Invalid options ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ rsapub.encrypt(raw, { "nonexistent" => "option" }) ++ } ++ end ++ ++ def test_encrypt_decrypt_legacy ++ rsapriv = Fixtures.pkey("rsa-1") ++ rsapub = dup_public(rsapriv) ++ ++ # Defaults to PKCS #1 v1.5 ++ raw = "data" ++ enc_legacy = rsapub.public_encrypt(raw) ++ assert_equal raw, rsapriv.decrypt(enc_legacy) ++ enc_new = rsapub.encrypt(raw) ++ assert_equal raw, rsapriv.private_decrypt(enc_new) ++ ++ # OAEP with default parameters ++ raw = "data" ++ enc_legacy = rsapub.public_encrypt(raw, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING) ++ assert_equal raw, rsapriv.decrypt(enc_legacy, { "rsa_padding_mode" => "oaep" }) ++ enc_new = rsapub.encrypt(raw, { "rsa_padding_mode" => "oaep" }) ++ assert_equal raw, rsapriv.private_decrypt(enc_legacy, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING) ++ end ++ + def test_export + rsa1024 = Fixtures.pkey("rsa1024") + key = OpenSSL::PKey::RSA.new +-- +2.32.0 + + +From 6f5c75b06967b5b2db1d13646d74310e1cdc563e Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 25 May 2021 18:43:29 +0900 +Subject: [PATCH 2/6] pkey: update version reference in #sign and #verify + documentation + +The next release is decided to be 3.0 rather than 2.3. +--- + ext/openssl/ossl_pkey.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index baf8ce9f20..d08f6f7e60 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -761,7 +761,7 @@ ossl_pkey_public_to_pem(VALUE self) + * +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. ++ * +options+ parameter was added in version 3.0. + * + * Example: + * data = "Sign me!" +@@ -875,7 +875,7 @@ ossl_pkey_sign(int argc, VALUE *argv, VALUE self) + * +data+:: + * See #sign. + * +options+:: +- * See #sign. +options+ parameter was added in version 2.3. ++ * See #sign. +options+ parameter was added in version 3.0. + */ + static VALUE + ossl_pkey_verify(int argc, VALUE *argv, VALUE self) +-- +2.32.0 + + +From 99fc31a9b4843b7f8923b5ce8b36115b2c66f4db Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 22 May 2020 16:10:35 +0900 +Subject: [PATCH 3/6] pkey: implement PKey#sign_raw, #verify_raw, and + #verify_recover + +Add a variant of PKey#sign and #verify that do not hash the data +automatically. + +Sometimes the caller has the hashed data only, but not the plaintext +to be signed. In that case, users would have to use the low-level API +such as RSA#private_encrypt or #public_decrypt directly. + +OpenSSL 1.0.0 and later supports EVP_PKEY_sign() and EVP_PKEY_verify() +which provide the same functionality as part of the EVP API. This patch +adds wrappers for them. +--- + ext/openssl/ossl_pkey.c | 232 ++++++++++++++++++++++++++++++++++ + test/openssl/test_pkey_dsa.rb | 25 +++- + test/openssl/test_pkey_ec.rb | 21 ++- + test/openssl/test_pkey_rsa.rb | 78 ++++++++---- + 4 files changed, 325 insertions(+), 31 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index d08f6f7e60..ba909c7632 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -935,6 +935,235 @@ ossl_pkey_verify(int argc, VALUE *argv, VALUE self) + } + } + ++/* ++ * call-seq: ++ * pkey.sign_raw(digest, data [, options]) -> string ++ * ++ * Signs +data+ using a private key +pkey+. Unlike #sign, +data+ will not be ++ * hashed by +digest+ automatically. ++ * ++ * See #verify_raw for the verification operation. ++ * ++ * Added in version 3.0. See also the man page EVP_PKEY_sign(3). ++ * ++ * +digest+:: ++ * A String that represents the message digest algorithm name, or +nil+ ++ * if the PKey type requires no digest algorithm. ++ * Although this method will not hash +data+ with it, this parameter may still ++ * be required depending on the signature algorithm. ++ * +data+:: ++ * A String. The data to be 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. ++ * ++ * Example: ++ * data = "Sign me!" ++ * hash = OpenSSL::Digest.digest("SHA256", data) ++ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) ++ * signopts = { rsa_padding_mode: "pss" } ++ * signature = pkey.sign_raw("SHA256", hash, signopts) ++ * ++ * # Creates a copy of the RSA key pkey, but without the private components ++ * pub_key = pkey.public_key ++ * puts pub_key.verify_raw("SHA256", signature, hash, signopts) # => true ++ */ ++static VALUE ++ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey; ++ VALUE digest, data, options, sig; ++ const EVP_MD *md = NULL; ++ EVP_PKEY_CTX *ctx; ++ size_t outlen; ++ int state; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "21", &digest, &data, &options); ++ if (!NIL_P(digest)) ++ md = ossl_evp_get_digestbyname(digest); ++ StringValue(data); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_sign_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_sign_init"); ++ } ++ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); ++ } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(ctx, options, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ if (EVP_PKEY_sign(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_sign"); ++ } ++ if (outlen > LONG_MAX) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_raise(ePKeyError, "signature would be too large"); ++ } ++ sig = ossl_str_new(NULL, (long)outlen, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_PKEY_sign(ctx, (unsigned char *)RSTRING_PTR(sig), &outlen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_sign"); ++ } ++ EVP_PKEY_CTX_free(ctx); ++ rb_str_set_len(sig, outlen); ++ return sig; ++} ++ ++/* ++ * call-seq: ++ * pkey.verify_raw(digest, signature, data [, options]) -> true or false ++ * ++ * Verifies the +signature+ for the +data+ using a public key +pkey+. Unlike ++ * #verify, this method will not hash +data+ with +digest+ automatically. ++ * ++ * Returns +true+ if the signature is successfully verified, +false+ otherwise. ++ * The caller must check the return value. ++ * ++ * See #sign_raw for the signing operation and an example code. ++ * ++ * Added in version 3.0. See also the man page EVP_PKEY_verify(3). ++ * ++ * +signature+:: ++ * A String containing the signature to be verified. ++ */ ++static VALUE ++ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey; ++ VALUE digest, sig, data, options; ++ const EVP_MD *md = NULL; ++ EVP_PKEY_CTX *ctx; ++ 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); ++ StringValue(sig); ++ StringValue(data); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_verify_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_verify_init"); ++ } ++ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); ++ } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(ctx, options, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ ret = EVP_PKEY_verify(ctx, (unsigned char *)RSTRING_PTR(sig), ++ RSTRING_LEN(sig), ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)); ++ EVP_PKEY_CTX_free(ctx); ++ if (ret < 0) ++ ossl_raise(ePKeyError, "EVP_PKEY_verify"); ++ ++ if (ret) ++ return Qtrue; ++ else { ++ ossl_clear_error(); ++ return Qfalse; ++ } ++} ++ ++/* ++ * call-seq: ++ * pkey.verify_recover(digest, signature [, options]) -> string ++ * ++ * Recovers the signed data from +signature+ using a public key +pkey+. Not all ++ * signature algorithms support this operation. ++ * ++ * Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3). ++ * ++ * +signature+:: ++ * A String containing the signature to be verified. ++ */ ++static VALUE ++ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey; ++ VALUE digest, sig, options, out; ++ const EVP_MD *md = NULL; ++ EVP_PKEY_CTX *ctx; ++ int state; ++ size_t outlen; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "21", &digest, &sig, &options); ++ ossl_pkey_check_public_key(pkey); ++ if (!NIL_P(digest)) ++ md = ossl_evp_get_digestbyname(digest); ++ StringValue(sig); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_verify_recover_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover_init"); ++ } ++ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); ++ } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(ctx, options, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ if (EVP_PKEY_verify_recover(ctx, NULL, &outlen, ++ (unsigned char *)RSTRING_PTR(sig), ++ RSTRING_LEN(sig)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover"); ++ } ++ out = ossl_str_new(NULL, (long)outlen, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_PKEY_verify_recover(ctx, (unsigned char *)RSTRING_PTR(out), &outlen, ++ (unsigned char *)RSTRING_PTR(sig), ++ RSTRING_LEN(sig)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover"); ++ } ++ EVP_PKEY_CTX_free(ctx); ++ rb_str_set_len(out, outlen); ++ return out; ++} ++ + /* + * call-seq: + * pkey.derive(peer_pkey) -> string +@@ -1223,6 +1452,9 @@ Init_ossl_pkey(void) + + rb_define_method(cPKey, "sign", ossl_pkey_sign, -1); + rb_define_method(cPKey, "verify", ossl_pkey_verify, -1); ++ rb_define_method(cPKey, "sign_raw", ossl_pkey_sign_raw, -1); ++ rb_define_method(cPKey, "verify_raw", ossl_pkey_verify_raw, -1); ++ rb_define_method(cPKey, "verify_recover", ossl_pkey_verify_recover, -1); + rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); + rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1); + rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1); +diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb +index 85bb6ec0ae..147e50176b 100644 +--- a/test/openssl/test_pkey_dsa.rb ++++ b/test/openssl/test_pkey_dsa.rb +@@ -48,12 +48,31 @@ def test_sign_verify + assert_equal false, dsa512.verify("SHA256", signature1, data) + end + +- def test_sys_sign_verify +- key = Fixtures.pkey("dsa256") ++ def test_sign_verify_raw ++ key = Fixtures.pkey("dsa512") + data = 'Sign me!' + digest = OpenSSL::Digest.digest('SHA1', data) ++ ++ invalid_sig = key.sign_raw(nil, digest.succ) ++ malformed_sig = "*" * invalid_sig.bytesize ++ ++ # Sign by #syssign + sig = key.syssign(digest) +- assert(key.sysverify(digest, sig)) ++ assert_equal true, key.sysverify(digest, sig) ++ assert_equal false, key.sysverify(digest, invalid_sig) ++ assert_raise(OpenSSL::PKey::DSAError) { key.sysverify(digest, malformed_sig) } ++ assert_equal true, key.verify_raw(nil, sig, digest) ++ assert_equal false, key.verify_raw(nil, invalid_sig, digest) ++ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, digest) } ++ ++ # Sign by #sign_raw ++ sig = key.sign_raw(nil, digest) ++ assert_equal true, key.sysverify(digest, sig) ++ assert_equal false, key.sysverify(digest, invalid_sig) ++ assert_raise(OpenSSL::PKey::DSAError) { key.sysverify(digest, malformed_sig) } ++ assert_equal true, key.verify_raw(nil, sig, digest) ++ assert_equal false, key.verify_raw(nil, invalid_sig, digest) ++ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, digest) } + end + + def test_DSAPrivateKey +diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb +index 95d4338a51..4b6df0290f 100644 +--- a/test/openssl/test_pkey_ec.rb ++++ b/test/openssl/test_pkey_ec.rb +@@ -109,13 +109,30 @@ def test_derive_key + assert_equal a.derive(b), a.dh_compute_key(b.public_key) + end + +- def test_dsa_sign_verify ++ def test_sign_verify_raw ++ key = Fixtures.pkey("p256") + data1 = "foo" + data2 = "bar" +- key = OpenSSL::PKey::EC.new("prime256v1").generate_key! ++ ++ malformed_sig = "*" * 30 ++ ++ # Sign by #dsa_sign_asn1 + sig = key.dsa_sign_asn1(data1) + assert_equal true, key.dsa_verify_asn1(data1, sig) + assert_equal false, key.dsa_verify_asn1(data2, sig) ++ assert_raise(OpenSSL::PKey::ECError) { key.dsa_verify_asn1(data1, malformed_sig) } ++ assert_equal true, key.verify_raw(nil, sig, data1) ++ assert_equal false, key.verify_raw(nil, sig, data2) ++ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, data1) } ++ ++ # Sign by #sign_raw ++ sig = key.sign_raw(nil, data1) ++ assert_equal true, key.dsa_verify_asn1(data1, sig) ++ assert_equal false, key.dsa_verify_asn1(data2, sig) ++ assert_raise(OpenSSL::PKey::ECError) { key.dsa_verify_asn1(data1, malformed_sig) } ++ assert_equal true, key.verify_raw(nil, sig, data1) ++ assert_equal false, key.verify_raw(nil, sig, data2) ++ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, data1) } + end + + def test_dsa_sign_asn1_FIPS186_3 +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index d6bfca3ac5..5e127f5407 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -13,32 +13,6 @@ def test_no_private_exp + assert_raise(OpenSSL::PKey::RSAError){ key.private_decrypt("foo") } + end + +- def test_padding +- key = OpenSSL::PKey::RSA.new(512, 3) +- +- # Need right size for raw mode +- plain0 = "x" * (512/8) +- cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING) +- plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING) +- assert_equal(plain0, plain1) +- +- # Need smaller size for pkcs1 mode +- plain0 = "x" * (512/8 - 11) +- cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING) +- plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING) +- assert_equal(plain0, plain1) +- +- cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default +- plain1 = key.public_decrypt(cipherdef) +- assert_equal(plain0, plain1) +- assert_equal(cipher1, cipherdef) +- +- # Failure cases +- assert_raise(ArgumentError){ key.private_encrypt() } +- assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) } +- assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) } +- end +- + def test_private + # Generated by key size and public exponent + key = OpenSSL::PKey::RSA.new(512, 3) +@@ -133,6 +107,58 @@ def test_sign_verify_options + assert_equal false, key.verify("SHA256", sig_pss, data) + end + ++ 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) ++ ++ # Too long data ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ key.sign_raw("SHA1", "x" * (key.n.num_bytes + 1)) ++ } ++ ++ # With options ++ pssopts = { ++ "rsa_padding_mode" => "pss", ++ "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) ++ end ++ ++ def test_sign_verify_raw_legacy ++ key = Fixtures.pkey("rsa-1") ++ bits = key.n.num_bits ++ ++ # Need right size for raw mode ++ plain0 = "x" * (bits/8) ++ cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING) ++ plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING) ++ assert_equal(plain0, plain1) ++ ++ # Need smaller size for pkcs1 mode ++ plain0 = "x" * (bits/8 - 11) ++ cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING) ++ plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING) ++ assert_equal(plain0, plain1) ++ ++ cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default ++ plain1 = key.public_decrypt(cipherdef) ++ assert_equal(plain0, plain1) ++ assert_equal(cipher1, cipherdef) ++ ++ # Failure cases ++ assert_raise(ArgumentError){ key.private_encrypt() } ++ assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) } ++ assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) } ++ end ++ ++ + def test_verify_empty_rsa + rsa = OpenSSL::PKey::RSA.new + assert_raise(OpenSSL::PKey::PKeyError, "[Bug #12783]") { +-- +2.32.0 + + +From 4330b1b9661fcab1172473f4fdd9986602c1e78c Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 18 May 2020 20:24:08 +0900 +Subject: [PATCH 4/6] pkey/rsa: port RSA#{private,public}_{encrypt,decrypt} to + the EVP API + +Implement these methods using the new OpenSSL::PKey::PKey#{encrypt,sign} +family. The definitions are now in lib/openssl/pkey.rb. + +Also, recommend using those generic methods in the documentation. +--- + ext/openssl/lib/openssl/pkey.rb | 106 ++++++++++++++++++++++++ + ext/openssl/ossl_pkey_rsa.c | 141 -------------------------------- + 2 files changed, 106 insertions(+), 141 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 569559e1ce..dd8c7c0b09 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -243,5 +243,111 @@ def new(*args, &blk) # :nodoc: + end + end + end ++ ++ # :call-seq: ++ # rsa.private_encrypt(string) -> String ++ # rsa.private_encrypt(string, padding) -> String ++ # ++ # Encrypt +string+ with the private key. +padding+ defaults to ++ # PKCS1_PADDING. The encrypted string output can be decrypted using ++ # #public_decrypt. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and ++ # PKey::PKey#verify_recover instead. ++ def private_encrypt(string, padding = PKCS1_PADDING) ++ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" ++ private? or raise OpenSSL::PKey::RSAError, "private key needed." ++ begin ++ sign_raw(nil, string, { ++ "rsa_padding_mode" => translate_padding_mode(padding), ++ }) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::RSAError, $!.message ++ end ++ end ++ ++ # :call-seq: ++ # rsa.public_decrypt(string) -> String ++ # rsa.public_decrypt(string, padding) -> String ++ # ++ # Decrypt +string+, which has been encrypted with the private key, with the ++ # public key. +padding+ defaults to PKCS1_PADDING. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and ++ # PKey::PKey#verify_recover instead. ++ def public_decrypt(string, padding = PKCS1_PADDING) ++ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" ++ begin ++ verify_recover(nil, string, { ++ "rsa_padding_mode" => translate_padding_mode(padding), ++ }) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::RSAError, $!.message ++ end ++ end ++ ++ # :call-seq: ++ # rsa.public_encrypt(string) -> String ++ # rsa.public_encrypt(string, padding) -> String ++ # ++ # Encrypt +string+ with the public key. +padding+ defaults to ++ # PKCS1_PADDING. The encrypted string output can be decrypted using ++ # #private_decrypt. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead. ++ def public_encrypt(data, padding = PKCS1_PADDING) ++ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" ++ begin ++ encrypt(data, { ++ "rsa_padding_mode" => translate_padding_mode(padding), ++ }) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::RSAError, $!.message ++ end ++ end ++ ++ # :call-seq: ++ # rsa.private_decrypt(string) -> String ++ # rsa.private_decrypt(string, padding) -> String ++ # ++ # Decrypt +string+, which has been encrypted with the public key, with the ++ # private key. +padding+ defaults to PKCS1_PADDING. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead. ++ def private_decrypt(data, padding = PKCS1_PADDING) ++ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" ++ private? or raise OpenSSL::PKey::RSAError, "private key needed." ++ begin ++ decrypt(data, { ++ "rsa_padding_mode" => translate_padding_mode(padding), ++ }) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::RSAError, $!.message ++ end ++ end ++ ++ PKCS1_PADDING = 1 ++ SSLV23_PADDING = 2 ++ NO_PADDING = 3 ++ PKCS1_OAEP_PADDING = 4 ++ ++ private def translate_padding_mode(num) ++ case num ++ when PKCS1_PADDING ++ "pkcs1" ++ when SSLV23_PADDING ++ "sslv23" ++ when NO_PADDING ++ "none" ++ when PKCS1_OAEP_PADDING ++ "oaep" ++ else ++ raise OpenSSL::PKey::PKeyError, "unsupported padding mode" ++ end ++ end + end + end +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 1c5476cdcd..8ebd3ec559 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -229,138 +229,6 @@ ossl_rsa_to_der(VALUE self) + return ossl_pkey_export_spki(self, 1); + } + +-/* +- * call-seq: +- * rsa.public_encrypt(string) => String +- * rsa.public_encrypt(string, padding) => String +- * +- * Encrypt _string_ with the public key. _padding_ defaults to PKCS1_PADDING. +- * The encrypted string output can be decrypted using #private_decrypt. +- */ +-static VALUE +-ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self) +-{ +- RSA *rsa; +- const BIGNUM *rsa_n; +- int buf_len, pad; +- VALUE str, buffer, padding; +- +- GetRSA(self, rsa); +- RSA_get0_key(rsa, &rsa_n, NULL, NULL); +- if (!rsa_n) +- ossl_raise(eRSAError, "incomplete RSA"); +- rb_scan_args(argc, argv, "11", &buffer, &padding); +- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); +- StringValue(buffer); +- str = rb_str_new(0, RSA_size(rsa)); +- buf_len = RSA_public_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), +- (unsigned char *)RSTRING_PTR(str), rsa, pad); +- if (buf_len < 0) ossl_raise(eRSAError, NULL); +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- +-/* +- * call-seq: +- * rsa.public_decrypt(string) => String +- * rsa.public_decrypt(string, padding) => String +- * +- * Decrypt _string_, which has been encrypted with the private key, with the +- * public key. _padding_ defaults to PKCS1_PADDING. +- */ +-static VALUE +-ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) +-{ +- RSA *rsa; +- const BIGNUM *rsa_n; +- int buf_len, pad; +- VALUE str, buffer, padding; +- +- GetRSA(self, rsa); +- RSA_get0_key(rsa, &rsa_n, NULL, NULL); +- if (!rsa_n) +- ossl_raise(eRSAError, "incomplete RSA"); +- rb_scan_args(argc, argv, "11", &buffer, &padding); +- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); +- StringValue(buffer); +- str = rb_str_new(0, RSA_size(rsa)); +- buf_len = RSA_public_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), +- (unsigned char *)RSTRING_PTR(str), rsa, pad); +- if (buf_len < 0) ossl_raise(eRSAError, NULL); +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- +-/* +- * call-seq: +- * rsa.private_encrypt(string) => String +- * rsa.private_encrypt(string, padding) => String +- * +- * Encrypt _string_ with the private key. _padding_ defaults to PKCS1_PADDING. +- * The encrypted string output can be decrypted using #public_decrypt. +- */ +-static VALUE +-ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self) +-{ +- RSA *rsa; +- const BIGNUM *rsa_n; +- int buf_len, pad; +- VALUE str, buffer, padding; +- +- GetRSA(self, rsa); +- RSA_get0_key(rsa, &rsa_n, NULL, NULL); +- if (!rsa_n) +- ossl_raise(eRSAError, "incomplete RSA"); +- if (!RSA_PRIVATE(self, rsa)) +- ossl_raise(eRSAError, "private key needed."); +- rb_scan_args(argc, argv, "11", &buffer, &padding); +- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); +- StringValue(buffer); +- str = rb_str_new(0, RSA_size(rsa)); +- buf_len = RSA_private_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), +- (unsigned char *)RSTRING_PTR(str), rsa, pad); +- if (buf_len < 0) ossl_raise(eRSAError, NULL); +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- +-/* +- * call-seq: +- * rsa.private_decrypt(string) => String +- * rsa.private_decrypt(string, padding) => String +- * +- * Decrypt _string_, which has been encrypted with the public key, with the +- * private key. _padding_ defaults to PKCS1_PADDING. +- */ +-static VALUE +-ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) +-{ +- RSA *rsa; +- const BIGNUM *rsa_n; +- int buf_len, pad; +- VALUE str, buffer, padding; +- +- GetRSA(self, rsa); +- RSA_get0_key(rsa, &rsa_n, NULL, NULL); +- if (!rsa_n) +- ossl_raise(eRSAError, "incomplete RSA"); +- if (!RSA_PRIVATE(self, rsa)) +- ossl_raise(eRSAError, "private key needed."); +- rb_scan_args(argc, argv, "11", &buffer, &padding); +- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); +- StringValue(buffer); +- str = rb_str_new(0, RSA_size(rsa)); +- buf_len = RSA_private_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), +- (unsigned char *)RSTRING_PTR(str), rsa, pad); +- if (buf_len < 0) ossl_raise(eRSAError, NULL); +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- + /* + * call-seq: + * rsa.sign_pss(digest, data, salt_length:, mgf1_hash:) -> String +@@ -657,10 +525,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_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); +- rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, -1); + rb_define_method(cRSA, "sign_pss", ossl_rsa_sign_pss, -1); + rb_define_method(cRSA, "verify_pss", ossl_rsa_verify_pss, -1); + +@@ -678,11 +542,6 @@ Init_ossl_rsa(void) + + rb_define_method(cRSA, "params", ossl_rsa_get_params, 0); + +- DefRSAConst(PKCS1_PADDING); +- DefRSAConst(SSLV23_PADDING); +- DefRSAConst(NO_PADDING); +- DefRSAConst(PKCS1_OAEP_PADDING); +- + /* + * TODO: Test it + rb_define_method(cRSA, "blinding_on!", ossl_rsa_blinding_on, 0); +-- +2.32.0 + + +From d45a31cf70f5a55d7f6cf5082efc4dbb68d1169d Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 10 Jul 2020 13:43:20 +0900 +Subject: [PATCH 5/6] pkey/ec: refactor EC#dsa_{sign,verify}_asn1 with + PKey#{sign,verify}_raw + +With the newly added OpenSSL::PKey::PKey#{sign,verify}_raw, +OpenSSL::PKey::EC's low level signing operation methods can be +implemented in Ruby. The definitions are now in lib/openssl/pkey.rb. +--- + ext/openssl/lib/openssl/pkey.rb | 22 +++++++++++++ + ext/openssl/ossl_pkey_ec.c | 55 --------------------------------- + 2 files changed, 22 insertions(+), 55 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index dd8c7c0b09..e587109694 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -164,6 +164,28 @@ def new(*args, &blk) # :nodoc: + class EC + include OpenSSL::Marshal + ++ # :call-seq: ++ # key.dsa_sign_asn1(data) -> String ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. ++ def dsa_sign_asn1(data) ++ sign_raw(nil, data) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::ECError, $!.message ++ end ++ ++ # :call-seq: ++ # key.dsa_verify_asn1(data, sig) -> true | false ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. ++ def dsa_verify_asn1(data, sig) ++ verify_raw(nil, sig, data) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::ECError, $!.message ++ end ++ + # :call-seq: + # ec.dh_compute_key(pubkey) -> string + # +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index 829529d4b9..f52e67079d 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -476,57 +476,6 @@ static VALUE ossl_ec_key_check_key(VALUE self) + return Qtrue; + } + +-/* +- * call-seq: +- * key.dsa_sign_asn1(data) => String +- * +- * See the OpenSSL documentation for ECDSA_sign() +- */ +-static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data) +-{ +- EC_KEY *ec; +- unsigned int buf_len; +- VALUE str; +- +- GetEC(self, ec); +- StringValue(data); +- +- if (EC_KEY_get0_private_key(ec) == NULL) +- ossl_raise(eECError, "Private EC key needed!"); +- +- str = rb_str_new(0, ECDSA_size(ec)); +- if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1) +- ossl_raise(eECError, "ECDSA_sign"); +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- +-/* +- * call-seq: +- * key.dsa_verify_asn1(data, sig) => true or false +- * +- * See the OpenSSL documentation for ECDSA_verify() +- */ +-static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) +-{ +- EC_KEY *ec; +- +- GetEC(self, ec); +- StringValue(data); +- StringValue(sig); +- +- switch (ECDSA_verify(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data), +- (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), ec)) { +- case 1: +- return Qtrue; +- case 0: +- return Qfalse; +- default: +- ossl_raise(eECError, "ECDSA_verify"); +- } +-} +- + /* + * OpenSSL::PKey::EC::Group + */ +@@ -1615,10 +1564,6 @@ void Init_ossl_ec(void) + rb_define_alias(cEC, "generate_key", "generate_key!"); + rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0); + +- rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1); +- rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2); +-/* do_sign/do_verify */ +- + 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); +-- +2.32.0 + + +From 2494043e302c920e90e06cce443c5cd428e183f7 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 10 Jul 2020 13:51:18 +0900 +Subject: [PATCH 6/6] pkey/dsa: refactor DSA#sys{sign,verify} with + PKey#{sign,verify}_raw + +With the newly added OpenSSL::PKey::PKey#{sign,verify}_raw, +OpenSSL::PKey::DSA's low level signing operation methods can be +implemented in Ruby. The definitions are now in lib/openssl/pkey.rb. +--- + ext/openssl/lib/openssl/pkey.rb | 54 ++++++++++++++++++++ + ext/openssl/ossl_pkey_dsa.c | 88 --------------------------------- + 2 files changed, 54 insertions(+), 88 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index e587109694..f6bf5892b0 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -158,6 +158,60 @@ def new(*args, &blk) # :nodoc: + end + end + end ++ ++ # :call-seq: ++ # dsa.syssign(string) -> string ++ # ++ # Computes and returns the \DSA signature of +string+, where +string+ is ++ # expected to be an already-computed message digest of the original input ++ # data. The signature is issued using the private key of this DSA instance. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. ++ # ++ # +string+:: ++ # A message digest of the original input data to be signed. ++ # ++ # Example: ++ # dsa = OpenSSL::PKey::DSA.new(2048) ++ # doc = "Sign me" ++ # digest = OpenSSL::Digest.digest('SHA1', doc) ++ # ++ # # With legacy #syssign and #sysverify: ++ # sig = dsa.syssign(digest) ++ # p dsa.sysverify(digest, sig) #=> true ++ # ++ # # With #sign_raw and #verify_raw: ++ # sig = dsa.sign_raw(nil, digest) ++ # p dsa.verify_raw(nil, sig, digest) #=> true ++ def syssign(string) ++ q or raise OpenSSL::PKey::DSAError, "incomplete DSA" ++ private? or raise OpenSSL::PKey::DSAError, "Private DSA key needed!" ++ begin ++ sign_raw(nil, string) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::DSAError, $!.message ++ end ++ end ++ ++ # :call-seq: ++ # dsa.sysverify(digest, sig) -> true | false ++ # ++ # Verifies whether the signature is valid given the message digest input. ++ # It does so by validating +sig+ using the public key of this DSA instance. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. ++ # ++ # +digest+:: ++ # A message digest of the original input data to be signed. ++ # +sig+:: ++ # A \DSA signature value. ++ def sysverify(digest, sig) ++ verify_raw(nil, sig, digest) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::DSAError, $!.message ++ end + end + + if defined?(EC) +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index ab9ac781e8..7af00eebec 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -264,92 +264,6 @@ ossl_dsa_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * dsa.syssign(string) -> aString +- * +- * Computes and returns the DSA signature of _string_, where _string_ is +- * expected to be an already-computed message digest of the original input +- * data. The signature is issued using the private key of this DSA instance. +- * +- * === Parameters +- * * _string_ is a message digest of the original input data to be signed. +- * +- * === Example +- * dsa = OpenSSL::PKey::DSA.new(2048) +- * doc = "Sign me" +- * digest = OpenSSL::Digest.digest('SHA1', doc) +- * sig = dsa.syssign(digest) +- * +- * +- */ +-static VALUE +-ossl_dsa_sign(VALUE self, VALUE data) +-{ +- DSA *dsa; +- const BIGNUM *dsa_q; +- unsigned int buf_len; +- VALUE str; +- +- GetDSA(self, dsa); +- DSA_get0_pqg(dsa, NULL, &dsa_q, NULL); +- if (!dsa_q) +- ossl_raise(eDSAError, "incomplete DSA"); +- if (!DSA_PRIVATE(self, dsa)) +- ossl_raise(eDSAError, "Private DSA key needed!"); +- StringValue(data); +- str = rb_str_new(0, DSA_size(dsa)); +- if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data), +- (unsigned char *)RSTRING_PTR(str), +- &buf_len, dsa)) { /* type is ignored (0) */ +- ossl_raise(eDSAError, NULL); +- } +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- +-/* +- * call-seq: +- * dsa.sysverify(digest, sig) -> true | false +- * +- * Verifies whether the signature is valid given the message digest input. It +- * does so by validating _sig_ using the public key of this DSA instance. +- * +- * === Parameters +- * * _digest_ is a message digest of the original input data to be signed +- * * _sig_ is a DSA signature value +- * +- * === Example +- * dsa = OpenSSL::PKey::DSA.new(2048) +- * doc = "Sign me" +- * digest = OpenSSL::Digest.digest('SHA1', doc) +- * sig = dsa.syssign(digest) +- * puts dsa.sysverify(digest, sig) # => true +- * +- */ +-static VALUE +-ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) +-{ +- DSA *dsa; +- int ret; +- +- GetDSA(self, dsa); +- StringValue(digest); +- StringValue(sig); +- /* type is ignored (0) */ +- ret = DSA_verify(0, (unsigned char *)RSTRING_PTR(digest), RSTRING_LENINT(digest), +- (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), dsa); +- if (ret < 0) { +- ossl_raise(eDSAError, NULL); +- } +- else if (ret == 1) { +- return Qtrue; +- } +- +- return Qfalse; +-} +- + /* + * Document-method: OpenSSL::PKey::DSA#set_pqg + * call-seq: +@@ -404,8 +318,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, "syssign", ossl_dsa_sign, 1); +- rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2); + + DEF_OSSL_PKEY_BN(cDSA, dsa, p); + DEF_OSSL_PKEY_BN(cDSA, dsa, q); +-- +2.32.0 + diff --git a/ruby-3.1.0-Migrate-from-the-low-level-HMAC-API-to-the-EVP-API.patch b/ruby-3.1.0-Migrate-from-the-low-level-HMAC-API-to-the-EVP-API.patch new file mode 100644 index 0000000..d25cae9 --- /dev/null +++ b/ruby-3.1.0-Migrate-from-the-low-level-HMAC-API-to-the-EVP-API.patch @@ -0,0 +1,523 @@ +From 8253d7c9cea16c2aa009b59db4f5d93afb74c6eb Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 +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 +@@ -141,8 +141,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 + #endif +-#if !defined(OPENSSL_NO_HMAC) +-# include +-#endif + #include + + #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 + #include + #include +-#include + #include + #include + #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 + diff --git a/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch b/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch new file mode 100644 index 0000000..b906c19 --- /dev/null +++ b/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch @@ -0,0 +1,458 @@ +From 91d04f991f8b9910efea7bbe5aecb0fea2bbd5fa Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 +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 +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 +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 /* memcpy() */ +-#if !defined(OPENSSL_NO_ENGINE) +-# include +-#endif + #include + + #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 + #include + #include ++ + #include + #include + #include +@@ -30,9 +31,6 @@ + #include + #endif + #include +-#if !defined(OPENSSL_NO_ENGINE) +-# include +-#endif + #if !defined(OPENSSL_NO_OCSP) + # include + #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 + + #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 ++#endif ++ + /* + * Classes + */ + +From b1ee2f23b28c2d0b14fd9b4b9fef13e870370746 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 +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 +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 +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) { diff --git a/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch b/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch new file mode 100644 index 0000000..a780108 --- /dev/null +++ b/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch @@ -0,0 +1,304 @@ +From 8f948ed68a4ed6c05ff66d822711e3b70ae4bb3f Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 + #include + ++#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 +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 +@@ -165,7 +165,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") +@@ -174,6 +174,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 +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 +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 +@@ -177,6 +177,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 +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 +@@ -178,6 +178,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"); + diff --git a/ruby-3.1.0-Properly-exclude-test-cases.patch b/ruby-3.1.0-Properly-exclude-test-cases.patch new file mode 100644 index 0000000..ca2cd9b --- /dev/null +++ b/ruby-3.1.0-Properly-exclude-test-cases.patch @@ -0,0 +1,93 @@ +From 96684439e96aa92e10376b5be45f006772028295 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Thu, 21 Oct 2021 13:02:38 +0200 +Subject: [PATCH] Properly exclude test cases. + +Lets consider the following scenario: + +~~~ +irb(#):001:0> p suite +OpenSSL::TestEC +=> OpenSSL::TestEC + +irb(#):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(#):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(#):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(#):005:0> filter === method +=> true + +irb(#):006:0> filter === "#{suite}##{method}" +=> false + +irb(#):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 + diff --git a/ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch b/ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch new file mode 100644 index 0000000..d1de216 --- /dev/null +++ b/ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch @@ -0,0 +1,1450 @@ +From 8b8e1d7f9b6b5a335864bbd0716df2af1ec41d91 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Thu, 16 Mar 2017 16:06:53 +0900 +Subject: [PATCH 1/5] pkey: simplify ossl_pkey_new() + +ossl_{rsa,dsa,dh,ec}_new() called from this function are not used +anywhere else. Inline them into pkey_new0() and reduce code +duplication. +--- + ext/openssl/ossl_pkey.c | 22 +++++++++------------- + ext/openssl/ossl_pkey.h | 3 --- + ext/openssl/ossl_pkey_dh.c | 21 --------------------- + ext/openssl/ossl_pkey_dsa.c | 21 --------------------- + ext/openssl/ossl_pkey_ec.c | 20 -------------------- + ext/openssl/ossl_pkey_rsa.c | 22 ---------------------- + 6 files changed, 9 insertions(+), 100 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 23204087ac..c6dbf57272 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -95,7 +95,7 @@ const rb_data_type_t ossl_evp_pkey_type = { + static VALUE + pkey_new0(EVP_PKEY *pkey) + { +- VALUE obj; ++ VALUE klass, obj; + int type; + + if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE) +@@ -103,26 +103,22 @@ pkey_new0(EVP_PKEY *pkey) + + switch (type) { + #if !defined(OPENSSL_NO_RSA) +- case EVP_PKEY_RSA: +- return ossl_rsa_new(pkey); ++ case EVP_PKEY_RSA: klass = cRSA; break; + #endif + #if !defined(OPENSSL_NO_DSA) +- case EVP_PKEY_DSA: +- return ossl_dsa_new(pkey); ++ case EVP_PKEY_DSA: klass = cDSA; break; + #endif + #if !defined(OPENSSL_NO_DH) +- case EVP_PKEY_DH: +- return ossl_dh_new(pkey); ++ case EVP_PKEY_DH: klass = cDH; break; + #endif + #if !defined(OPENSSL_NO_EC) +- case EVP_PKEY_EC: +- return ossl_ec_new(pkey); ++ case EVP_PKEY_EC: klass = cEC; break; + #endif +- default: +- obj = NewPKey(cPKey); +- SetPKey(obj, pkey); +- return obj; ++ default: klass = cPKey; break; + } ++ obj = NewPKey(klass); ++ SetPKey(obj, pkey); ++ return obj; + } + + VALUE +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index 0db59305f7..e363a261c2 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -56,7 +56,6 @@ void Init_ossl_pkey(void); + extern VALUE cRSA; + extern VALUE eRSAError; + +-VALUE ossl_rsa_new(EVP_PKEY *); + void Init_ossl_rsa(void); + + /* +@@ -65,7 +64,6 @@ void Init_ossl_rsa(void); + extern VALUE cDSA; + extern VALUE eDSAError; + +-VALUE ossl_dsa_new(EVP_PKEY *); + void Init_ossl_dsa(void); + + /* +@@ -74,7 +72,6 @@ void Init_ossl_dsa(void); + extern VALUE cDH; + extern VALUE eDHError; + +-VALUE ossl_dh_new(EVP_PKEY *); + void Init_ossl_dh(void); + + /* +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index bf4e3f9322..dff69cfc33 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -54,27 +54,6 @@ dh_instance(VALUE klass, DH *dh) + return obj; + } + +-VALUE +-ossl_dh_new(EVP_PKEY *pkey) +-{ +- VALUE obj; +- +- if (!pkey) { +- obj = dh_instance(cDH, DH_new()); +- } else { +- obj = NewPKey(cDH); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { +- ossl_raise(rb_eTypeError, "Not a DH key!"); +- } +- SetPKey(obj, pkey); +- } +- if (obj == Qfalse) { +- ossl_raise(eDHError, NULL); +- } +- +- return obj; +-} +- + /* + * Private + */ +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index 431c20e05c..e9be9ac482 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -68,27 +68,6 @@ dsa_instance(VALUE klass, DSA *dsa) + return obj; + } + +-VALUE +-ossl_dsa_new(EVP_PKEY *pkey) +-{ +- VALUE obj; +- +- if (!pkey) { +- obj = dsa_instance(cDSA, DSA_new()); +- } else { +- obj = NewPKey(cDSA); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { +- ossl_raise(rb_eTypeError, "Not a DSA key!"); +- } +- SetPKey(obj, pkey); +- } +- if (obj == Qfalse) { +- ossl_raise(eDSAError, NULL); +- } +- +- return obj; +-} +- + /* + * Private + */ +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index fc2bc6c815..eabf495f19 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -84,26 +84,6 @@ static VALUE ec_instance(VALUE klass, EC_KEY *ec) + return obj; + } + +-VALUE ossl_ec_new(EVP_PKEY *pkey) +-{ +- VALUE obj; +- +- if (!pkey) { +- obj = ec_instance(cEC, EC_KEY_new()); +- } else { +- obj = NewPKey(cEC); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { +- ossl_raise(rb_eTypeError, "Not a EC key!"); +- } +- SetPKey(obj, pkey); +- } +- if (obj == Qfalse) { +- ossl_raise(eECError, NULL); +- } +- +- return obj; +-} +- + /* + * Creates a new EC_KEY on the EC group obj. arg can be an EC::Group or a String + * representing an OID. +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 761866c66a..c1ae44fe40 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -69,28 +69,6 @@ rsa_instance(VALUE klass, RSA *rsa) + return obj; + } + +-VALUE +-ossl_rsa_new(EVP_PKEY *pkey) +-{ +- VALUE obj; +- +- if (!pkey) { +- obj = rsa_instance(cRSA, RSA_new()); +- } +- else { +- obj = NewPKey(cRSA); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { +- ossl_raise(rb_eTypeError, "Not a RSA key!"); +- } +- SetPKey(obj, pkey); +- } +- if (obj == Qfalse) { +- ossl_raise(eRSAError, NULL); +- } +- +- return obj; +-} +- + /* + * Private + */ +-- +2.32.0 + + +From 2b0d259ef7aae707922996d305675a68dad27abd Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Thu, 16 Mar 2017 16:09:35 +0900 +Subject: [PATCH 2/5] pkey: inline {rsa,dsa,dh,ec}_instance() + +Merge the code into the callers so that the wrapping Ruby object is +allocated before the raw key object is allocated. This prevents possible +memory leak on Ruby object allocation failure, and also reduces the +lines of code. +--- + ext/openssl/ossl_pkey_dh.c | 63 ++++++++++++---------------------- + ext/openssl/ossl_pkey_dsa.c | 68 ++++++++++++++----------------------- + ext/openssl/ossl_pkey_ec.c | 34 ++++--------------- + ext/openssl/ossl_pkey_rsa.c | 67 +++++++++++++----------------------- + 4 files changed, 76 insertions(+), 156 deletions(-) + +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index dff69cfc33..bc50e5566b 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -29,31 +29,6 @@ + VALUE cDH; + VALUE eDHError; + +-/* +- * Public +- */ +-static VALUE +-dh_instance(VALUE klass, DH *dh) +-{ +- EVP_PKEY *pkey; +- VALUE obj; +- +- if (!dh) { +- return Qfalse; +- } +- obj = NewPKey(klass); +- if (!(pkey = EVP_PKEY_new())) { +- return Qfalse; +- } +- if (!EVP_PKEY_assign_DH(pkey, dh)) { +- EVP_PKEY_free(pkey); +- return Qfalse; +- } +- SetPKey(obj, pkey); +- +- return obj; +-} +- + /* + * Private + */ +@@ -84,7 +59,7 @@ dh_generate(int size, int gen) + if (!dh || !cb) { + DH_free(dh); + BN_GENCB_free(cb); +- return NULL; ++ ossl_raise(eDHError, "malloc failure"); + } + + if (rb_block_given_p()) +@@ -110,12 +85,12 @@ dh_generate(int size, int gen) + ossl_clear_error(); + rb_jump_tag(cb_arg.state); + } +- return NULL; ++ ossl_raise(eDHError, "DH_generate_parameters_ex"); + } + + if (!DH_generate_key(dh)) { + DH_free(dh); +- return NULL; ++ ossl_raise(eDHError, "DH_generate_key"); + } + + return dh; +@@ -136,6 +111,7 @@ dh_generate(int size, int gen) + static VALUE + ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) + { ++ EVP_PKEY *pkey; + DH *dh ; + int g = 2; + VALUE size, gen, obj; +@@ -143,13 +119,14 @@ ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) + if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) { + g = NUM2INT(gen); + } ++ obj = rb_obj_alloc(klass); ++ GetPKey(obj, pkey); ++ + dh = dh_generate(NUM2INT(size), g); +- obj = dh_instance(klass, dh); +- if (obj == Qfalse) { +- DH_free(dh); +- ossl_raise(eDHError, NULL); ++ if (!EVP_PKEY_assign_DH(pkey, dh)) { ++ DH_free(dh); ++ ossl_raise(eDHError, "EVP_PKEY_assign_DH"); + } +- + return obj; + } + +@@ -195,9 +172,7 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) + if (!NIL_P(gen)) { + g = NUM2INT(gen); + } +- if (!(dh = dh_generate(NUM2INT(arg), g))) { +- ossl_raise(eDHError, NULL); +- } ++ dh = dh_generate(NUM2INT(arg), g); + } + else { + arg = ossl_to_der_if_possible(arg); +@@ -434,17 +409,21 @@ ossl_dh_to_text(VALUE self) + 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); /* err check perfomed by dh_instance */ +- obj = dh_instance(rb_obj_class(self), dh); +- if (obj == Qfalse) { +- DH_free(dh); +- ossl_raise(eDHError, NULL); ++ 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; + } + +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index e9be9ac482..c907f31c19 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -43,31 +43,6 @@ DSA_PRIVATE(VALUE obj, DSA *dsa) + VALUE cDSA; + VALUE eDSAError; + +-/* +- * Public +- */ +-static VALUE +-dsa_instance(VALUE klass, DSA *dsa) +-{ +- EVP_PKEY *pkey; +- VALUE obj; +- +- if (!dsa) { +- return Qfalse; +- } +- obj = NewPKey(klass); +- if (!(pkey = EVP_PKEY_new())) { +- return Qfalse; +- } +- if (!EVP_PKEY_assign_DSA(pkey, dsa)) { +- EVP_PKEY_free(pkey); +- return Qfalse; +- } +- SetPKey(obj, pkey); +- +- return obj; +-} +- + /* + * Private + */ +@@ -100,9 +75,9 @@ dsa_generate(int size) + unsigned long h; + + if (!dsa || !cb) { +- DSA_free(dsa); +- BN_GENCB_free(cb); +- return NULL; ++ DSA_free(dsa); ++ BN_GENCB_free(cb); ++ ossl_raise(eDSAError, "malloc failure"); + } + + if (rb_block_given_p()) +@@ -132,12 +107,12 @@ dsa_generate(int size) + ossl_clear_error(); + rb_jump_tag(cb_arg.state); + } +- return NULL; ++ ossl_raise(eDSAError, "DSA_generate_parameters_ex"); + } + + if (!DSA_generate_key(dsa)) { +- DSA_free(dsa); +- return NULL; ++ DSA_free(dsa); ++ ossl_raise(eDSAError, "DSA_generate_key"); + } + + return dsa; +@@ -157,14 +132,18 @@ dsa_generate(int size) + static VALUE + ossl_dsa_s_generate(VALUE klass, VALUE size) + { +- DSA *dsa = dsa_generate(NUM2INT(size)); /* err handled by dsa_instance */ +- VALUE obj = dsa_instance(klass, dsa); ++ EVP_PKEY *pkey; ++ DSA *dsa; ++ VALUE obj; + +- if (obj == Qfalse) { +- DSA_free(dsa); +- ossl_raise(eDSAError, NULL); +- } ++ obj = rb_obj_alloc(klass); ++ GetPKey(obj, pkey); + ++ dsa = dsa_generate(NUM2INT(size)); ++ if (!EVP_PKEY_assign_DSA(pkey, dsa)) { ++ DSA_free(dsa); ++ ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); ++ } + return obj; + } + +@@ -460,20 +439,23 @@ ossl_dsa_to_text(VALUE self) + static VALUE + ossl_dsa_to_public_key(VALUE self) + { +- EVP_PKEY *pkey; ++ EVP_PKEY *pkey, *pkey_new; + DSA *dsa; + VALUE obj; + + GetPKeyDSA(self, pkey); +- /* err check performed by dsa_instance */ ++ 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 +- obj = dsa_instance(rb_obj_class(self), dsa); +- if (obj == Qfalse) { +- DSA_free(dsa); +- ossl_raise(eDSAError, NULL); ++ 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; + } +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index eabf495f19..aec9d1e60f 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -63,27 +63,6 @@ static ID id_i_group; + static VALUE ec_group_new(const EC_GROUP *group); + static VALUE ec_point_new(const EC_POINT *point, const EC_GROUP *group); + +-static VALUE ec_instance(VALUE klass, EC_KEY *ec) +-{ +- EVP_PKEY *pkey; +- VALUE obj; +- +- if (!ec) { +- return Qfalse; +- } +- obj = NewPKey(klass); +- if (!(pkey = EVP_PKEY_new())) { +- return Qfalse; +- } +- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { +- EVP_PKEY_free(pkey); +- return Qfalse; +- } +- SetPKey(obj, pkey); +- +- return obj; +-} +- + /* + * Creates a new EC_KEY on the EC group obj. arg can be an EC::Group or a String + * representing an OID. +@@ -130,17 +109,18 @@ ec_key_new_from_group(VALUE arg) + static VALUE + ossl_ec_key_s_generate(VALUE klass, VALUE arg) + { ++ EVP_PKEY *pkey; + EC_KEY *ec; + VALUE obj; + +- ec = ec_key_new_from_group(arg); ++ obj = rb_obj_alloc(klass); ++ GetPKey(obj, pkey); + +- obj = ec_instance(klass, ec); +- if (obj == Qfalse) { +- EC_KEY_free(ec); +- ossl_raise(eECError, NULL); ++ ec = ec_key_new_from_group(arg); ++ if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { ++ EC_KEY_free(ec); ++ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); + } +- + if (!EC_KEY_generate_key(ec)) + ossl_raise(eECError, "EC_KEY_generate_key"); + +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index c1ae44fe40..fbdb9c8960 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -44,31 +44,6 @@ RSA_PRIVATE(VALUE obj, RSA *rsa) + VALUE cRSA; + VALUE eRSAError; + +-/* +- * Public +- */ +-static VALUE +-rsa_instance(VALUE klass, RSA *rsa) +-{ +- EVP_PKEY *pkey; +- VALUE obj; +- +- if (!rsa) { +- return Qfalse; +- } +- obj = NewPKey(klass); +- if (!(pkey = EVP_PKEY_new())) { +- return Qfalse; +- } +- if (!EVP_PKEY_assign_RSA(pkey, rsa)) { +- EVP_PKEY_free(pkey); +- return Qfalse; +- } +- SetPKey(obj, pkey); +- +- return obj; +-} +- + /* + * Private + */ +@@ -102,7 +77,7 @@ rsa_generate(int size, unsigned long exp) + RSA_free(rsa); + BN_free(e); + BN_GENCB_free(cb); +- return NULL; ++ ossl_raise(eRSAError, "malloc failure"); + } + for (i = 0; i < (int)sizeof(exp) * 8; ++i) { + if (exp & (1UL << i)) { +@@ -110,7 +85,7 @@ rsa_generate(int size, unsigned long exp) + BN_free(e); + RSA_free(rsa); + BN_GENCB_free(cb); +- return NULL; ++ ossl_raise(eRSAError, "BN_set_bit"); + } + } + } +@@ -139,7 +114,7 @@ rsa_generate(int size, unsigned long exp) + ossl_clear_error(); + rb_jump_tag(cb_arg.state); + } +- return NULL; ++ ossl_raise(eRSAError, "RSA_generate_key_ex"); + } + + return rsa; +@@ -158,26 +133,26 @@ static VALUE + ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) + { + /* why does this method exist? why can't initialize take an optional exponent? */ ++ EVP_PKEY *pkey; + RSA *rsa; + VALUE size, exp; + VALUE obj; + + rb_scan_args(argc, argv, "11", &size, &exp); ++ obj = rb_obj_alloc(klass); ++ GetPKey(obj, pkey); + +- rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp)); /* err handled by rsa_instance */ +- obj = rsa_instance(klass, rsa); +- +- if (obj == Qfalse) { +- RSA_free(rsa); +- ossl_raise(eRSAError, NULL); ++ rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp)); ++ if (!EVP_PKEY_assign_RSA(pkey, rsa)) { ++ RSA_free(rsa); ++ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); + } +- + return obj; + } + + /* + * call-seq: +- * RSA.new(key_size) => RSA instance ++ * RSA.new(size [, exponent]) => RSA instance + * RSA.new(encoded_key) => RSA instance + * RSA.new(encoded_key, pass_phrase) => RSA instance + * +@@ -206,10 +181,11 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + GetPKey(self, pkey); + if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { + rsa = RSA_new(); ++ if (!rsa) ++ ossl_raise(eRSAError, "RSA_new"); + } + else if (RB_INTEGER_TYPE_P(arg)) { + rsa = rsa_generate(NUM2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2ULONG(pass)); +- if (!rsa) ossl_raise(eRSAError, NULL); + } + else { + pass = ossl_pem_passwd_value(pass); +@@ -243,7 +219,7 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + } + if (!EVP_PKEY_assign_RSA(pkey, rsa)) { + RSA_free(rsa); +- ossl_raise(eRSAError, NULL); ++ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); + } + + return self; +@@ -787,17 +763,20 @@ ossl_rsa_to_text(VALUE self) + static VALUE + ossl_rsa_to_public_key(VALUE self) + { +- EVP_PKEY *pkey; ++ EVP_PKEY *pkey, *pkey_new; + RSA *rsa; + VALUE obj; + + GetPKeyRSA(self, pkey); +- /* err check performed by rsa_instance */ ++ obj = rb_obj_alloc(rb_obj_class(self)); ++ GetPKey(obj, pkey_new); ++ + rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey)); +- obj = rsa_instance(rb_obj_class(self), rsa); +- if (obj == Qfalse) { +- RSA_free(rsa); +- ossl_raise(eRSAError, NULL); ++ 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; + } +-- +2.32.0 + + +From 1e1fedc6c2c9d42bc76b5a24bf0f39c8101f8d53 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 18 Mar 2017 17:26:33 +0900 +Subject: [PATCH 3/5] pkey: have PKey.read parse PEM-encoded DHParameter + +Try PEM_read_bio_Parameters(). Only PEM format is supported at the +moment since corresponding d2i_* functions are not provided by OpenSSL. +--- + ext/openssl/ossl_pkey.c | 3 +++ + test/openssl/test_pkey_dh.rb | 2 ++ + test/openssl/utils.rb | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index c6dbf57272..a00d66aada 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -178,6 +178,9 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) + OSSL_BIO_reset(bio); + if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL))) + goto ok; ++ OSSL_BIO_reset(bio); ++ if ((pkey = PEM_read_bio_Parameters(bio, NULL))) ++ goto ok; + + BIO_free(bio); + ossl_raise(ePKeyError, "Could not parse PKey"); +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index fd2c7a66a9..4a05626a12 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -36,6 +36,8 @@ def test_DHparams + EOF + key = OpenSSL::PKey::DH.new(pem) + assert_same_dh dup_public(dh1024), key ++ key = OpenSSL::PKey.read(pem) ++ assert_same_dh dup_public(dh1024), key + + assert_equal asn1.to_der, dh1024.to_der + assert_equal pem, dh1024.export +diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb +index 3776fbac4e..c1d737b2ab 100644 +--- a/test/openssl/utils.rb ++++ b/test/openssl/utils.rb +@@ -42,9 +42,6 @@ module Fixtures + + def pkey(name) + OpenSSL::PKey.read(read_file("pkey", name)) +- rescue OpenSSL::PKey::PKeyError +- # TODO: DH parameters can be read by OpenSSL::PKey.read atm +- OpenSSL::PKey::DH.new(read_file("pkey", name)) + end + + def read_file(category, name) +-- +2.32.0 + + +From 70655b40a980dad36dfb3054d309f6484e2a70b7 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 13 Jun 2017 23:39:41 +0900 +Subject: [PATCH 4/5] pkey: refactor DER/PEM-encoded string parsing code + +Export the flow used by OpenSSL::PKey.read and let the subclasses call +it before attempting other formats. +--- + ext/openssl/ossl_pkey.c | 57 +++++++++++++++++++++---------------- + ext/openssl/ossl_pkey.h | 1 + + ext/openssl/ossl_pkey_dsa.c | 37 +++++++++++------------- + ext/openssl/ossl_pkey_ec.c | 29 +++++++------------ + ext/openssl/ossl_pkey_rsa.c | 26 ++++++++--------- + 5 files changed, 73 insertions(+), 77 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index a00d66aada..47ddd0f014 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -136,6 +136,35 @@ ossl_pkey_new(EVP_PKEY *pkey) + return obj; + } + ++EVP_PKEY * ++ossl_pkey_read_generic(BIO *bio, VALUE pass) ++{ ++ void *ppass = (void *)pass; ++ EVP_PKEY *pkey; ++ ++ if ((pkey = d2i_PrivateKey_bio(bio, NULL))) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass))) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if ((pkey = d2i_PUBKEY_bio(bio, NULL))) ++ goto out; ++ OSSL_BIO_reset(bio); ++ /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */ ++ if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass))) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL))) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if ((pkey = PEM_read_bio_Parameters(bio, NULL))) ++ goto out; ++ ++ out: ++ return pkey; ++} ++ + /* + * call-seq: + * OpenSSL::PKey.read(string [, pwd ]) -> PKey +@@ -160,33 +189,11 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) + VALUE data, pass; + + rb_scan_args(argc, argv, "11", &data, &pass); +- pass = ossl_pem_passwd_value(pass); +- + bio = ossl_obj2bio(&data); +- if ((pkey = d2i_PrivateKey_bio(bio, NULL))) +- goto ok; +- OSSL_BIO_reset(bio); +- if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, (void *)pass))) +- goto ok; +- OSSL_BIO_reset(bio); +- if ((pkey = d2i_PUBKEY_bio(bio, NULL))) +- goto ok; +- OSSL_BIO_reset(bio); +- /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */ +- if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass))) +- goto ok; +- OSSL_BIO_reset(bio); +- if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL))) +- goto ok; +- OSSL_BIO_reset(bio); +- if ((pkey = PEM_read_bio_Parameters(bio, NULL))) +- goto ok; +- +- BIO_free(bio); +- ossl_raise(ePKeyError, "Could not parse PKey"); +- +-ok: ++ pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass)); + BIO_free(bio); ++ if (!pkey) ++ ossl_raise(ePKeyError, "Could not parse PKey"); + return ossl_pkey_new(pkey); + } + +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index e363a261c2..895927e3fb 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -45,6 +45,7 @@ void ossl_generate_cb_stop(void *ptr); + + VALUE ossl_pkey_new(EVP_PKEY *); + void ossl_pkey_check_public_key(const EVP_PKEY *); ++EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE); + EVP_PKEY *GetPKeyPtr(VALUE); + EVP_PKEY *DupPKeyPtr(VALUE); + EVP_PKEY *GetPrivPKeyPtr(VALUE); +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index c907f31c19..56f58559ed 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -170,37 +170,34 @@ ossl_dsa_s_generate(VALUE klass, VALUE size) + static VALUE + ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) + { +- EVP_PKEY *pkey; +- DSA *dsa; ++ EVP_PKEY *pkey, *tmp; ++ DSA *dsa = NULL; + BIO *in; + VALUE arg, pass; + + GetPKey(self, pkey); +- if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { ++ rb_scan_args(argc, argv, "02", &arg, &pass); ++ if (argc == 0) { + dsa = DSA_new(); ++ if (!dsa) ++ ossl_raise(eDSAError, "DSA_new"); + } +- else if (RB_INTEGER_TYPE_P(arg)) { +- if (!(dsa = dsa_generate(NUM2INT(arg)))) { +- ossl_raise(eDSAError, NULL); +- } ++ else if (argc == 1 && RB_INTEGER_TYPE_P(arg)) { ++ dsa = dsa_generate(NUM2INT(arg)); + } + else { + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); + in = ossl_obj2bio(&arg); +- dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); +- if (!dsa) { +- OSSL_BIO_reset(in); +- dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL); +- } +- if (!dsa) { +- OSSL_BIO_reset(in); +- dsa = d2i_DSAPrivateKey_bio(in, NULL); +- } +- if (!dsa) { +- OSSL_BIO_reset(in); +- dsa = d2i_DSA_PUBKEY_bio(in, NULL); +- } ++ ++ 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( \ +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index aec9d1e60f..ca8f5c6e4e 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -162,24 +162,17 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) + } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { + ec = ec_key_new_from_group(arg); + } else { +- BIO *in; +- +- pass = ossl_pem_passwd_value(pass); +- in = ossl_obj2bio(&arg); +- +- ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); +- if (!ec) { +- OSSL_BIO_reset(in); +- ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, (void *)pass); +- } +- if (!ec) { +- OSSL_BIO_reset(in); +- ec = d2i_ECPrivateKey_bio(in, NULL); +- } +- if (!ec) { +- OSSL_BIO_reset(in); +- ec = d2i_EC_PUBKEY_bio(in, NULL); +- } ++ 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); + + if (!ec) { +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index fbdb9c8960..8415121c7d 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -179,7 +179,8 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + VALUE arg, pass; + + GetPKey(self, pkey); +- if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { ++ rb_scan_args(argc, argv, "02", &arg, &pass); ++ if (argc == 0) { + rsa = RSA_new(); + if (!rsa) + ossl_raise(eRSAError, "RSA_new"); +@@ -191,19 +192,15 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); + in = ossl_obj2bio(&arg); +- rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); +- if (!rsa) { +- OSSL_BIO_reset(in); +- rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL); +- } +- if (!rsa) { +- OSSL_BIO_reset(in); +- rsa = d2i_RSAPrivateKey_bio(in, NULL); +- } +- if (!rsa) { +- OSSL_BIO_reset(in); +- rsa = d2i_RSA_PUBKEY_bio(in, NULL); +- } ++ ++ 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); +@@ -214,6 +211,7 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + } + BIO_free(in); + if (!rsa) { ++ ossl_clear_error(); + ossl_raise(eRSAError, "Neither PUB key nor PRIV key"); + } + } +-- +2.32.0 + + +From eacc680b1efc82935efc945bbe23c9073f17f440 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Wed, 14 Jun 2017 00:25:43 +0900 +Subject: [PATCH 5/5] pkey: refactor #export/#to_pem and #to_der + +Add ossl_pkey_export_traditional() and ossl_pkey_export_spki() helper +functions, and use them. This reduces code duplication. +--- + ext/openssl/ossl_pkey.c | 54 +++++++++++++++++++++-- + ext/openssl/ossl_pkey.h | 14 ++++++ + ext/openssl/ossl_pkey_dsa.c | 49 +++------------------ + ext/openssl/ossl_pkey_ec.c | 86 ++++++++----------------------------- + ext/openssl/ossl_pkey_rsa.c | 84 +++++++++++------------------------- + 5 files changed, 114 insertions(+), 173 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 47ddd0f014..610a83fd2d 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -341,6 +341,52 @@ ossl_pkey_inspect(VALUE self) + OBJ_nid2sn(nid)); + } + ++VALUE ++ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der) ++{ ++ EVP_PKEY *pkey; ++ VALUE cipher, pass; ++ const EVP_CIPHER *enc = NULL; ++ BIO *bio; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "02", &cipher, &pass); ++ if (!NIL_P(cipher)) { ++ enc = ossl_evp_get_cipherbyname(cipher); ++ pass = ossl_pem_passwd_value(pass); ++ } ++ ++ bio = BIO_new(BIO_s_mem()); ++ if (!bio) ++ ossl_raise(ePKeyError, "BIO_new"); ++ if (to_der) { ++ if (!i2d_PrivateKey_bio(bio, pkey)) { ++ BIO_free(bio); ++ ossl_raise(ePKeyError, "i2d_PrivateKey_bio"); ++ } ++ } ++ else { ++#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER) ++ if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0, ++ ossl_pem_passwd_cb, ++ (void *)pass)) { ++#else ++ char pem_str[80]; ++ const char *aname; ++ ++ EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &aname, pkey->ameth); ++ snprintf(pem_str, sizeof(pem_str), "%s PRIVATE KEY", aname); ++ if (!PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, pem_str, bio, ++ pkey, enc, NULL, 0, ossl_pem_passwd_cb, ++ (void *)pass)) { ++#endif ++ BIO_free(bio); ++ ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional"); ++ } ++ } ++ return ossl_membio2str(bio); ++} ++ + static VALUE + do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der) + { +@@ -410,8 +456,8 @@ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self) + return do_pkcs8_export(argc, argv, self, 0); + } + +-static VALUE +-do_spki_export(VALUE self, int to_der) ++VALUE ++ossl_pkey_export_spki(VALUE self, int to_der) + { + EVP_PKEY *pkey; + BIO *bio; +@@ -444,7 +490,7 @@ do_spki_export(VALUE self, int to_der) + static VALUE + ossl_pkey_public_to_der(VALUE self) + { +- return do_spki_export(self, 1); ++ return ossl_pkey_export_spki(self, 1); + } + + /* +@@ -456,7 +502,7 @@ ossl_pkey_public_to_der(VALUE self) + static VALUE + ossl_pkey_public_to_pem(VALUE self) + { +- return do_spki_export(self, 0); ++ return ossl_pkey_export_spki(self, 0); + } + + /* +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index 895927e3fb..7dbaed47bc 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -49,6 +49,20 @@ EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE); + EVP_PKEY *GetPKeyPtr(VALUE); + EVP_PKEY *DupPKeyPtr(VALUE); + EVP_PKEY *GetPrivPKeyPtr(VALUE); ++ ++/* ++ * Serializes _self_ in X.509 SubjectPublicKeyInfo format and returns the ++ * resulting String. Sub-classes use this when overriding #to_der. ++ */ ++VALUE ossl_pkey_export_spki(VALUE self, int to_der); ++/* ++ * Serializes the private key _self_ in the traditional private key format ++ * and returns the resulting String. Sub-classes use this when overriding ++ * #to_der. ++ */ ++VALUE ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, ++ int to_der); ++ + void Init_ossl_pkey(void); + + /* +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index 56f58559ed..0e68f7f27f 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -296,34 +296,12 @@ static VALUE + ossl_dsa_export(int argc, VALUE *argv, VALUE self) + { + DSA *dsa; +- BIO *out; +- const EVP_CIPHER *ciph = NULL; +- VALUE cipher, pass, str; + + GetDSA(self, dsa); +- rb_scan_args(argc, argv, "02", &cipher, &pass); +- if (!NIL_P(cipher)) { +- ciph = ossl_evp_get_cipherbyname(cipher); +- pass = ossl_pem_passwd_value(pass); +- } +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eDSAError, NULL); +- } +- if (DSA_HAS_PRIVATE(dsa)) { +- if (!PEM_write_bio_DSAPrivateKey(out, dsa, ciph, NULL, 0, +- ossl_pem_passwd_cb, (void *)pass)){ +- BIO_free(out); +- ossl_raise(eDSAError, NULL); +- } +- } else { +- if (!PEM_write_bio_DSA_PUBKEY(out, dsa)) { +- BIO_free(out); +- ossl_raise(eDSAError, NULL); +- } +- } +- str = ossl_membio2str(out); +- +- return str; ++ if (DSA_HAS_PRIVATE(dsa)) ++ return ossl_pkey_export_traditional(argc, argv, self, 0); ++ else ++ return ossl_pkey_export_spki(self, 0); + } + + /* +@@ -337,25 +315,12 @@ static VALUE + ossl_dsa_to_der(VALUE self) + { + DSA *dsa; +- int (*i2d_func)(DSA *, unsigned char **); +- unsigned char *p; +- long len; +- VALUE str; + + GetDSA(self, dsa); +- if(DSA_HAS_PRIVATE(dsa)) +- i2d_func = (int (*)(DSA *,unsigned char **))i2d_DSAPrivateKey; ++ if (DSA_HAS_PRIVATE(dsa)) ++ return ossl_pkey_export_traditional(0, NULL, self, 1); + else +- i2d_func = i2d_DSA_PUBKEY; +- if((len = i2d_func(dsa, NULL)) <= 0) +- ossl_raise(eDSAError, NULL); +- str = rb_str_new(0, len); +- p = (unsigned char *)RSTRING_PTR(str); +- if(i2d_func(dsa, &p) < 0) +- ossl_raise(eDSAError, NULL); +- ossl_str_adjust(str, p); +- +- return str; ++ return ossl_pkey_export_spki(self, 1); + } + + +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index ca8f5c6e4e..6fe2533e2a 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -141,7 +141,7 @@ 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; ++ EC_KEY *ec = NULL; + VALUE arg, pass; + + GetPKey(self, pkey); +@@ -378,66 +378,6 @@ static VALUE ossl_ec_key_is_private(VALUE self) + return EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse; + } + +-static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format) +-{ +- EC_KEY *ec; +- BIO *out; +- int i = -1; +- int private = 0; +- VALUE str; +- const EVP_CIPHER *cipher = NULL; +- +- GetEC(self, ec); +- +- if (EC_KEY_get0_public_key(ec) == NULL) +- ossl_raise(eECError, "can't export - no public key set"); +- +- if (EC_KEY_check_key(ec) != 1) +- ossl_raise(eECError, "can't export - EC_KEY_check_key failed"); +- +- if (EC_KEY_get0_private_key(ec)) +- private = 1; +- +- if (!NIL_P(ciph)) { +- cipher = ossl_evp_get_cipherbyname(ciph); +- pass = ossl_pem_passwd_value(pass); +- } +- +- if (!(out = BIO_new(BIO_s_mem()))) +- ossl_raise(eECError, "BIO_new(BIO_s_mem())"); +- +- switch(format) { +- case EXPORT_PEM: +- if (private) { +- i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, ossl_pem_passwd_cb, (void *)pass); +- } else { +- i = PEM_write_bio_EC_PUBKEY(out, ec); +- } +- +- break; +- case EXPORT_DER: +- if (private) { +- i = i2d_ECPrivateKey_bio(out, ec); +- } else { +- i = i2d_EC_PUBKEY_bio(out, ec); +- } +- +- break; +- default: +- BIO_free(out); +- ossl_raise(rb_eRuntimeError, "unknown format (internal error)"); +- } +- +- if (i != 1) { +- BIO_free(out); +- ossl_raise(eECError, "outlen=%d", i); +- } +- +- str = ossl_membio2str(out); +- +- return str; +-} +- + /* + * call-seq: + * key.export([cipher, pass_phrase]) => String +@@ -448,11 +388,16 @@ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int forma + * instance. Note that encryption will only be effective for a private key, + * public keys will always be encoded in plain text. + */ +-static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self) ++static VALUE ++ossl_ec_key_export(int argc, VALUE *argv, VALUE self) + { +- VALUE cipher, passwd; +- rb_scan_args(argc, argv, "02", &cipher, &passwd); +- return ossl_ec_key_to_string(self, cipher, passwd, EXPORT_PEM); ++ EC_KEY *ec; ++ ++ GetEC(self, ec); ++ if (EC_KEY_get0_private_key(ec)) ++ return ossl_pkey_export_traditional(argc, argv, self, 0); ++ else ++ return ossl_pkey_export_spki(self, 0); + } + + /* +@@ -461,9 +406,16 @@ static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self) + * + * See the OpenSSL documentation for i2d_ECPrivateKey_bio() + */ +-static VALUE ossl_ec_key_to_der(VALUE self) ++static VALUE ++ossl_ec_key_to_der(VALUE self) + { +- return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER); ++ EC_KEY *ec; ++ ++ GetEC(self, ec); ++ if (EC_KEY_get0_private_key(ec)) ++ return ossl_pkey_export_traditional(0, NULL, self, 1); ++ else ++ return ossl_pkey_export_spki(self, 1); + } + + /* +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 8415121c7d..3c298a2aea 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -173,8 +173,8 @@ ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) + static VALUE + ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + { +- EVP_PKEY *pkey; +- RSA *rsa; ++ EVP_PKEY *pkey, *tmp; ++ RSA *rsa = NULL; + BIO *in; + VALUE arg, pass; + +@@ -279,6 +279,21 @@ ossl_rsa_is_private(VALUE self) + return RSA_PRIVATE(self, rsa) ? Qtrue : Qfalse; + } + ++static int ++can_export_rsaprivatekey(VALUE self) ++{ ++ RSA *rsa; ++ const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; ++ ++ GetRSA(self, rsa); ++ ++ RSA_get0_key(rsa, &n, &e, &d); ++ RSA_get0_factors(rsa, &p, &q); ++ RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); ++ ++ return n && e && d && p && q && dmp1 && dmq1 && iqmp; ++} ++ + /* + * call-seq: + * rsa.export([cipher, pass_phrase]) => PEM-format String +@@ -292,41 +307,10 @@ ossl_rsa_is_private(VALUE self) + static VALUE + ossl_rsa_export(int argc, VALUE *argv, VALUE self) + { +- RSA *rsa; +- const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; +- BIO *out; +- const EVP_CIPHER *ciph = NULL; +- VALUE cipher, pass, str; +- +- GetRSA(self, rsa); +- +- rb_scan_args(argc, argv, "02", &cipher, &pass); +- +- if (!NIL_P(cipher)) { +- ciph = ossl_evp_get_cipherbyname(cipher); +- pass = ossl_pem_passwd_value(pass); +- } +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eRSAError, NULL); +- } +- RSA_get0_key(rsa, &n, &e, &d); +- RSA_get0_factors(rsa, &p, &q); +- RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); +- if (n && e && d && p && q && dmp1 && dmq1 && iqmp) { +- if (!PEM_write_bio_RSAPrivateKey(out, rsa, ciph, NULL, 0, +- ossl_pem_passwd_cb, (void *)pass)) { +- BIO_free(out); +- ossl_raise(eRSAError, NULL); +- } +- } else { +- if (!PEM_write_bio_RSA_PUBKEY(out, rsa)) { +- BIO_free(out); +- ossl_raise(eRSAError, NULL); +- } +- } +- str = ossl_membio2str(out); +- +- return str; ++ if (can_export_rsaprivatekey(self)) ++ return ossl_pkey_export_traditional(argc, argv, self, 0); ++ else ++ return ossl_pkey_export_spki(self, 0); + } + + /* +@@ -338,30 +322,10 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self) + static VALUE + ossl_rsa_to_der(VALUE self) + { +- RSA *rsa; +- const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; +- int (*i2d_func)(const RSA *, unsigned char **); +- unsigned char *ptr; +- long len; +- VALUE str; +- +- GetRSA(self, rsa); +- RSA_get0_key(rsa, &n, &e, &d); +- RSA_get0_factors(rsa, &p, &q); +- RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); +- if (n && e && d && p && q && dmp1 && dmq1 && iqmp) +- i2d_func = i2d_RSAPrivateKey; ++ if (can_export_rsaprivatekey(self)) ++ return ossl_pkey_export_traditional(0, NULL, self, 1); + else +- i2d_func = (int (*)(const RSA *, unsigned char **))i2d_RSA_PUBKEY; +- if((len = i2d_func(rsa, NULL)) <= 0) +- ossl_raise(eRSAError, NULL); +- str = rb_str_new(0, len); +- ptr = (unsigned char *)RSTRING_PTR(str); +- if(i2d_func(rsa, &ptr) < 0) +- ossl_raise(eRSAError, NULL); +- ossl_str_adjust(str, ptr); +- +- return str; ++ return ossl_pkey_export_spki(self, 1); + } + + /* +-- +2.32.0 + diff --git a/ruby-3.1.0-Support-GCCs-DWARF-5.patch b/ruby-3.1.0-Support-GCCs-DWARF-5.patch new file mode 100644 index 0000000..d9b434a --- /dev/null +++ b/ruby-3.1.0-Support-GCCs-DWARF-5.patch @@ -0,0 +1,229 @@ +From 3b91792d3d644d6d6b0059cb315c9fe5d3626bab Mon Sep 17 00:00:00 2001 +From: Yusuke Endoh +Date: Sat, 6 Mar 2021 00:03:57 +0900 +Subject: [PATCH] Support GCC's DWARF 5 [Bug #17585] + +Co-Authored-By: xtkoba (Tee KOBAYASHI) +--- + 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; diff --git a/ruby-3.1.0-Use-EVP-API-in-more-places.patch b/ruby-3.1.0-Use-EVP-API-in-more-places.patch new file mode 100644 index 0000000..f9c4580 --- /dev/null +++ b/ruby-3.1.0-Use-EVP-API-in-more-places.patch @@ -0,0 +1,831 @@ +From cf070378020088cd7e69b1cb08be68152ab8a078 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 +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 #=> # ++ # 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 +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 +@@ -172,6 +172,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 + diff --git a/ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.patch b/ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.patch new file mode 100644 index 0000000..dfdd690 --- /dev/null +++ b/ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.patch @@ -0,0 +1,114 @@ +From 8c185e0ae5e42bf5f3d76a1a0898946671116fa3 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 +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 ++ ++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: diff --git a/ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch b/ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch new file mode 100644 index 0000000..d02ce45 --- /dev/null +++ b/ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch @@ -0,0 +1,1113 @@ +From e8504c6248c4b0e5e961f57f004e1133c20c88a5 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 5 Apr 2021 00:30:01 +0900 +Subject: [PATCH 1/5] pkey: fix interrupt handling in + OpenSSL::PKey.generate_key + +rb_thread_call_without_gvl() can be interrupted, but it may be able to +resume the operation. Call rb_thread_check_ints() to see if it raises +an exception or not. +--- + ext/openssl/ossl_pkey.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 22e9f19982..d76f0600d1 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -239,7 +239,7 @@ struct pkey_blocking_generate_arg { + int state; + int yield: 1; + int genparam: 1; +- int stop: 1; ++ int interrupted: 1; + }; + + static VALUE +@@ -261,23 +261,31 @@ static int + pkey_gen_cb(EVP_PKEY_CTX *ctx) + { + struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx); ++ int state; + + if (arg->yield) { +- int state; + rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state); + if (state) { +- arg->stop = 1; + arg->state = state; ++ return 0; ++ } ++ } ++ if (arg->interrupted) { ++ arg->interrupted = 0; ++ state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL); ++ if (state) { ++ arg->state = state; ++ return 0; + } + } +- return !arg->stop; ++ return 1; + } + + static void + pkey_blocking_gen_stop(void *ptr) + { + struct pkey_blocking_generate_arg *arg = ptr; +- arg->stop = 1; ++ arg->interrupted = 1; + } + + static void * +-- +2.32.0 + + +From f433d1b680e7ac5ef13fc15b0844267222438cf3 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 17 May 2020 20:48:23 +0900 +Subject: [PATCH 2/5] pkey/dh: use high level EVP interface to generate + parameters and keys + +Implement PKey::DH.new(size, gen), PKey::DH.generate(size, gen), and +PKey::DH#generate_key! using PKey.generate_parameters and .generate_key +instead of the low level DH functions. + +Note that the EVP interface can enforce additional restrictions - for +example, DH key shorter than 2048 bits is no longer accepted by default +in OpenSSL 3.0. The test code is updated accordingly. +--- + ext/openssl/lib/openssl/pkey.rb | 57 ++++++++++ + ext/openssl/ossl_pkey_dh.c | 186 ++++++-------------------------- + test/openssl/test_pkey_dh.rb | 15 ++- + 3 files changed, 101 insertions(+), 157 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index be60ac2beb..5a3d0ed1ef 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -27,6 +27,63 @@ def compute_key(pub_bn) + peer.set_key(pub_bn, nil) + derive(peer) + end ++ ++ # :call-seq: ++ # dh.generate_key! -> self ++ # ++ # Generates a private and public key unless a private key already exists. ++ # If this DH instance was generated from public \DH parameters (e.g. by ++ # encoding the result of DH#public_key), then this method needs to be ++ # called first in order to generate the per-session keys before performing ++ # the actual key exchange. ++ # ++ # 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 ++ def generate_key! ++ unless priv_key ++ tmp = OpenSSL::PKey.generate_key(self) ++ set_key(tmp.pub_key, tmp.priv_key) ++ end ++ self ++ end ++ ++ class << self ++ # :call-seq: ++ # DH.generate(size, generator = 2) -> dh ++ # ++ # Creates a new DH instance from scratch by generating random parameters ++ # and a key pair. ++ # ++ # See also OpenSSL::PKey.generate_parameters and ++ # OpenSSL::PKey.generate_key. ++ # ++ # +size+:: ++ # The desired key size in bits. ++ # +generator+:: ++ # The generator. ++ def generate(size, generator = 2, &blk) ++ dhparams = OpenSSL::PKey.generate_parameters("DH", { ++ "dh_paramgen_prime_len" => size, ++ "dh_paramgen_generator" => generator, ++ }, &blk) ++ OpenSSL::PKey.generate_key(dhparams) ++ end ++ ++ # Handle DH.new(size, generator) form here; new(str) and new() forms ++ # are handled by #initialize ++ def new(*args, &blk) # :nodoc: ++ if args[0].is_a?(Integer) ++ generate(*args, &blk) ++ else ++ super ++ end ++ end ++ end + end + + class DSA +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index 5bc1c49ca1..6b477b077c 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -32,147 +32,56 @@ VALUE eDHError; + /* + * Private + */ +-struct dh_blocking_gen_arg { +- DH *dh; +- int size; +- int gen; +- BN_GENCB *cb; +- int result; +-}; +- +-static void * +-dh_blocking_gen(void *arg) +-{ +- struct dh_blocking_gen_arg *gen = (struct dh_blocking_gen_arg *)arg; +- gen->result = DH_generate_parameters_ex(gen->dh, gen->size, gen->gen, gen->cb); +- return 0; +-} +- +-static DH * +-dh_generate(int size, int gen) +-{ +- struct ossl_generate_cb_arg cb_arg = { 0 }; +- struct dh_blocking_gen_arg gen_arg; +- DH *dh = DH_new(); +- BN_GENCB *cb = BN_GENCB_new(); +- +- if (!dh || !cb) { +- DH_free(dh); +- BN_GENCB_free(cb); +- ossl_raise(eDHError, "malloc failure"); +- } +- +- if (rb_block_given_p()) +- cb_arg.yield = 1; +- BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); +- gen_arg.dh = dh; +- gen_arg.size = size; +- gen_arg.gen = gen; +- gen_arg.cb = cb; +- if (cb_arg.yield == 1) { +- /* we cannot release GVL when callback proc is supplied */ +- dh_blocking_gen(&gen_arg); +- } else { +- /* there's a chance to unblock */ +- rb_thread_call_without_gvl(dh_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); +- } +- +- BN_GENCB_free(cb); +- if (!gen_arg.result) { +- DH_free(dh); +- if (cb_arg.state) { +- /* Clear OpenSSL error queue before re-raising. */ +- ossl_clear_error(); +- rb_jump_tag(cb_arg.state); +- } +- ossl_raise(eDHError, "DH_generate_parameters_ex"); +- } +- +- if (!DH_generate_key(dh)) { +- DH_free(dh); +- ossl_raise(eDHError, "DH_generate_key"); +- } +- +- return dh; +-} +- +-/* +- * call-seq: +- * DH.generate(size [, generator]) -> dh +- * +- * Creates a new DH instance from scratch by generating the private and public +- * components alike. +- * +- * === Parameters +- * * _size_ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure. +- * * _generator_ is a small number > 1, typically 2 or 5. +- * +- */ +-static VALUE +-ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) +-{ +- EVP_PKEY *pkey; +- DH *dh ; +- int g = 2; +- VALUE size, gen, obj; +- +- if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) { +- g = NUM2INT(gen); +- } +- obj = rb_obj_alloc(klass); +- GetPKey(obj, pkey); +- +- dh = dh_generate(NUM2INT(size), g); +- if (!EVP_PKEY_assign_DH(pkey, dh)) { +- DH_free(dh); +- ossl_raise(eDHError, "EVP_PKEY_assign_DH"); +- } +- return obj; +-} +- + /* + * call-seq: + * DH.new -> dh + * DH.new(string) -> dh + * DH.new(size [, generator]) -> dh + * +- * Either generates a DH instance from scratch or by reading already existing +- * DH parameters from _string_. Note that when reading a DH instance from +- * data that was encoded from a DH instance by using DH#to_pem or DH#to_der +- * the result will *not* contain a public/private key pair yet. This needs to +- * be generated using DH#generate_key! first. ++ * Creates a new instance of OpenSSL::PKey::DH. ++ * ++ * If called without arguments, an empty instance without any parameter or key ++ * components is created. Use #set_pqg to manually set the parameters afterwards ++ * (and optionally #set_key to set private and public key components). ++ * ++ * If a String is given, tries to parse it as a DER- or PEM- encoded parameters. ++ * See also OpenSSL::PKey.read which can parse keys of any kinds. ++ * ++ * The DH.new(size [, generator]) form is an alias of DH.generate. + * +- * === Parameters +- * * _size_ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure. +- * * _generator_ is a small number > 1, typically 2 or 5. +- * * _string_ contains the DER or PEM encoded key. ++ * +string+:: ++ * A String that contains the DER or PEM encoded key. ++ * +size+:: ++ * See DH.generate. ++ * +generator+:: ++ * See DH.generate. + * +- * === Examples +- * DH.new # -> dh +- * DH.new(1024) # -> dh +- * DH.new(1024, 5) # -> dh +- * #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 ++ * Examples: ++ * # Creating an instance from scratch ++ * dh = 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) ++ * ++ * # 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 + */ + static VALUE + ossl_dh_initialize(int argc, VALUE *argv, VALUE self) + { + EVP_PKEY *pkey; + DH *dh; +- int g = 2; + BIO *in; +- VALUE arg, gen; ++ VALUE arg; + + GetPKey(self, pkey); +- if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) { +- dh = DH_new(); +- } +- else if (RB_INTEGER_TYPE_P(arg)) { +- if (!NIL_P(gen)) { +- g = NUM2INT(gen); +- } +- dh = dh_generate(NUM2INT(arg), g); ++ /* 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"); + } + else { + arg = ossl_to_der_if_possible(arg); +@@ -449,33 +358,6 @@ ossl_dh_check_params(VALUE self) + return codes == 0 ? Qtrue : Qfalse; + } + +-/* +- * call-seq: +- * dh.generate_key! -> self +- * +- * Generates a private and public key unless a private key already exists. +- * If this DH instance was generated from public DH parameters (e.g. by +- * encoding the result of DH#public_key), then this method needs to be +- * called first in order to generate the per-session keys before performing +- * the actual key exchange. +- * +- * === 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 +- */ +-static VALUE +-ossl_dh_generate_key(VALUE self) +-{ +- DH *dh; +- +- GetDH(self, dh); +- if (!DH_generate_key(dh)) +- ossl_raise(eDHError, "Failed to generate key"); +- return self; +-} +- + /* + * Document-method: OpenSSL::PKey::DH#set_pqg + * call-seq: +@@ -540,7 +422,6 @@ Init_ossl_dh(void) + * puts symm_key1 == symm_key2 # => true + */ + cDH = rb_define_class_under(mPKey, "DH", cPKey); +- rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1); + rb_define_method(cDH, "initialize", ossl_dh_initialize, -1); + rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1); + rb_define_method(cDH, "public?", ossl_dh_is_public, 0); +@@ -552,7 +433,6 @@ Init_ossl_dh(void) + 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); +- rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0); + + DEF_OSSL_PKEY_BN(cDH, dh, p); + DEF_OSSL_PKEY_BN(cDH, dh, q); +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index 9efc3ba68d..279ce1984c 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -4,12 +4,19 @@ + if defined?(OpenSSL) && defined?(OpenSSL::PKey::DH) + + class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase +- NEW_KEYLEN = 256 ++ NEW_KEYLEN = 2048 + +- def test_new ++ def test_new_empty ++ dh = OpenSSL::PKey::DH.new ++ assert_equal nil, dh.p ++ assert_equal nil, dh.priv_key ++ end ++ ++ def test_new_generate ++ # This test is slow + dh = OpenSSL::PKey::DH.new(NEW_KEYLEN) + assert_key(dh) +- end ++ end if ENV["OSSL_TEST_ALL"] + + def test_new_break + assert_nil(OpenSSL::PKey::DH.new(NEW_KEYLEN) { break }) +@@ -80,7 +87,7 @@ def test_key_exchange + end + + def test_dup +- dh = OpenSSL::PKey::DH.new(NEW_KEYLEN) ++ dh = Fixtures.pkey("dh1024") + dh2 = dh.dup + assert_equal dh.to_der, dh2.to_der # params + assert_equal_params dh, dh2 # keys +-- +2.32.0 + + +From ba1d1d68ac2b489691eb3fe2052e77b3e57a372b Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 17 May 2020 20:48:23 +0900 +Subject: [PATCH 3/5] pkey/rsa: use high level EVP interface to generate + parameters and keys + +Implement PKey::RSA.new(size, exponent) and PKey::RSA.generate using +OpenSSL::PKey.generate_key instead of the low level RSA functions. +--- + ext/openssl/lib/openssl/pkey.rb | 30 ++++++++ + ext/openssl/ossl_pkey_rsa.c | 132 ++++---------------------------- + 2 files changed, 46 insertions(+), 116 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 5a3d0ed1ef..3bef06e3b3 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -128,5 +128,35 @@ def to_bn(conversion_form = group.point_conversion_form) + + class RSA + include OpenSSL::Marshal ++ ++ class << self ++ # :call-seq: ++ # RSA.generate(size, exponent = 65537) -> RSA ++ # ++ # Generates an \RSA keypair. ++ # ++ # See also OpenSSL::PKey.generate_key. ++ # ++ # +size+:: ++ # The desired key size in bits. ++ # +exponent+:: ++ # An odd Integer, normally 3, 17, or 65537. ++ def generate(size, exp = 0x10001, &blk) ++ OpenSSL::PKey.generate_key("RSA", { ++ "rsa_keygen_bits" => size, ++ "rsa_keygen_pubexp" => exp, ++ }, &blk) ++ end ++ ++ # Handle RSA.new(size, exponent) form here; new(str) and new() forms ++ # are handled by #initialize ++ def new(*args, &blk) # :nodoc: ++ if args[0].is_a?(Integer) ++ generate(*args, &blk) ++ else ++ super ++ end ++ end ++ end + end + end +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 3c298a2aea..43f82cb29e 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -47,125 +47,28 @@ VALUE eRSAError; + /* + * Private + */ +-struct rsa_blocking_gen_arg { +- RSA *rsa; +- BIGNUM *e; +- int size; +- BN_GENCB *cb; +- int result; +-}; +- +-static void * +-rsa_blocking_gen(void *arg) +-{ +- struct rsa_blocking_gen_arg *gen = (struct rsa_blocking_gen_arg *)arg; +- gen->result = RSA_generate_key_ex(gen->rsa, gen->size, gen->e, gen->cb); +- return 0; +-} +- +-static RSA * +-rsa_generate(int size, unsigned long exp) +-{ +- int i; +- struct ossl_generate_cb_arg cb_arg = { 0 }; +- struct rsa_blocking_gen_arg gen_arg; +- RSA *rsa = RSA_new(); +- BIGNUM *e = BN_new(); +- BN_GENCB *cb = BN_GENCB_new(); +- +- if (!rsa || !e || !cb) { +- RSA_free(rsa); +- BN_free(e); +- BN_GENCB_free(cb); +- ossl_raise(eRSAError, "malloc failure"); +- } +- for (i = 0; i < (int)sizeof(exp) * 8; ++i) { +- if (exp & (1UL << i)) { +- if (BN_set_bit(e, i) == 0) { +- BN_free(e); +- RSA_free(rsa); +- BN_GENCB_free(cb); +- ossl_raise(eRSAError, "BN_set_bit"); +- } +- } +- } +- +- if (rb_block_given_p()) +- cb_arg.yield = 1; +- BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); +- gen_arg.rsa = rsa; +- gen_arg.e = e; +- gen_arg.size = size; +- gen_arg.cb = cb; +- if (cb_arg.yield == 1) { +- /* we cannot release GVL when callback proc is supplied */ +- rsa_blocking_gen(&gen_arg); +- } else { +- /* there's a chance to unblock */ +- rb_thread_call_without_gvl(rsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); +- } +- +- BN_GENCB_free(cb); +- BN_free(e); +- if (!gen_arg.result) { +- RSA_free(rsa); +- if (cb_arg.state) { +- /* must clear OpenSSL error stack */ +- ossl_clear_error(); +- rb_jump_tag(cb_arg.state); +- } +- ossl_raise(eRSAError, "RSA_generate_key_ex"); +- } +- +- return rsa; +-} +- + /* + * call-seq: +- * RSA.generate(size) => RSA instance +- * RSA.generate(size, exponent) => RSA instance ++ * RSA.new -> rsa ++ * RSA.new(encoded_key [, passphrase]) -> rsa ++ * RSA.new(encoded_key) { passphrase } -> rsa ++ * RSA.new(size [, exponent]) -> rsa + * +- * Generates an RSA keypair. _size_ is an integer representing the desired key +- * size. Keys smaller than 1024 should be considered insecure. _exponent_ is +- * an odd number normally 3, 17, or 65537. +- */ +-static VALUE +-ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) +-{ +-/* why does this method exist? why can't initialize take an optional exponent? */ +- EVP_PKEY *pkey; +- RSA *rsa; +- VALUE size, exp; +- VALUE obj; +- +- rb_scan_args(argc, argv, "11", &size, &exp); +- obj = rb_obj_alloc(klass); +- GetPKey(obj, pkey); +- +- rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp)); +- if (!EVP_PKEY_assign_RSA(pkey, rsa)) { +- RSA_free(rsa); +- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); +- } +- return obj; +-} +- +-/* +- * call-seq: +- * RSA.new(size [, exponent]) => RSA instance +- * RSA.new(encoded_key) => RSA instance +- * RSA.new(encoded_key, pass_phrase) => RSA instance ++ * Generates or loads an \RSA keypair. + * +- * Generates or loads an RSA keypair. If an integer _key_size_ is given it +- * represents the desired key size. Keys less than 1024 bits should be +- * considered insecure. ++ * If called without arguments, creates a new instance with no key components ++ * set. They can be set individually by #set_key, #set_factors, and ++ * #set_crt_params. + * +- * A key can instead be loaded from an _encoded_key_ which must be PEM or DER +- * encoded. A _pass_phrase_ can be used to decrypt the key. If none is given +- * OpenSSL will prompt for the pass phrase. ++ * If called with a String, tries to parse as DER or PEM encoding of an \RSA key. ++ * Note that, if _passphrase_ is not specified but the key is encrypted with a ++ * passphrase, \OpenSSL will prompt for it. ++ * See also OpenSSL::PKey.read which can parse keys of any kinds. + * +- * = Examples ++ * If called with a number, generates a new key pair. This form works as an ++ * alias of RSA.generate. + * ++ * Examples: + * OpenSSL::PKey::RSA.new 2048 + * OpenSSL::PKey::RSA.new File.read 'rsa.pem' + * OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my pass phrase' +@@ -179,15 +82,13 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + VALUE arg, pass; + + 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"); + } +- else if (RB_INTEGER_TYPE_P(arg)) { +- rsa = rsa_generate(NUM2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2ULONG(pass)); +- } + else { + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); +@@ -832,7 +733,6 @@ Init_ossl_rsa(void) + */ + cRSA = rb_define_class_under(mPKey, "RSA", cPKey); + +- rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1); + rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1); + rb_define_method(cRSA, "initialize_copy", ossl_rsa_initialize_copy, 1); + +-- +2.32.0 + + +From a6c4a8116c09243c39cc8d1e7ececcd8be0cfaf2 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 17 May 2020 22:14:03 +0900 +Subject: [PATCH 4/5] pkey/dsa: use high level EVP interface to generate + parameters and keys + +Implement PKey::DSA.new(size) and PKey::DSA.generate using +OpenSSL::PKey.generate_parameters and .generate_key instead of the low +level DSA functions. +--- + ext/openssl/lib/openssl/pkey.rb | 30 +++++++ + ext/openssl/ossl_pkey_dsa.c | 140 ++++++-------------------------- + test/openssl/test_pkey_dsa.rb | 23 ++---- + 3 files changed, 64 insertions(+), 129 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 3bef06e3b3..53ee52f98b 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -88,6 +88,36 @@ def new(*args, &blk) # :nodoc: + + class DSA + include OpenSSL::Marshal ++ ++ class << self ++ # :call-seq: ++ # DSA.generate(size) -> dsa ++ # ++ # Creates a new DSA instance by generating a private/public key pair ++ # from scratch. ++ # ++ # See also OpenSSL::PKey.generate_parameters and ++ # OpenSSL::PKey.generate_key. ++ # ++ # +size+:: ++ # The desired key size in bits. ++ def generate(size, &blk) ++ dsaparams = OpenSSL::PKey.generate_parameters("DSA", { ++ "dsa_paramgen_bits" => size, ++ }, &blk) ++ OpenSSL::PKey.generate_key(dsaparams) ++ end ++ ++ # Handle DSA.new(size) form here; new(str) and new() forms ++ # are handled by #initialize ++ def new(*args, &blk) # :nodoc: ++ if args[0].is_a?(Integer) ++ generate(*args, &blk) ++ else ++ super ++ end ++ end ++ end + end + + if defined?(EC) +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index 0e68f7f27f..1c5a8a737e 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -46,126 +46,39 @@ VALUE eDSAError; + /* + * Private + */ +-struct dsa_blocking_gen_arg { +- DSA *dsa; +- int size; +- int *counter; +- unsigned long *h; +- BN_GENCB *cb; +- int result; +-}; +- +-static void * +-dsa_blocking_gen(void *arg) +-{ +- struct dsa_blocking_gen_arg *gen = (struct dsa_blocking_gen_arg *)arg; +- gen->result = DSA_generate_parameters_ex(gen->dsa, gen->size, NULL, 0, +- gen->counter, gen->h, gen->cb); +- return 0; +-} +- +-static DSA * +-dsa_generate(int size) +-{ +- struct ossl_generate_cb_arg cb_arg = { 0 }; +- struct dsa_blocking_gen_arg gen_arg; +- DSA *dsa = DSA_new(); +- BN_GENCB *cb = BN_GENCB_new(); +- int counter; +- unsigned long h; +- +- if (!dsa || !cb) { +- DSA_free(dsa); +- BN_GENCB_free(cb); +- ossl_raise(eDSAError, "malloc failure"); +- } +- +- if (rb_block_given_p()) +- cb_arg.yield = 1; +- BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); +- gen_arg.dsa = dsa; +- gen_arg.size = size; +- gen_arg.counter = &counter; +- gen_arg.h = &h; +- gen_arg.cb = cb; +- if (cb_arg.yield == 1) { +- /* we cannot release GVL when callback proc is supplied */ +- dsa_blocking_gen(&gen_arg); +- } else { +- /* there's a chance to unblock */ +- rb_thread_call_without_gvl(dsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); +- } +- +- BN_GENCB_free(cb); +- if (!gen_arg.result) { +- DSA_free(dsa); +- if (cb_arg.state) { +- /* Clear OpenSSL error queue before re-raising. By the way, the +- * documentation of DSA_generate_parameters_ex() says the error code +- * can be obtained by ERR_get_error(), but the default +- * implementation, dsa_builtin_paramgen() doesn't put any error... */ +- ossl_clear_error(); +- rb_jump_tag(cb_arg.state); +- } +- ossl_raise(eDSAError, "DSA_generate_parameters_ex"); +- } +- +- if (!DSA_generate_key(dsa)) { +- DSA_free(dsa); +- ossl_raise(eDSAError, "DSA_generate_key"); +- } +- +- return dsa; +-} +- +-/* +- * call-seq: +- * DSA.generate(size) -> dsa +- * +- * Creates a new DSA instance by generating a private/public key pair +- * from scratch. +- * +- * === Parameters +- * * _size_ is an integer representing the desired key size. +- * +- */ +-static VALUE +-ossl_dsa_s_generate(VALUE klass, VALUE size) +-{ +- EVP_PKEY *pkey; +- DSA *dsa; +- VALUE obj; +- +- obj = rb_obj_alloc(klass); +- GetPKey(obj, pkey); +- +- dsa = dsa_generate(NUM2INT(size)); +- if (!EVP_PKEY_assign_DSA(pkey, dsa)) { +- DSA_free(dsa); +- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); +- } +- return obj; +-} +- + /* + * call-seq: + * DSA.new -> dsa +- * DSA.new(size) -> dsa + * DSA.new(string [, pass]) -> dsa ++ * DSA.new(size) -> dsa + * + * Creates a new DSA instance by reading an existing key from _string_. + * +- * === Parameters +- * * _size_ is an integer representing the desired key size. +- * * _string_ contains a DER or PEM encoded key. +- * * _pass_ is a string that contains an optional password. ++ * If called without arguments, creates a new instance with no key components ++ * set. They can be set individually by #set_pqg and #set_key. + * +- * === Examples +- * DSA.new -> dsa +- * DSA.new(1024) -> dsa +- * DSA.new(File.read('dsa.pem')) -> dsa +- * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa ++ * If called with a String, tries to parse as DER or PEM encoding of a \DSA key. ++ * See also OpenSSL::PKey.read which can parse keys of any kinds. ++ * ++ * If called with a number, generates random parameters and a key pair. This ++ * form works as an alias of DSA.generate. ++ * ++ * +string+:: ++ * A String that contains a DER or PEM encoded key. ++ * +pass+:: ++ * A String that contains an optional password. ++ * +size+:: ++ * See DSA.generate. + * ++ * Examples: ++ * p OpenSSL::PKey::DSA.new(1024) ++ * #=> # ++ * ++ * p OpenSSL::PKey::DSA.new(File.read('dsa.pem')) ++ * #=> # ++ * ++ * p OpenSSL::PKey::DSA.new(File.read('dsa.pem'), 'mypassword') ++ * #=> # + */ + static VALUE + ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) +@@ -176,15 +89,13 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) + VALUE arg, pass; + + 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"); + } +- else if (argc == 1 && RB_INTEGER_TYPE_P(arg)) { +- dsa = dsa_generate(NUM2INT(arg)); +- } + else { + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); +@@ -553,7 +464,6 @@ Init_ossl_dsa(void) + */ + cDSA = rb_define_class_under(mPKey, "DSA", cPKey); + +- rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1); + rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1); + rb_define_method(cDSA, "initialize_copy", ossl_dsa_initialize_copy, 1); + +diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb +index 4bf8a7b374..85bb6ec0ae 100644 +--- a/test/openssl/test_pkey_dsa.rb ++++ b/test/openssl/test_pkey_dsa.rb +@@ -5,31 +5,26 @@ + + class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase + def test_private +- key = OpenSSL::PKey::DSA.new(256) +- assert(key.private?) ++ key = Fixtures.pkey("dsa1024") ++ assert_equal true, key.private? + key2 = OpenSSL::PKey::DSA.new(key.to_der) +- assert(key2.private?) ++ assert_equal true, key2.private? + key3 = key.public_key +- assert(!key3.private?) ++ assert_equal false, key3.private? + key4 = OpenSSL::PKey::DSA.new(key3.to_der) +- assert(!key4.private?) ++ assert_equal false, key4.private? + end + + def test_new +- key = OpenSSL::PKey::DSA.new 256 ++ key = OpenSSL::PKey::DSA.new(2048) + pem = key.public_key.to_pem + OpenSSL::PKey::DSA.new pem +- if $0 == __FILE__ +- assert_nothing_raised { +- key = OpenSSL::PKey::DSA.new 2048 +- } +- end + end + + def test_new_break +- assert_nil(OpenSSL::PKey::DSA.new(512) { break }) ++ assert_nil(OpenSSL::PKey::DSA.new(2048) { break }) + assert_raise(RuntimeError) do +- OpenSSL::PKey::DSA.new(512) { raise } ++ OpenSSL::PKey::DSA.new(2048) { raise } + end + end + +@@ -184,7 +179,7 @@ def test_read_DSAPublicKey_pem + end + + def test_dup +- key = OpenSSL::PKey::DSA.new(256) ++ key = Fixtures.pkey("dsa1024") + key2 = key.dup + assert_equal key.params, key2.params + key2.set_pqg(key2.p + 1, key2.q, key2.g) +-- +2.32.0 + + +From ba5a3a5c3eabf969f5cd2232b022e440af803b5b Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 5 Apr 2021 00:39:04 +0900 +Subject: [PATCH 5/5] pkey: remove unused ossl_generate_cb_2() helper function + +The previous series of commits re-implemented key generation with the +low level API with the EVP API. The BN_GENCB-based callback function is +no longer used. +--- + ext/openssl/extconf.rb | 3 -- + ext/openssl/openssl_missing.h | 12 ------ + ext/openssl/ossl_pkey.c | 73 +++++++---------------------------- + ext/openssl/ossl_pkey.h | 8 ---- + 4 files changed, 15 insertions(+), 81 deletions(-) + +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index 693e55cd97..b3c6647faf 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -136,9 +136,6 @@ def find_openssl_library + $defs.push("-DHAVE_OPAQUE_OPENSSL") + end + have_func("CRYPTO_lock") || $defs.push("-DHAVE_OPENSSL_110_THREADING_API") +-have_func("BN_GENCB_new") +-have_func("BN_GENCB_free") +-have_func("BN_GENCB_get_arg") + have_func("EVP_MD_CTX_new") + have_func("EVP_MD_CTX_free") + have_func("EVP_MD_CTX_pkey_ctx") +diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h +index 7d218f86f5..e575415f49 100644 +--- a/ext/openssl/openssl_missing.h ++++ b/ext/openssl/openssl_missing.h +@@ -34,18 +34,6 @@ int ossl_EC_curve_nist2nid(const char *); + #endif + + /* added in 1.1.0 */ +-#if !defined(HAVE_BN_GENCB_NEW) +-# define BN_GENCB_new() ((BN_GENCB *)OPENSSL_malloc(sizeof(BN_GENCB))) +-#endif +- +-#if !defined(HAVE_BN_GENCB_FREE) +-# define BN_GENCB_free(cb) OPENSSL_free(cb) +-#endif +- +-#if !defined(HAVE_BN_GENCB_GET_ARG) +-# define BN_GENCB_get_arg(cb) (cb)->arg +-#endif +- + #if !defined(HAVE_EVP_MD_CTX_NEW) + # define EVP_MD_CTX_new EVP_MD_CTX_create + #endif +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index d76f0600d1..f9282b9417 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -17,64 +17,6 @@ VALUE cPKey; + VALUE ePKeyError; + static ID id_private_q; + +-/* +- * callback for generating keys +- */ +-static VALUE +-call_check_ints0(VALUE arg) +-{ +- rb_thread_check_ints(); +- return Qnil; +-} +- +-static void * +-call_check_ints(void *arg) +-{ +- int state; +- rb_protect(call_check_ints0, Qnil, &state); +- return (void *)(VALUE)state; +-} +- +-int +-ossl_generate_cb_2(int p, int n, BN_GENCB *cb) +-{ +- VALUE ary; +- struct ossl_generate_cb_arg *arg; +- int state; +- +- arg = (struct ossl_generate_cb_arg *)BN_GENCB_get_arg(cb); +- if (arg->yield) { +- ary = rb_ary_new2(2); +- rb_ary_store(ary, 0, INT2NUM(p)); +- rb_ary_store(ary, 1, INT2NUM(n)); +- +- /* +- * can be break by raising exception or 'break' +- */ +- rb_protect(rb_yield, ary, &state); +- if (state) { +- arg->state = state; +- return 0; +- } +- } +- if (arg->interrupted) { +- arg->interrupted = 0; +- state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL); +- if (state) { +- arg->state = state; +- return 0; +- } +- } +- return 1; +-} +- +-void +-ossl_generate_cb_stop(void *ptr) +-{ +- struct ossl_generate_cb_arg *arg = (struct ossl_generate_cb_arg *)ptr; +- arg->interrupted = 1; +-} +- + static void + ossl_evp_pkey_free(void *ptr) + { +@@ -257,6 +199,21 @@ pkey_gen_cb_yield(VALUE ctx_v) + return rb_yield_values2(info_num, argv); + } + ++static VALUE ++call_check_ints0(VALUE arg) ++{ ++ rb_thread_check_ints(); ++ return Qnil; ++} ++ ++static void * ++call_check_ints(void *arg) ++{ ++ int state; ++ rb_protect(call_check_ints0, Qnil, &state); ++ return (void *)(VALUE)state; ++} ++ + static int + pkey_gen_cb(EVP_PKEY_CTX *ctx) + { +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index 7dbaed47bc..629c16ae1f 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -35,14 +35,6 @@ extern const rb_data_type_t ossl_evp_pkey_type; + } \ + } while (0) + +-struct ossl_generate_cb_arg { +- int yield; +- int interrupted; +- int state; +-}; +-int ossl_generate_cb_2(int p, int n, BN_GENCB *cb); +-void ossl_generate_cb_stop(void *ptr); +- + VALUE ossl_pkey_new(EVP_PKEY *); + void ossl_pkey_check_public_key(const EVP_PKEY *); + EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE); +-- +2.32.0 + diff --git a/ruby-3.1.0-Use-mmap-for-allocating-heap-pages-in-the-GC.patch b/ruby-3.1.0-Use-mmap-for-allocating-heap-pages-in-the-GC.patch new file mode 100644 index 0000000..512be18 --- /dev/null +++ b/ruby-3.1.0-Use-mmap-for-allocating-heap-pages-in-the-GC.patch @@ -0,0 +1,359 @@ +From bcab8c3cd877506de75f50e0f9ed98827ed554b0 Mon Sep 17 00:00:00 2001 +From: Peter Zhu +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 +@@ -1944,6 +1944,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) +@@ -2666,6 +2667,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 + #include + ++/* 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 ++#endif ++/* MALLOC_HEADERS_END */ ++ + #ifdef HAVE_SYS_TIME_H + # include + #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) + diff --git a/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch b/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch new file mode 100644 index 0000000..b8f727d --- /dev/null +++ b/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch @@ -0,0 +1,29 @@ +From a9977ba2f9863e3fb1b2346589ebbca67d80536c Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +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; diff --git a/ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch b/ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch new file mode 100644 index 0000000..5f3445e --- /dev/null +++ b/ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch @@ -0,0 +1,29 @@ +From b4b5eab2a5fd0e9ac62c01102dd26d0a433c5683 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 + diff --git a/ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch b/ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch new file mode 100644 index 0000000..80b73d2 --- /dev/null +++ b/ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch @@ -0,0 +1,439 @@ +From 9596788bdd2d061bef042485af14262e9fc4020c Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 -export -out +- str = <<~EOF.unpack("m").first +-MIIGQQIBAzCCBgcGCSqGSIb3DQEHAaCCBfgEggX0MIIF8DCCAu8GCSqGSIb3DQEH +-BqCCAuAwggLcAgEAMIIC1QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIeZPM +-Rh6KiXgCAggAgIICqL6O+LCZmBzdIg6mozPF3FpY0hVbWHvTNMiDHieW3CrAanhN +-YCH2/wHqH8WpFpEWwF0qEEXAWjHsIlYB4Cfqo6b7XpuZe5eVESsjNTOTMF1JCUJj +-A6iNefXmCFLync1JK5LUodRDhTlKLU1WPK20X9X4vuEwHn8wt5RUb8P0E+Xh6rpS +-XC4LkZKT45zF3cJa/n5+dW65ohVGNVnF9D1bCNEKHMOllK1V9omutQ9slW88hpga +-LGiFsJoFOb/ESGb78KO+bd6zbX1MdKdBV+WD6t1uF/cgU65y+2A4nXs1urda+MJ7 +-7iVqiB7Vnc9cANTbAkTSGNyoUDVM/NZde782/8IvddLAzUZ2EftoRDke6PvuBOVL +-ljBhNWmdamrtBqzuzVZCRdWq44KZkF2Xoc9asepwIkdVmntzQF7f1Z+Ta5yg6HFp +-xnr7CuM+MlHEShXkMgYtHnwAq10fDMSXIvjhi/AA5XUAusDO3D+hbtcRDcJ4uUes +-dm5dhQE2qJ02Ysn4aH3o1F3RYNOzrxejHJwl0D2TCE8Ww2X342xib57+z9u03ufj +-jswhiMKxy67f1LhUMq3XrT3uV6kCVXk/KUOUPcXPlPVNA5JmZeFhMp6GrtB5xJJ9 +-wwBZD8UL5A2U2Mxi2OZsdUBv8eo3jnjZ284aFpt+mCjIHrLW5O0jwY8OCwSlYUoY +-IY00wlabX0s82kBcIQNZbC1RSV2267ro/7A0MClc8YQ/zWN0FKY6apgtUkHJI1cL +-1dc77mhnjETjwW94iLMDFy4zQfVu7IfCBqOBzygRNnqqUG66UhTs1xFnWM0mWXl/ +-Zh9+AMpbRLIPaKCktIjl5juzzm+KEgkhD+707XRCFIGUYGP5bSHzGaz8PK9hj0u1 +-E2SpZHUvYOcawmxtA7pmpSxl5uQjMIIC+QYJKoZIhvcNAQcBoIIC6gSCAuYwggLi +-MIIC3gYLKoZIhvcNAQwKAQKgggKmMIICojAcBgoqhkiG9w0BDAEDMA4ECKB338m8 +-qSzHAgIIAASCAoACFhJeqA3xx+s1qIH6udNQYY5hAL6oz7SXoGwFhDiceSyJjmAD +-Dby9XWM0bPl1Gj5nqdsuI/lAM++fJeoETk+rxw8q6Ofk2zUaRRE39qgpwBwSk44o +-0SAFJ6bzHpc5CFh6sZmDaUX5Lm9GtjnGFmmsPTSJT5an5JuJ9WczGBEd0nSBQhJq +-xHbTGZiN8i3SXcIH531Sub+CBIFWy5lyCKgDYh/kgJFGQAaWUOjLI+7dCEESonXn +-F3Jh2uPbnDF9MGJyAFoNgWFhgSpi1cf6AUi87GY4Oyur88ddJ1o0D0Kz2uw8/bpG +-s3O4PYnIW5naZ8mozzbnYByEFk7PoTwM7VhoFBfYNtBoAI8+hBnPY/Y71YUojEXf +-SeX6QbtkIANfzS1XuFNKElShC3DPQIHpKzaatEsfxHfP+8VOav6zcn4mioao7NHA +-x7Dp6R1enFGoQOq4UNjBT8YjnkG5vW8zQHW2dAHLTJBq6x2Fzm/4Pjo/8vM1FiGl +-BQdW5vfDeJ/l6NgQm3xR9ka2E2HaDqIcj1zWbN8jy/bHPFJYuF/HH8MBV/ngMIXE +-vFEW/ToYv8eif0+EpUtzBsCKD4a7qYYYh87RmEVoQU96q6m+UbhpD2WztYfAPkfo +-OSL9j2QHhVczhL7OAgqNeM95pOsjA9YMe7exTeqK31LYnTX8oH8WJD1xGbRSJYgu +-SY6PQbumcJkc/TFPn0GeVUpiDdf83SeG50lo/i7UKQi2l1hi5Y51fQhnBnyMr68D +-llSZEvSWqfDxBJkBpeg6PIYvkTpEwKRJpVQoM3uYvdqVSSnW6rydqIb+snfOrlhd +-f+xCtq9xr+kHeTSqLIDRRAnMfgFRhY3IBlj6MSUwIwYJKoZIhvcNAQkVMRYEFBdb +-8XGWehZ6oPj56Pf/uId46M9AMDEwITAJBgUrDgMCGgUABBRvSCB04/f8f13pp2PF +-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 ++ # openssl pkcs12 -certpbe PBE-SHA1-3DES -in <@mycert> -nokeys -export + str = <<~EOF.unpack("m").first +-MIIDHAIBAzCCAuIGCSqGSIb3DQEHAaCCAtMEggLPMIICyzCCAscGCSqGSIb3DQEH +-BqCCArgwggK0AgEAMIICrQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIX4+W +-irqwH40CAggAgIICgOaCyo+5+6IOVoGCCL80c50bkkzAwqdXxvkKExJSdcJz2uMU +-0gRrKnZEjL5wrUsN8RwZu8DvgQTEhNEkKsUgM7AWainmN/EnwohIdHZAHpm6WD67 +-I9kLGp0/DHrqZrV9P2dLfhXLUSQE8PI0tqZPZ8UEABhizkViw4eISTkrOUN7pGbN +-Qtx/oqgitXDuX2polbxYYDwt9vfHZhykHoKgew26SeJyZfeMs/WZ6olEI4cQUAFr +-mvYGuC1AxEGTo9ERmU8Pm16j9Hr9PFk50WYe+rnk9oX3wJogQ7XUWS5kYf7XRycd +-NDkNiwV/ts94bbuaGZp1YA6I48FXpIc8b5fX7t9tY0umGaWy0bARe1L7o0Y89EPe +-lMg25rOM7j3uPtFG8whbSfdETSy57UxzzTcJ6UwexeaK6wb2jqEmj5AOoPLWeaX0 +-LyOAszR3v7OPAcjIDYZGdrbb3MZ2f2vo2pdQfu9698BrWhXuM7Odh73RLhJVreNI +-aezNOAtPyBlvGiBQBGTzRIYHSLL5Y5aVj2vWLAa7hjm5qTL5C5mFdDIo6TkEMr6I +-OsexNQofEGs19kr8nARXDlcbEimk2VsPj4efQC2CEXZNzURsKca82pa62MJ8WosB +-DTFd8X06zZZ4nED50vLopZvyW4fyW60lELwOyThAdG8UchoAaz2baqP0K4de44yM +-Y5/yPFDu4+GoimipJfbiYviRwbzkBxYW8+958ILh0RtagLbvIGxbpaym9PqGjOzx +-ShNXjLK2aAFZsEizQ8kd09quJHU/ogq2cUXdqqhmOqPnUWrJVi/VCoRB3Pv1/lE4 +-mrUgr2YZ11rYvBw6g5XvNvFcSc53OKyV7SLn0dwwMTAhMAkGBSsOAwIaBQAEFEWP +-1WRQykaoD4uJCpTx/wv0SLLBBAiDKI26LJK7xgICCAA= ++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 -nocerts -export -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 + diff --git a/ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch b/ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch new file mode 100644 index 0000000..ac45842 --- /dev/null +++ b/ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch @@ -0,0 +1,67 @@ +From 10d2216b2f35a31777a099d9f765b0b6ea34a63e Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 + diff --git a/ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch b/ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch new file mode 100644 index 0000000..c9421bc --- /dev/null +++ b/ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch @@ -0,0 +1,31 @@ +From 05fd14aea7eff2a6911a6f529f1237276482c6e7 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 + diff --git a/ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch b/ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch new file mode 100644 index 0000000..2019380 --- /dev/null +++ b/ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch @@ -0,0 +1,265 @@ +From 2c6797bc97d7c92284dc3c0ed27f97ace4e5cfb9 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 + diff --git a/ruby-3.1.1-ossl_ocsp-use-null.patch b/ruby-3.1.1-ossl_ocsp-use-null.patch new file mode 100644 index 0000000..d6d39ef --- /dev/null +++ b/ruby-3.1.1-ossl_ocsp-use-null.patch @@ -0,0 +1,31 @@ +--- 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 diff --git a/ruby-3.1.2-ossl-tests-replace-sha1.patch b/ruby-3.1.2-ossl-tests-replace-sha1.patch new file mode 100644 index 0000000..176101c --- /dev/null +++ b/ruby-3.1.2-ossl-tests-replace-sha1.patch @@ -0,0 +1,647 @@ +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 +@@ -174,6 +174,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. UNIVERSAL_TAG_NAME[2] = "INTEGER" and OpenSSL::ASN1::INTEGER = 2. + * + * == 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. diff --git a/ruby-bundler-raise-error-in-dependency-confusion.patch b/ruby-bundler-raise-error-in-dependency-confusion.patch new file mode 100644 index 0000000..5800852 --- /dev/null +++ b/ruby-bundler-raise-error-in-dependency-confusion.patch @@ -0,0 +1,422 @@ +diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb +index 8e56d4a9bc..c37946b46c 100644 +--- a/lib/bundler/definition.rb ++++ b/lib/bundler/definition.rb +@@ -910,6 +910,8 @@ def source_requirements + # Load all specs from remote sources + index + ++ validate_dependency_confusion! unless disable_dependency_confusion_check? ++ + # Record the specs available in each gem's source, so that those + # specs will be available later when the resolver knows where to + # look for that gemspec (or its dependencies) +@@ -989,5 +991,112 @@ def equivalent_rubygems_remotes?(source) + + Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes) + end ++ ++ def validate_dependency_confusion! ++ # Continue if there is a scoped repository in the remote case. ++ return unless @remote && sources.non_global_rubygems_sources.size > 0 ++ ++ # Raise an error unless all the scope repositories implement the dependency API. ++ # When there is a non-dependency API scoped repository, we cannot get ++ # indirect dependencies used in a `Gemfile`. ++ unless sources.non_global_rubygems_sources.all?(&:dependency_api_available?) ++ non_api_sources = sources.non_global_rubygems_sources.reject(&:dependency_api_available?) ++ non_api_source_names_str = non_api_sources.map {|d| " * #{d}" }.join("\n") ++ ++ msg = String.new ++ msg << "Your Gemfile contains scoped sources that don't implement a dependency API, namely:\n\n" ++ msg << non_api_source_names_str ++ msg << "\n\nUsing the above gem servers may result in installing unexpected gems. " \ ++ "To resolve this warning, make sure you use gem servers that implement dependency APIs, " \ ++ "such as gemstash or geminabox gem servers." ++ raise_error_or_warn_dependency_confusion(msg) ++ return ++ end ++ ++ indirect_dep_names = indirect_dependency_names_in_non_global_rubygems_soruces ++ # Get all the gem names from the index made from the default source. ++ # default_source_dep_names = @index.sources.select(&:default_source_used?).map(&:spec_names).flatten ++ # Get all the gem names from each source. ++ all_spec_names_list = @index.sources.map(&:spec_names) ++ ++ # Only include the indirect dependency gems on the scoped sources that ++ # also exist on another source. The gems are included in more than 2 ++ # sources (the own source + another source). If the gems don't exist on ++ # the another source, the dependency confusion doesn't happen. ++ indirect_dep_names.select! do |name| ++ source_num = all_spec_names_list.select {|all_names| all_names.include?(name) } ++ source_num.size >= 2 ++ end ++ ++ # Raise an error if there is an indirect dependency. ++ if indirect_dep_names.size > 0 ++ dep_names_str = indirect_dep_names.join(", ") ++ source_names_str = sources.non_global_rubygems_sources.map {|d| " * #{d}" }.join("\n") ++ ++ msg = String.new ++ msg << "Your Gemfile contains implicit dependency gems #{dep_names_str} on the scoped sources, namely:\n\n" ++ msg << source_names_str ++ msg << "\n\nUsing implicit dependency gems on the above sources may result in installing unexpected gems. " ++ msg << "To suppress this message, make sure you set the gems explicitly in the Gemfile." ++ raise_error_or_warn_dependency_confusion(msg) ++ return ++ end ++ end ++ ++ def raise_error_or_warn_dependency_confusion(msg) ++ if warn_on_dependnecy_confusion? ++ Bundler.ui.warn msg ++ else ++ msg = "#{msg} Or set the environment variable BUNDLE_WARN_ON_DEPENDENCY_CONFUSION." ++ raise SecurityError, msg ++ end ++ end ++ ++ def indirect_dependency_names_in_non_global_rubygems_soruces ++ # Indirect dependency gem names ++ indirect_dep_names = [] ++ # Direct dependency gem names ++ direct_dep_names = @dependencies.map(&:name) ++ ++ sources.non_global_rubygems_sources.each do |s| ++ # If the non dependency API source is used, the `dependency_names` ++ # returns gems not only used in the `Gemfile`, but also returns ones ++ # existing in the scoped source too. This method shouldn't be used with ++ # the non dependency API sources. ++ s.specs.dependency_names.each do |dep_name| ++ # Exclude direct dependency gems. ++ next if direct_dep_names.include?(dep_name) ++ ++ s.specs.local_search(dep_name).each do |spec| ++ # Debug gems with unexpected `spec.class`. ++ Bundler.ui.debug "Found dependency gem #{dep_name} (#{spec.class}) in scoped sources." ++ # StubSpecification extending RemoteSpecification: the gems by ++ # `gem list`. Exclude the gems. ++ # EndpointSpecification: gems returned by dependency API such as ++ # geminabox ++ # RemoteSpecification: gems returned by non dependency API such as ++ # gem server. This method cannot be executed with the non ++ # dependency API sources. ++ indirect_dep_names << dep_name if spec.class == EndpointSpecification ++ end ++ end ++ end ++ ++ indirect_dep_names.sort.uniq ++ end ++ ++ # Print a warning instead of raising an error when this option is enabled. ++ # Don't use Bundler.settings to minimize the difference to backport easily ++ # and avoid additional tests. ++ def warn_on_dependnecy_confusion? ++ @warn_on_dependnecy_confusion ||= ENV["BUNDLE_WARN_ON_DEPENDENCY_CONFUSION"] ++ end ++ ++ # Disable the dependency confusion check when this option is enabled. ++ # The option can be used as a workaround if the check logic is problematic ++ # in a case such as a performance issue. ++ def disable_dependency_confusion_check? ++ @disable_dependnecy_confusion_check ||= ENV["BUNDLE_DISABLE_DEPENDENCY_CONFUSION_CHECK"] ++ end + end + end +diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb +index 485b388a32..48a2ab736b 100644 +--- a/lib/bundler/source/rubygems.rb ++++ b/lib/bundler/source/rubygems.rb +@@ -289,6 +289,10 @@ def dependency_names_to_double_check + names + end + ++ def dependency_api_available? ++ api_fetchers.any? ++ end ++ + protected + + def credless_remotes +diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb +index ac2adacb3d..37869878ce 100644 +--- a/lib/bundler/source_list.rb ++++ b/lib/bundler/source_list.rb +@@ -64,6 +64,10 @@ def rubygems_sources + @rubygems_sources + [default_source] + end + ++ def non_global_rubygems_sources ++ @rubygems_sources ++ end ++ + def rubygems_remotes + rubygems_sources.map(&:remotes).flatten.uniq + end +diff --git a/spec/bundler/bundler/definition_dep_confusion_spec.rb b/spec/bundler/bundler/definition_dep_confusion_spec.rb +new file mode 100644 +index 0000000000..9fee464960 +--- /dev/null ++++ b/spec/bundler/bundler/definition_dep_confusion_spec.rb +@@ -0,0 +1,257 @@ ++# frozen_string_literal: true ++ ++require "bundler/definition" ++ ++RSpec.describe Bundler::Definition do ++ before do ++ allow(Bundler::SharedHelpers).to receive(:find_gemfile) { Pathname.new("Gemfile") } ++ end ++ ++ let(:sources) { Bundler::SourceList.new } ++ subject { Bundler::Definition.new(nil, [], sources, []) } ++ ++ describe "#validate_dependency_confusion!" do ++ before do ++ subject.instance_variable_set(:@remote, remote) ++ end ++ ++ context "when it's not remote" do ++ let(:remote) { false } ++ ++ it "should neither raise an error nor warn" do ++ expect(subject).not_to receive(:raise_error_or_warn_dependency_confusion) ++ subject.send(:validate_dependency_confusion!) ++ end ++ end ++ ++ context "when it's remote" do ++ before do ++ allow(sources).to receive(:non_global_rubygems_sources).and_return(non_global_rubygems_sources) ++ end ++ ++ let(:remote) { true } ++ ++ context "when the number of non-global source is zero" do ++ let(:non_global_rubygems_sources) { [] } ++ ++ it "should neither raise an error nor warn" do ++ expect(subject).not_to receive(:raise_error_or_warn_dependency_confusion) ++ subject.send(:validate_dependency_confusion!) ++ end ++ end ++ ++ context "when there are any non dependency API non global sources" do ++ let(:non_global_rubygems_sources) do ++ [ ++ double("non-global-source-0", :dependency_api_available? => true, :to_s => "a"), ++ double("non-global-source-1", :dependency_api_available? => false, :to_s => "b"), ++ double("non-global-source-2", :dependency_api_available? => false, :to_s => "c"), ++ ] ++ end ++ ++ it "should raise an error or warn" do ++ expect(subject).to receive(:raise_error_or_warn_dependency_confusion).with(<<-M.strip) ++Your Gemfile contains scoped sources that don't implement a dependency API, namely: ++ ++ * b ++ * c ++ ++Using the above gem servers may result in installing unexpected gems. To resolve this warning, make sure you use gem servers that implement dependency APIs, such as gemstash or geminabox gem servers. ++ M ++ subject.send(:validate_dependency_confusion!) ++ end ++ end ++ ++ context "when all the non global sources implement dependency API" do ++ before do ++ allow(subject).to receive(:indirect_dependency_names_in_non_global_rubygems_soruces).and_return(indirect_dependency_names) ++ subject.instance_variable_set(:@index, index) ++ end ++ ++ let(:non_global_rubygems_sources) do ++ [ ++ double("non-global-source-0", :dependency_api_available? => true, :to_s => "a"), ++ double("non-global-source-1", :dependency_api_available? => true, :to_s => "b"), ++ ] ++ end ++ ++ let(:index) { double("index", :sources => index_sources) } ++ let(:index_sources) do ++ [ ++ double("index-source-1", :spec_names => ["a1", "a2"]), ++ double("index-source-2", :spec_names => ["a2", "b1", "b2"]), ++ double("index-source-3", :spec_names => ["b2"]) ++ ] ++ end ++ ++ context "when there is not an indirect dependency in the non global sources" do ++ let(:indirect_dependency_names) {[]} ++ ++ it "should neither raise an error nor warn" do ++ expect(subject).not_to receive(:raise_error_or_warn_dependency_confusion) ++ subject.send(:validate_dependency_confusion!) ++ end ++ end ++ ++ context "when there is an indirect dependency in the non global sources" do ++ ++ context "when the indirect dependency doesn't exist in another source" do ++ let(:indirect_dependency_names) {["a1", "b1"]} ++ ++ it "should neither raise an error nor warn" do ++ expect(subject).not_to receive(:raise_error_or_warn_dependency_confusion) ++ subject.send(:validate_dependency_confusion!) ++ end ++ end ++ ++ context "when the indirect dependency also exists in anotehr source" do ++ let(:indirect_dependency_names) {["a1", "a2", "b2"]} ++ ++ it "should raise an error or warn" do ++ expect(subject).to receive(:raise_error_or_warn_dependency_confusion).with(<<-M.strip) ++Your Gemfile contains implicit dependency gems a2, b2 on the scoped sources, namely: ++ ++ * a ++ * b ++ ++Using implicit dependency gems on the above sources may result in installing unexpected gems. To suppress this message, make sure you set the gems explicitly in the Gemfile. ++ M ++ subject.send(:validate_dependency_confusion!) ++ end ++ end ++ end ++ end ++ end ++ end ++ ++ describe "#indirect_dependency_names_in_non_global_rubygems_soruces" do ++ before do ++ subject.instance_variable_set(:@dependencies, dependencies) ++ allow(sources).to receive(:non_global_rubygems_sources).and_return(non_global_rubygems_sources) ++ end ++ ++ # Direct dependencies ++ let(:dependencies) do ++ [ ++ double("dependency-0", :name => "g0"), ++ double("dependency-1", :name => "g3") ++ ] ++ end ++ let(:non_global_rubygems_sources) do ++ [ ++ double("non-global-source-0", :specs => index_0, :to_s => "s0"), ++ double("non-global-source-1", :specs => index_1, :to_s => "s1"), ++ ] ++ end ++ let(:index_0) do ++ # All the dependencies in the source-0. ++ index = double("index-0", :dependency_names => ["g0", "g1", "g2", "g5"]) ++ allow(index).to receive(:local_search) do |query| ++ return_map = { ++ "g1" => [double("spec", :class => Bundler::StubSpecification, :to_s => "g1")], ++ "g2" => [double("spec", :class => Bundler::EndpointSpecification, :to_s => "g2")], ++ "g5" => [double("spec", :class => Bundler::EndpointSpecification, :to_s => "g5")] ++ } ++ return_map[query] ++ end ++ index ++ end ++ let(:index_1) do ++ # All the dependencies in the source-1. ++ index = double("index-1", :dependency_names => ["g3", "g4", "g5"]) ++ allow(index).to receive(:local_search) do |query| ++ return_map = { ++ "g4" => [double("spec", :class => Bundler::EndpointSpecification, :to_s => "g4")], ++ "g5" => [double("spec", :class => Bundler::EndpointSpecification, :to_s => "g5")] ++ } ++ return_map[query] ++ end ++ index ++ end ++ ++ it "should return only indirect dependencies of endpoint specification" do ++ expect(subject.send(:indirect_dependency_names_in_non_global_rubygems_soruces)).to eq(["g2", "g4", "g5"]) ++ end ++ end ++ ++ describe "#raise_error_or_warn_dependency_confusion" do ++ before do ++ allow(subject).to receive(:warn_on_dependnecy_confusion?).and_return(warn_on_dependnecy_confusion) ++ end ++ ++ context "when #warn_on_dependnecy_confusion? returns false" do ++ let(:warn_on_dependnecy_confusion) { false } ++ ++ it "should raise an error" do ++ expect(Bundler.ui).not_to receive(:warn) ++ expect do ++ subject.send(:raise_error_or_warn_dependency_confusion, "This is a message.") ++ end.to raise_error(Bundler::SecurityError, "This is a message. " \ ++ "Or set the environment variable BUNDLE_WARN_ON_DEPENDENCY_CONFUSION.") ++ end ++ end ++ ++ context "when #warn_on_dependnecy_confusion? returns true" do ++ let(:warn_on_dependnecy_confusion) { true } ++ ++ it "should warn" do ++ expect(Bundler.ui).to receive(:warn).with(<<-W.strip) ++This is a message. ++W ++ subject.send(:raise_error_or_warn_dependency_confusion, "This is a message.") ++ end ++ end ++ end ++ ++ describe "#warn_on_dependnecy_confusion?" do ++ context "when BUNDLE_WARN_ON_DEPENDENCY_CONFUSION is set" do ++ it "should return true" do ++ with_env({"BUNDLE_WARN_ON_DEPENDENCY_CONFUSION" => "1"}) do ++ expect(subject.send(:warn_on_dependnecy_confusion?)).to be_truthy ++ end ++ end ++ end ++ ++ context "when BUNDLE_WARN_ON_DEPENDENCY_CONFUSION is not set" do ++ it "should return false" do ++ with_env({"BUNDLE_WARN_ON_DEPENDENCY_CONFUSION" => nil}) do ++ expect(subject.send(:warn_on_dependnecy_confusion?)).to be_falsy ++ end ++ end ++ end ++ end ++ ++ describe "#disable_dependency_confusion_check?" do ++ context "when BUNDLE_DISABLE_DEPENDENCY_CONFUSION_CHECK is set" do ++ it "should return true" do ++ with_env({"BUNDLE_DISABLE_DEPENDENCY_CONFUSION_CHECK" => "1"}) do ++ expect(subject.send(:disable_dependency_confusion_check?)).to be_truthy ++ end ++ end ++ end ++ ++ context "when BUNDLE_DISABLE_DEPENDENCY_CONFUSION_CHECK is not set" do ++ it "should return false" do ++ with_env({"BUNDLE_DISABLE_DEPENDENCY_CONFUSION_CHECK" => nil}) do ++ expect(subject.send(:disable_dependency_confusion_check?)).to be_falsy ++ end ++ end ++ end ++ end ++ ++ def with_env(env={}) ++ begin ++ tmp_env = {} ++ env.each do |key, value| ++ tmp_env[key] = ENV.delete key ++ ENV[key] = value ++ end ++ ++ yield ++ ensure ++ tmp_env.each do |key, value| ++ ENV[key] = value ++ end ++ end ++ end ++end +-- +2.31.1 + diff --git a/ruby-exercise.stp b/ruby-exercise.stp new file mode 100644 index 0000000..df9df41 --- /dev/null +++ b/ruby-exercise.stp @@ -0,0 +1,39 @@ +/* Example tapset file. + * + * You can execute the tapset using following command (please adjust the path + * prior running the command, if needed): + * + * stap /usr/share/doc/ruby-2.0.0.0/ruby-exercise.stp -c "ruby -e \"puts 'test'\"" + */ + +probe ruby.cmethod.entry { + printf("%d -> %s::%s %s:%d\n", tid(), classname, methodname, file, line); +} + +probe ruby.cmethod.return { + printf("%d <- %s::%s %s:%d\n", tid(), classname, methodname, file, line); +} + +probe ruby.method.entry { + printf("%d -> %s::%s %s:%d\n", tid(), classname, methodname, file, line); +} + +probe ruby.method.return { + printf("%d <- %s::%s %s:%d\n", tid(), classname, methodname, file, line); +} + +probe ruby.gc.mark.begin { printf("%d gc.mark.begin\n", tid()); } + +probe ruby.gc.mark.end { printf("%d gc.mark.end\n", tid()); } + +probe ruby.gc.sweep.begin { printf("%d gc.sweep.begin\n", tid()); } + +probe ruby.gc.sweep.end { printf("%d gc.sweep.end\n", tid()); } + +probe ruby.object.create{ + printf("%d obj.create %s %s:%d\n", tid(), classname, file, line); +} + +probe ruby.raise { + printf("%d raise %s %s:%d\n", tid(), classname, file, line); +} diff --git a/ruby.rpmlintrc b/ruby.rpmlintrc new file mode 100644 index 0000000..bc72c06 --- /dev/null +++ b/ruby.rpmlintrc @@ -0,0 +1,56 @@ +# Keep matching patterns enough not to hide unintended errors and warnings. + +# There is no way to implement this with `%{SOURCE0}` without `%{_sourcedir}`. +# The order in the .spec file could be possibly different. +addFilter(r'ruby\.(spec|src):20: E: use-of-RPM_SOURCE_DIR$') + +# The used version is not obvious. +addFilter(r'ruby\.(spec|src):\d+: W: unversioned-explicit-provides bundled\(ccan-build_assert\)$') +addFilter(r'ruby\.(spec|src):\d+: W: unversioned-explicit-provides bundled\(ccan-check_type\)$') +addFilter(r'ruby\.(spec|src):\d+: W: unversioned-explicit-provides bundled\(ccan-container_of\)$') +addFilter(r'ruby\.(spec|src):\d+: W: unversioned-explicit-provides bundled\(ccan-list\)$') + +# The template files do not have to have executable bits. +addFilter(r'^rubygem-bundler\.noarch: E: non-executable-script /usr/share/gems/gems/bundler-[\d\.]+/lib/bundler/templates/[\w/\.]+ 644 /usr/bin/env ') + +# The bundled gem files permissions are overridden as 644 by `make install`. +# https://bugs.ruby-lang.org/issues/17840 +# power_assert +# https://github.com/ruby/power_assert/issues/35 +addFilter(r'^rubygem-power_assert\.noarch: E: non-executable-script /usr/share/gems/gems/power_assert-[\d\.]+/bin/console 644 ') +addFilter(r'^rubygem-power_assert\.noarch: E: non-executable-script /usr/share/gems/gems/power_assert-[\d\.]+/bin/setup 644 ') +# rake +# https://github.com/ruby/rake/issues/385 +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/bundle 644 ') +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/console 644 ') +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/rake 644 ') +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/rdoc 644 ') +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/rubocop 644 ') +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/setup 644 ') +# rbs +# https://github.com/ruby/rbs/issues/673 +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/annotate-with-rdoc 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/console 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/query-rdoc 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/rbs-prof 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/setup 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/sort 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/steep 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/test_runner.rb 644 ') +# test-unit +addFilter(r'^rubygem-test-unit\.noarch: E: non-executable-script /usr/share/gems/gems/test-unit-[\d\.]+/test/run-test.rb 644 ') + +# The function `chroot` without using `chdir` is detected by rpmlint with the +# following message. However it looks a false positive as the `chroot` in the +# `dir.c` is just used as a Ruby binding `Dir.chroot` for the function. +# +# ruby-libs.x86_64: E: missing-call-to-chdir-with-chroot /usr/lib64/libruby.so.3.0.1 +# This executable appears to call chroot without using chdir to change the +# current directory. This is likely an error and permits an attacker to break +# out of the chroot by using fchdir. While that's not always a security issue, +# this has to be checked. +addFilter(r'^ruby-libs\.\w+: E: missing-call-to-chdir-with-chroot /usr/lib(64)?/libruby.so.[\d/.]+$') + +# Nothing referred and no dependency information should be no problem. +# https://bugs.ruby-lang.org/issues/16558#note-2 +addFilter(r'^ruby-libs\.\w+: E: shared-lib-without-dependency-information /usr/lib(64)?/ruby/enc/gb2312.so$') diff --git a/ruby.spec b/ruby.spec new file mode 100644 index 0000000..2f405d7 --- /dev/null +++ b/ruby.spec @@ -0,0 +1,2679 @@ +%global major_version 2 +%global minor_version 6 +%global teeny_version 10 +%global major_minor_version %{major_version}.%{minor_version} + +%global ruby_version %{major_minor_version}.%{teeny_version} +%global ruby_release %{ruby_version} + +# Specify the named version. It has precedense to revision. +#%%global milestone rc2 + +# Keep the revision enabled for pre-releases from SVN. +#%%global revision 66252 + +%global ruby_archive %{name}-%{ruby_version} + +# If revision and milestone are removed/commented out, the official release build is expected. +%if 0%{?milestone:1}%{?revision:1} != 0 +%global development_release %{?milestone}%{?!milestone:%{?revision:r%{revision}}} +%global ruby_archive %{ruby_archive}-%{?milestone}%{?!milestone:%{?revision:r%{revision}}} +%endif + + +%global release 109 +%{!?release_string:%global release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} + +# The RubyGems library has to stay out of Ruby directory tree, since the +# RubyGems should be share by all Ruby implementations. +%global rubygems_dir %{_datadir}/rubygems + +# Bundled libraries versions +%global rubygems_version 3.0.3.1 +%global rubygems_molinillo_version 0.5.7 + +%global bundler_version 1.17.2 +%global bundler_fileutils_version 1.1.0 +%global bundler_molinillo_version 0.6.6 +%global bundler_net_http_persistent_version 2.9.4 +%global bundler_thor_version 0.20.0 + +%global bigdecimal_version 1.4.1 +%global did_you_mean_version 1.3.0 +%global io_console_version 0.4.7 +%global irb_version 1.0.0 +%global json_version 2.1.0 +%global minitest_version 5.11.3 +%global net_telnet_version 0.2.0 +%global openssl_version 2.1.2 +%global power_assert_version 1.1.3 +%global psych_version 3.1.0 +%global rake_version 12.3.3 +%global rdoc_version 6.1.2.1 +%global test_unit_version 3.2.9 +%global xmlrpc_version 0.3.0 + +# Might not be needed in the future, if we are lucky enough. +# https://bugzilla.redhat.com/show_bug.cgi?id=888262 +%global tapset_root %{_datadir}/systemtap +%global tapset_dir %{tapset_root}/tapset +%global tapset_libdir %(echo %{_libdir} | sed 's/64//')* + +%global _normalized_cpu %(echo %{_target_cpu} | sed 's/^ppc/powerpc/;s/i.86/i386/;s/sparcv./sparc/') + +%if 0%{?fedora} >= 19 +%bcond_without rubypick +%endif + +%bcond_without cmake +%bcond_without git +%bcond_without gmp +%bcond_without hostname +%bcond_without systemtap +# Enable the tests requiring internet when building on local. +%bcond_with bundler_tests + +%if 0%{?fedora} +%bcond_without hardening_test +%endif + +Summary: An interpreter of object-oriented scripting language +Name: ruby +Version: %{ruby_version} +Release: %{release_string} +# Public Domain for example for: include/ruby/st.h, strftime.c, missing/*, ... +# MIT and CCO: ccan/* +# zlib: ext/digest/md5/md5.*, ext/nkf/nkf-utf8/nkf.c +# UCD: some of enc/trans/**/*.src +License: (Ruby or BSD) and Public Domain and MIT and CC0 and zlib and UCD +URL: http://ruby-lang.org/ +Source0: https://cache.ruby-lang.org/pub/%{name}/%{major_minor_version}/%{ruby_archive}.tar.xz +Source1: operating_system.rb +# TODO: Try to push SystemTap support upstream. +Source2: libruby.stp +Source3: ruby-exercise.stp +Source4: macros.ruby +Source5: macros.rubygems +Source6: abrt_prelude.rb +# RPM dependency generators. +Source8: rubygems.attr +Source9: rubygems.req +Source10: rubygems.prov +Source11: rubygems.con +# ABRT hoook test case. +Source13: test_abrt.rb +# SystemTap tests. +Source14: test_systemtap.rb + +# The load directive is supported since RPM 4.12, i.e. F21+. The build process +# fails on older Fedoras. +%{load:%{SOURCE4}} +%{load:%{SOURCE5}} + +# Fix ruby_version abuse. +# https://bugs.ruby-lang.org/issues/11002 +Patch0: ruby-2.3.0-ruby_version.patch +# http://bugs.ruby-lang.org/issues/7807 +Patch1: ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch +# Allows to override libruby.so placement. Hopefully we will be able to return +# to plain --with-rubyarchprefix. +# http://bugs.ruby-lang.org/issues/8973 +Patch2: ruby-2.1.0-Enable-configuration-of-archlibdir.patch +# Force multiarch directories for i.86 to be always named i386. This solves +# some differencies in build between Fedora and RHEL. +Patch3: ruby-2.1.0-always-use-i386.patch +# Allows to install RubyGems into custom directory, outside of Ruby's tree. +# http://bugs.ruby-lang.org/issues/5617 +Patch4: ruby-2.1.0-custom-rubygems-location.patch +# Make mkmf verbose by default +Patch5: ruby-1.9.3-mkmf-verbose.patch +# Adds support for '--with-prelude' configuration option. This allows to built +# in support for ABRT. +# http://bugs.ruby-lang.org/issues/8566 +Patch6: ruby-2.1.0-Allow-to-specify-additional-preludes-by-configuratio.patch +# Use miniruby to regenerate prelude.c. +# https://bugs.ruby-lang.org/issues/15306 +Patch7: ruby-2.2.3-Generate-preludes-using-miniruby.patch +# Fix a fiddle import test on an optimized glibc on Power 9. +# https://bugs.ruby-lang.org/issues/12666#note-13 +Patch9: ruby-3.0.3-fiddle-1.0.8-Rely-on-hard-coded-lib-name-to-detect-glibc.patch +# `gem build ../foo.gemspec` changes directory, which does not play well with +# gems unpacked by setup macro. +# https://github.com/rubygems/rubygems/issues/2587 +Patch11: rubygems-3.0.3-Restore-gem-build-behavior-and-introdcue-the-C-flag-to-gem-build.patch +# This allows to loosen the RDoc dependency again. +# https://github.com/rubygems/rubygems/pull/2604 +Patch12: rubygems-3.0.3-Avoid-rdoc-hook-when-its-failed-to-load-rdoc-library.patch + +# Add support for .include directive used by OpenSSL config files. +# https://github.com/ruby/openssl/pull/216 +Patch22: ruby-2.6.0-config-support-include-directive.patch + +# IO.select on all platforms to wait for input with recvfrom_nonblock +# and accept_nonblock +# https://bugzilla.redhat.com/show_bug.cgi?id=1719743 +# https://github.com/ruby/ruby/commit/920b924e5652884064a9529ffbd80d458a46fbc6 +# https://github.com/ruby/ruby/commit/c1f0daeb6ac5c5414c9a4a58bb778a118006ae1f +Patch24: ruby-2.7.0-preview1-IO.select-on-all-platforms-to-wait-for-input-with-recvfr.patch +# Use ffi_closure_alloc to avoid segmentation fault by libffi on aarch64. +# https://bugzilla.redhat.com/show_bug.cgi?id=1727832 +# https://bugzilla.redhat.com/show_bug.cgi?id=1721569 +# https://github.com/ruby/fiddle/pull/20 +Patch25: ruby-2.6.3-fiddle-1.0.0-ffi-closure-alloc-default.patch +# Resolv::DNS: timeouts if multiple IPv6 name servers are given and address +# contains leading zero +# https://bugzilla.redhat.com/show_bug.cgi?id=1944227 +Patch26: ruby-3.0.0-Convert-ip-addresses-to-canonical-form.patch +# rubygem-bundler: Insecure permissions on directory in /tmp/ allows for execution of malicious code +# https://bugzilla.redhat.com/show_bug.cgi?id=1651826 +# https://github.com/rubygems/bundler/pull/7416 +Patch27: rubygem-bundler-2.1.0-dont-use-insecure-temporary-directory-as-home-directory.patch +# Update the location of bundler gemspec to fix `make test-bundler`. +# https://github.com/ruby/ruby/commit/8cca079d3be8d07c261baea72529628469938245 +Patch28: ruby-2.7.0-update-location-of-bundler-gemspec.patch +# Use ENV["BUNDLE_GEM"] instead of gem command to fix `make test-bundler`. +# https://github.com/rubygems/rubygems/commit/a30484bc3103d0f7eb048d2536436a0424c1d695 +# https://github.com/ruby/ruby/commit/68ddd4d300e9a88737c4f37af74e1a0312949b2f +Patch29: ruby-2.7.0-bundler-use-bundle-gem-instead-of-gem-command.patch +# Raise an error or print a warning in dependency confusion cases. +# https://github.com/rubygems/rubygems/pull/5029 +Patch30: ruby-bundler-raise-error-in-dependency-confusion.patch + +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Suggests: rubypick +Recommends: ruby(rubygems) >= %{rubygems_version} +Recommends: rubygem(bigdecimal) >= %{bigdecimal_version} +Recommends: rubygem(did_you_mean) >= %{did_you_mean_version} +Recommends: rubygem(openssl) >= %{openssl_version} + +BuildRequires: autoconf +BuildRequires: gdbm-devel +%{?with_gmp:BuildRequires: gmp-devel} +BuildRequires: libffi-devel +BuildRequires: openssl-devel +BuildRequires: libyaml-devel +BuildRequires: readline-devel +# Needed to pass test_set_program_name(TestRubyOptions) +BuildRequires: procps +%{?with_systemtap:BuildRequires: %{_bindir}/dtrace} +# RubyGems test suite optional dependencies. +%{?with_git:BuildRequires: git} +%{?with_cmake:BuildRequires: %{_bindir}/cmake} +# Required to test hardening. +%{?with_hardening_test:BuildRequires: %{_bindir}/checksec} +%{?with_hostname:BuildRequires: %{_bindir}/hostname} +BuildRequires: multilib-rpm-config +BuildRequires: gcc +BuildRequires: zlib-devel + +# This package provides %%{_bindir}/ruby-mri therefore it is marked by this +# virtual provide. It can be installed as dependency of rubypick. +Provides: ruby(runtime_executable) = %{ruby_release} + +%description +Ruby is the interpreted scripting language for quick and easy +object-oriented programming. It has many features to process text +files and to do system management tasks (as in Perl). It is simple, +straight-forward, and extensible. + + +%package devel +Summary: A Ruby development environment +Requires: %{name}%{?_isa} = %{version}-%{release} +# This would not be needed if ~50 packages depending on -devel used +# --disable-gems +Requires: rubygems + +%description devel +Header files and libraries for building an extension library for the +Ruby or an application embedding Ruby. + +%package libs +Summary: Libraries necessary to run Ruby +License: Ruby or BSD +Provides: ruby(release) = %{ruby_release} + +# Virtual provides for CCAN copylibs. +# https://fedorahosted.org/fpc/ticket/364 +Provides: bundled(ccan-build_assert) +Provides: bundled(ccan-check_type) +Provides: bundled(ccan-container_of) +Provides: bundled(ccan-list) + +# Tcl/Tk support was removed from stdlib in Ruby 2.4, i.e. F27 timeframe +# so lets obsolete it. This is not the best place, but we don't have +# better, unless https://fedorahosted.org/fpc/ticket/645 provides some +# generic solution. +Obsoletes: ruby-tcltk < 2.4.0 + + +%description libs +This package includes the libruby, necessary to run Ruby. + + +# TODO: Rename or not rename to ruby-rubygems? +%package -n rubygems +Summary: The Ruby standard for packaging ruby libraries +Version: %{rubygems_version} +License: Ruby or MIT +Requires: ruby(release) +Recommends: rubygem(rdoc) >= %{rdoc_version} +Recommends: rubygem(io-console) >= %{io_console_version} +Requires: rubygem(openssl) >= %{openssl_version} +Requires: rubygem(psych) >= %{psych_version} +Provides: gem = %{version}-%{release} +Provides: ruby(rubygems) = %{version}-%{release} +# https://github.com/rubygems/rubygems/pull/1189#issuecomment-121600910 +Provides: bundled(rubygem-molinillo) = %{rubygems_molinillo_version} +BuildArch: noarch + +%description -n rubygems +RubyGems is the Ruby standard for publishing and managing third party +libraries. + + +%package -n rubygems-devel +Summary: Macros and development tools for packaging RubyGems +Version: %{rubygems_version} +License: Ruby or MIT +Requires: ruby(rubygems) = %{version}-%{release} +# Needed for RDoc documentation format generation. +Requires: rubygem(json) >= %{json_version} +Requires: rubygem(rdoc) >= %{rdoc_version} +BuildArch: noarch + +%description -n rubygems-devel +Macros and development tools for packaging RubyGems. + + +%package -n rubygem-rake +Summary: Ruby based make-like utility +Version: %{rake_version} +License: MIT +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rake = %{version}-%{release} +Provides: rubygem(rake) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-rake +Rake is a Make-like program implemented in Ruby. Tasks and dependencies are +specified in standard Ruby syntax. + + +%package -n rubygem-irb +Summary: The Interactive Ruby +Version: %{irb_version} +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: irb = %{version}-%{release} +Provides: rubygem(irb) = %{version}-%{release} +# Obsoleted by Ruby 2.6 in F30 timeframe. +Provides: ruby(irb) = %{ruby_version}-%{release} +Provides: ruby-irb = %{ruby_version}-%{release} +Obsoletes: ruby-irb < %{ruby_version}-%{release} +BuildArch: noarch + +%description -n rubygem-irb +The irb is acronym for Interactive Ruby. It evaluates ruby expression +from the terminal. + + +%package -n rubygem-rdoc +Summary: A tool to generate HTML and command-line documentation for Ruby projects +Version: %{rdoc_version} +# SIL: lib/rdoc/generator/template/darkfish/css/fonts.css +License: GPLv2 and Ruby and MIT and OFL +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Requires: rubygem(irb) >= %{irb_version} +Requires: rubygem(io-console) >= %{io_console_version} +Requires: rubygem(json) >= %{json_version} +Provides: rdoc = %{version}-%{release} +Provides: ri = %{version}-%{release} +Provides: rubygem(rdoc) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-rdoc +RDoc produces HTML and command-line documentation for Ruby projects. RDoc +includes the 'rdoc' and 'ri' tools for generating and displaying online +documentation. + + +%package doc +Summary: Documentation for %{name} +Requires: %{_bindir}/ri +BuildArch: noarch + +%description doc +This package contains documentation for %{name}. + + +%package -n rubygem-bigdecimal +Summary: BigDecimal provides arbitrary-precision floating point decimal arithmetic +Version: %{bigdecimal_version} +License: Ruby or BSD +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(bigdecimal) = %{version}-%{release} + +%description -n rubygem-bigdecimal +Ruby provides built-in support for arbitrary precision integer arithmetic. +For example: + +42**13 -> 1265437718438866624512 + +BigDecimal provides similar support for very large or very accurate floating +point numbers. Decimal arithmetic is also useful for general calculation, +because it provides the correct answers people expect–whereas normal binary +floating point arithmetic often introduces subtle errors because of the +conversion between base 10 and base 2. + + +%package -n rubygem-did_you_mean +Summary: "Did you mean?" experience in Ruby +Version: %{did_you_mean_version} +License: MIT +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(did_you_mean) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-did_you_mean +"did you mean?" experience in Ruby: the error message will tell you the right +one when you misspelled something. + + +%package -n rubygem-io-console +Summary: IO/Console is a simple console utilizing library +Version: %{io_console_version} +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(io-console) = %{version}-%{release} + +%description -n rubygem-io-console +IO/Console provides very simple and portable access to console. It doesn't +provide higher layer features, such like curses and readline. + + +%package -n rubygem-json +Summary: This is a JSON implementation as a Ruby extension in C +Version: %{json_version} +# UCD: ext/json/generator/generator.c +License: (Ruby or GPLv2) and UCD +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(json) = %{version}-%{release} + +%description -n rubygem-json +This is a implementation of the JSON specification according to RFC 4627. +You can think of it as a low fat alternative to XML, if you want to store +data to disk or transmit it over a network rather than use a verbose +markup language. + + +%package -n rubygem-minitest +Summary: Minitest provides a complete suite of testing facilities +Version: %{minitest_version} +License: MIT +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(minitest) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-minitest +minitest/unit is a small and incredibly fast unit testing framework. + +minitest/spec is a functionally complete spec engine. + +minitest/benchmark is an awesome way to assert the performance of your +algorithms in a repeatable manner. + +minitest/mock by Steven Baker, is a beautifully tiny mock object +framework. + +minitest/pride shows pride in testing and adds coloring to your test +output. + + +%package -n rubygem-openssl +Summary: OpenSSL provides SSL, TLS and general purpose cryptography +Version: %{openssl_version} +License: Ruby or BSD +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(openssl) = %{version}-%{release} + +%description -n rubygem-openssl +OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the +OpenSSL library. + + +%package -n rubygem-power_assert +Summary: Power Assert for Ruby +Version: %{power_assert_version} +License: Ruby or BSD +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(power_assert) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-power_assert +Power Assert shows each value of variables and method calls in the expression. +It is useful for testing, providing which value wasn't correct when the +condition is not satisfied. + + +%package -n rubygem-psych +Summary: A libyaml wrapper for Ruby +Version: %{psych_version} +License: MIT +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(psych) = %{version}-%{release} + +%description -n rubygem-psych +Psych is a YAML parser and emitter. Psych leverages +libyaml[http://pyyaml.org/wiki/LibYAML] for its YAML parsing and emitting +capabilities. In addition to wrapping libyaml, Psych also knows how to +serialize and de-serialize most Ruby objects to and from the YAML format. + + +%package -n rubygem-net-telnet +Summary: Provides telnet client functionality +Version: %{net_telnet_version} +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(net-telnet) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-net-telnet +Provides telnet client functionality. + +This class also has, through delegation, all the methods of a socket object +(by default, a TCPSocket, but can be set by the Proxy option to new()). This +provides methods such as close() to end the session and sysread() to read data +directly from the host, instead of via the waitfor() mechanism. Note that if +you do use sysread() directly when in telnet mode, you should probably pass +the output through preprocess() to extract telnet command sequences. + + +%package -n rubygem-test-unit +Summary: An xUnit family unit testing framework for Ruby +Version: %{test_unit_version} +# lib/test/unit/diff.rb is a double license of the Ruby license and PSF license. +# lib/test-unit.rb is a dual license of the Ruby license and LGPLv2.1 or later. +License: (Ruby or BSD) and (Ruby or BSD or Python) and (Ruby or BSD or LGPLv2+) +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Requires: rubygem(power_assert) +Provides: rubygem(test-unit) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-test-unit +Test::Unit (test-unit) is unit testing framework for Ruby, based on xUnit +principles. These were originally designed by Kent Beck, creator of extreme +programming software development methodology, for Smalltalk's SUnit. It allows +writing tests, checking results and automated testing in Ruby. + + +%package -n rubygem-xmlrpc +Summary: XMLRPC is a lightweight protocol that enables remote procedure calls over HTTP +Version: %{xmlrpc_version} +License: Ruby or BSD +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(xmlrpc) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-xmlrpc +XMLRPC is a lightweight protocol that enables remote procedure calls over +HTTP. + + +%package -n rubygem-bundler +Summary: Library and utilities to manage a Ruby application's gem dependencies +Version: %{bundler_version} +License: MIT +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Requires: rubygem(io-console) +Provides: rubygem(bundler) = %{version}-%{release} +# https://github.com/bundler/bundler/issues/3647 +Provides: bundled(rubygem-fileutils) = %{bundler_fileutils_version} +Provides: bundled(rubygem-molinillo) = %{bundler_molinillo_version} +Provides: bundled(rubygem-net-http-persisntent) = %{bundler_net_http_persistent_version} +Provides: bundled(rubygem-thor) = %{bundler_thor_version} +BuildArch: noarch + +%description -n rubygem-bundler +Bundler manages an application's dependencies through its entire life, across +many machines, systematically and repeatably. + + +%prep +%setup -q -n %{ruby_archive} + +# Remove bundled libraries to be sure they are not used. +rm -rf ext/psych/yaml +rm -rf ext/fiddle/libffi* + +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch9 -p1 +%patch11 -p1 +%patch12 -p1 +%patch22 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch30 -p1 + +# Provide an example of usage of the tapset: +cp -a %{SOURCE3} . + +# Make abrt_prelude.rb available for compilation process. The prelude must be +# available together with Ruby's source due to +# https://github.com/ruby/ruby/blob/trunk/tool/compile_prelude.rb#L26 +cp -a %{SOURCE6} . + +%build +autoconf + +%configure \ + --with-rubylibprefix='%{ruby_libdir}' \ + --with-archlibdir='%{_libdir}' \ + --with-rubyarchprefix='%{ruby_libarchdir}' \ + --with-sitedir='%{ruby_sitelibdir}' \ + --with-sitearchdir='%{ruby_sitearchdir}' \ + --with-vendordir='%{ruby_vendorlibdir}' \ + --with-vendorarchdir='%{ruby_vendorarchdir}' \ + --with-rubyhdrdir='%{_includedir}' \ + --with-rubyarchhdrdir='%{_includedir}' \ + --with-sitearchhdrdir='$(sitehdrdir)/$(arch)' \ + --with-vendorarchhdrdir='$(vendorhdrdir)/$(arch)' \ + --with-rubygemsdir='%{rubygems_dir}' \ + --with-ruby-pc='%{name}.pc' \ + --with-compress-debug-sections=no \ + --disable-rpath \ + --enable-shared \ + --with-ruby-version='' \ + --enable-multiarch \ + --with-prelude=./abrt_prelude.rb \ + +# Q= makes the build output more verbose and allows to check Fedora +# compiler options. +make %{?_smp_mflags} COPY="cp -p" Q= + +%install +rm -rf %{buildroot} +make install DESTDIR=%{buildroot} + +# Rename ruby/config.h to ruby/config-.h to avoid file conflicts on +# multilib systems and install config.h wrapper +%multilib_fix_c_header --file %{_includedir}/%{name}/config.h +# TODO: The correct patch should be %%{_includedir}/%%{name}/rb_mjit_min_header-%{ruby_version}.h +# https://bugs.ruby-lang.org/issues/15425 +%multilib_fix_c_header --file %{_includedir}/rb_mjit_min_header-%{ruby_version}.h + +# Rename the ruby executable. It is replaced by RubyPick. +%{?with_rubypick:mv %{buildroot}%{_bindir}/%{name}{,-mri}} + +# Version is empty if --with-ruby-version is specified. +# http://bugs.ruby-lang.org/issues/7807 +sed -i 's/Version: \${ruby_version}/Version: %{ruby_version}/' %{buildroot}%{_libdir}/pkgconfig/%{name}.pc + +# Kill bundled certificates, as they should be part of ca-certificates. +# bundler +for cert in \ + rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem \ + rubygems.org/AddTrustExternalCARoot.pem \ + index.rubygems.org/GlobalSignRootCA.pem +do + rm %{buildroot}%{ruby_libdir}/bundler/ssl_certs/$cert + rm -r $(dirname %{buildroot}%{ruby_libdir}/bundler/ssl_certs/$cert) +done + +for cert in \ + rubygems.org/GlobalSignRootCA.pem +do + rm %{buildroot}%{rubygems_dir}/rubygems/ssl_certs/$cert + rm -r $(dirname %{buildroot}%{rubygems_dir}/rubygems/ssl_certs/$cert) +done +# Ensure there is not forgotten any certificate. +test ! "$(ls -A %{buildroot}%{rubygems_dir}/rubygems/ssl_certs/ 2>/dev/null)" +test "$(ls -A %{buildroot}%{ruby_libdir}/bundler/ssl_certs/ 2>/dev/null)" \ + = "certificate_manager.rb" + +# Move macros file into proper place and replace the %%{name} macro, since it +# would be wrongly evaluated during build of other packages. +mkdir -p %{buildroot}%{_rpmconfigdir}/macros.d +install -m 644 %{SOURCE4} %{buildroot}%{_rpmconfigdir}/macros.d/macros.ruby +sed -i "s/%%{name}/%{name}/" %{buildroot}%{_rpmconfigdir}/macros.d/macros.ruby +install -m 644 %{SOURCE5} %{buildroot}%{_rpmconfigdir}/macros.d/macros.rubygems +sed -i "s/%%{name}/%{name}/" %{buildroot}%{_rpmconfigdir}/macros.d/macros.rubygems + +# Install dependency generators. +mkdir -p %{buildroot}%{_rpmconfigdir}/fileattrs +install -m 644 %{SOURCE8} %{buildroot}%{_rpmconfigdir}/fileattrs +install -m 755 %{SOURCE9} %{buildroot}%{_rpmconfigdir} +install -m 755 %{SOURCE10} %{buildroot}%{_rpmconfigdir} +install -m 755 %{SOURCE11} %{buildroot}%{_rpmconfigdir} + +# Install custom operating_system.rb. +mkdir -p %{buildroot}%{rubygems_dir}/rubygems/defaults +cp %{SOURCE1} %{buildroot}%{rubygems_dir}/rubygems/defaults + +# Move gems root into common direcotry, out of Ruby directory structure. +mv %{buildroot}%{ruby_libdir}/gems %{buildroot}%{gem_dir} + +# Create folders for gem binary extensions. +# TODO: These folders should go into rubygem-filesystem but how to achieve it, +# since noarch package cannot provide arch dependent subpackages? +# http://rpm.org/ticket/78 +mkdir -p %{buildroot}%{_exec_prefix}/lib{,64}/gems/%{name} + +# Move bundled rubygems to %%gem_dir and %%gem_extdir_mri +# make symlinks for io-console and bigdecimal, which are considered to be part of stdlib by other Gems +mkdir -p %{buildroot}%{gem_dir}/gems/irb-%{irb_version}/lib +mv %{buildroot}%{ruby_libdir}/irb* %{buildroot}%{gem_dir}/gems/irb-%{irb_version}/lib +mv %{buildroot}%{gem_dir}/specifications/default/irb-%{irb_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/irb-%{irb_version}/lib/irb.rb %{buildroot}%{ruby_libdir}/irb.rb +# TODO: This should be possible to replaced by simple directory symlink +# after ~ F31 EOL (rhbz#1691039). +mkdir -p %{buildroot}%{ruby_libdir}/irb +pushd %{buildroot}%{gem_dir}/gems/irb-%{irb_version}/lib +find irb -type d -mindepth 1 -exec mkdir %{buildroot}%{ruby_libdir}/'{}' \; +find irb -type f -exec ln -s %{gem_dir}/gems/irb-%{irb_version}/lib/'{}' %{buildroot}%{ruby_libdir}/'{}' \; +popd + +mkdir -p %{buildroot}%{gem_dir}/gems/rdoc-%{rdoc_version}/lib +mv %{buildroot}%{ruby_libdir}/rdoc* %{buildroot}%{gem_dir}/gems/rdoc-%{rdoc_version}/lib +mv %{buildroot}%{gem_dir}/specifications/default/rdoc-%{rdoc_version}.gemspec %{buildroot}%{gem_dir}/specifications + +mkdir -p %{buildroot}%{gem_dir}/gems/bigdecimal-%{bigdecimal_version}/lib +mkdir -p %{buildroot}%{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version}/bigdecimal +mv %{buildroot}%{ruby_libdir}/bigdecimal %{buildroot}%{gem_dir}/gems/bigdecimal-%{bigdecimal_version}/lib +mv %{buildroot}%{ruby_libarchdir}/bigdecimal.so %{buildroot}%{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version} +mv %{buildroot}%{ruby_libarchdir}/bigdecimal/util.so %{buildroot}%{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version}/bigdecimal +mv %{buildroot}%{gem_dir}/specifications/default/bigdecimal-%{bigdecimal_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/bigdecimal-%{bigdecimal_version}/lib/bigdecimal %{buildroot}%{ruby_libdir}/bigdecimal +ln -s %{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version}/bigdecimal.so %{buildroot}%{ruby_libarchdir}/bigdecimal.so +ln -s %{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version}/bigdecimal/util.so %{buildroot}%{ruby_libarchdir}/bigdecimal/util.so + +# TODO: Put help files into proper location. +# https://bugs.ruby-lang.org/issues/15359 +mkdir -p %{buildroot}%{gem_dir}/gems/bundler-%{bundler_version}/lib +mv %{buildroot}%{ruby_libdir}/bundler.rb %{buildroot}%{gem_dir}/gems/bundler-%{bundler_version}/lib +mv %{buildroot}%{ruby_libdir}/bundler %{buildroot}%{gem_dir}/gems/bundler-%{bundler_version}/lib +mv %{buildroot}%{gem_dir}/specifications/default/bundler-%{bundler_version}.gemspec %{buildroot}%{gem_dir}/specifications + +mkdir -p %{buildroot}%{gem_dir}/gems/io-console-%{io_console_version}/lib +mkdir -p %{buildroot}%{_libdir}/gems/%{name}/io-console-%{io_console_version}/io +mv %{buildroot}%{ruby_libdir}/io %{buildroot}%{gem_dir}/gems/io-console-%{io_console_version}/lib +mv %{buildroot}%{ruby_libarchdir}/io/console.so %{buildroot}%{_libdir}/gems/%{name}/io-console-%{io_console_version}/io +mv %{buildroot}%{gem_dir}/specifications/default/io-console-%{io_console_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/io-console-%{io_console_version}/lib/io %{buildroot}%{ruby_libdir}/io +ln -s %{_libdir}/gems/%{name}/io-console-%{io_console_version}/io/console.so %{buildroot}%{ruby_libarchdir}/io/console.so + +mkdir -p %{buildroot}%{gem_dir}/gems/json-%{json_version}/lib +mkdir -p %{buildroot}%{_libdir}/gems/%{name}/json-%{json_version} +mv %{buildroot}%{ruby_libdir}/json* %{buildroot}%{gem_dir}/gems/json-%{json_version}/lib +mv %{buildroot}%{ruby_libarchdir}/json/ %{buildroot}%{_libdir}/gems/%{name}/json-%{json_version}/ +mv %{buildroot}%{gem_dir}/specifications/default/json-%{json_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/json-%{json_version}/lib/json.rb %{buildroot}%{ruby_libdir}/json.rb +ln -s %{gem_dir}/gems/json-%{json_version}/lib/json %{buildroot}%{ruby_libdir}/json +ln -s %{_libdir}/gems/%{name}/json-%{json_version}/json/ %{buildroot}%{ruby_libarchdir}/json + +mkdir -p %{buildroot}%{gem_dir}/gems/openssl-%{openssl_version}/lib +mkdir -p %{buildroot}%{_libdir}/gems/%{name}/openssl-%{openssl_version} +mv %{buildroot}%{ruby_libdir}/openssl* %{buildroot}%{gem_dir}/gems/openssl-%{openssl_version}/lib +mv %{buildroot}%{ruby_libarchdir}/openssl.so %{buildroot}%{_libdir}/gems/%{name}/openssl-%{openssl_version}/ +mv %{buildroot}%{gem_dir}/specifications/default/openssl-%{openssl_version}.gemspec %{buildroot}%{gem_dir}/specifications +# This used to be directory when OpenSSL was integral part of StdLib => Keep +# it as directory and link everything in it to prevent directory => symlink +# conversion RPM issues. +mkdir -p %{buildroot}%{ruby_libdir}/openssl +find %{buildroot}%{gem_dir}/gems/openssl-%{openssl_version}/lib/openssl -maxdepth 1 -type f -exec \ + sh -c 'ln -s %{gem_dir}/gems/openssl-%{openssl_version}/lib/openssl/`basename {}` %{buildroot}%{ruby_libdir}/openssl' \; +ln -s %{gem_dir}/gems/openssl-%{openssl_version}/lib/openssl.rb %{buildroot}%{ruby_libdir}/openssl.rb +ln -s %{_libdir}/gems/%{name}/openssl-%{openssl_version}/openssl.so %{buildroot}%{ruby_libarchdir}/openssl.so + +mkdir -p %{buildroot}%{gem_dir}/gems/psych-%{psych_version}/lib +mkdir -p %{buildroot}%{_libdir}/gems/%{name}/psych-%{psych_version} +mv %{buildroot}%{ruby_libdir}/psych* %{buildroot}%{gem_dir}/gems/psych-%{psych_version}/lib +mv %{buildroot}%{ruby_libarchdir}/psych.so %{buildroot}%{_libdir}/gems/%{name}/psych-%{psych_version}/ +mv %{buildroot}%{gem_dir}/specifications/default/psych-%{psych_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/psych-%{psych_version}/lib/psych %{buildroot}%{ruby_libdir}/psych +ln -s %{gem_dir}/gems/psych-%{psych_version}/lib/psych.rb %{buildroot}%{ruby_libdir}/psych.rb +ln -s %{_libdir}/gems/%{name}/psych-%{psych_version}/psych.so %{buildroot}%{ruby_libarchdir}/psych.so + +# Move the binary extensions into proper place (if no gem has binary extension, +# the extensions directory might be empty). +find %{buildroot}%{gem_dir}/extensions/*-%{_target_os}/%{ruby_version}/* -maxdepth 0 \ + -exec mv '{}' %{buildroot}%{_libdir}/gems/%{name}/ \; \ + || echo "No gem binary extensions to move." + +# Adjust the gemspec files so that the gems will load properly +sed -i '/^end$/ i\ + s.extensions = ["json/ext/parser.so", "json/ext/generator.so"]' %{buildroot}%{gem_dir}/specifications/json-%{json_version}.gemspec + +# Move man pages into proper location +mv %{buildroot}%{gem_dir}/gems/rake-%{rake_version}/doc/rake.1 %{buildroot}%{_mandir}/man1 + +%if %{with systemtap} +# Install a tapset and fix up the path to the library. +mkdir -p %{buildroot}%{tapset_dir} +sed -e "s|@LIBRARY_PATH@|%{tapset_libdir}/libruby.so.%{major_minor_version}|" \ + %{SOURCE2} > %{buildroot}%{tapset_dir}/libruby.so.%{major_minor_version}.stp +# Escape '*/' in comment. +sed -i -r "s|( \*.*\*)\/(.*)|\1\\\/\2|" %{buildroot}%{tapset_dir}/libruby.so.%{major_minor_version}.stp +%endif + +# Prepare -doc subpackage file lists. +find doc -maxdepth 1 -type f ! -name '.*' ! -name '*.ja*' > .ruby-doc.en +echo 'doc/images' >> .ruby-doc.en +echo 'doc/syntax' >> .ruby-doc.en + +find doc -maxdepth 1 -type f -name '*.ja*' > .ruby-doc.ja +echo 'doc/irb' >> .ruby-doc.ja +echo 'doc/pty' >> .ruby-doc.ja + +sed -i 's/^/%doc /' .ruby-doc.* +sed -i 's/^/%lang(ja) /' .ruby-doc.ja + +# https://github.com/yuki24/did_you_mean/issues/122 +rm -rf %{buildroot}%{gem_dir}/gems/did_you_mean-%{did_you_mean_version}/tmp/ + +# https://github.com/ruby/rake/issues/316 +rm -f %{buildroot}%{gem_dir}/gems/rake-%{rake_version}/.gitignore + +%check +%if 0%{?with_hardening_test} +# Check Ruby hardening. +checksec --file=libruby.so.%{ruby_version} | \ + grep "Full RELRO.*Canary found.*NX enabled.*DSO.*No RPATH.*No RUNPATH.*Yes.*\d*.*\d*.*libruby.so.%{ruby_version}" +%endif + +# Check RubyGems version. +[ "`make runruby TESTRUN_SCRIPT='bin/gem -v' | tail -1`" == '%{rubygems_version}' ] + +# Check Rubygems bundled dependencies versions. + +# Molinillo. +[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ + module Gem; module Resolver; end; end; \ + require 'rubygems/resolver/molinillo/lib/molinillo/gem_metadata'; \ + puts Gem::Resolver::Molinillo::VERSION\\\"\" | tail -1`" \ + == '%{rubygems_molinillo_version}' ] + +# Check Bundler bundled dependencies versions. + +# FileUtils. +# TODO: There is no version in bundled FileUtils yet. +#%%{global bundler_fileutils_version} + +# Molinillo. +[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ + module Bundler; end; \ + require 'bundler/vendor/molinillo/lib/molinillo/gem_metadata'; \ + puts Bundler::Molinillo::VERSION\\\"\" | tail -1`" \ + == '%{bundler_molinillo_version}' ] + +# Net::HTTP::Persistent. +[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ + module Bundler; module Persistent; module Net; module HTTP; \ + end; end; end; end; \ + require 'bundler/vendor/net-http-persistent/lib/net/http/persistent'; \ + puts Bundler::Persistent::Net::HTTP::Persistent::VERSION\\\"\" | tail -1`" \ + == '%{bundler_net_http_persistent_version}' ] + +# Thor. +[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ + module Bundler; end; \ + require 'bundler/vendor/thor/lib/thor/version'; \ + puts Bundler::Thor::VERSION\\\"\" | tail -1`" \ + == '%{bundler_thor_version}' ] + + +# test_debug(TestRubyOptions) fails due to LoadError reported in debug mode, +# when abrt.rb cannot be required (seems to be easier way then customizing +# the test suite). +touch abrt.rb + +# Check if abrt hook is required (RubyGems are disabled by default when using +# runruby, so re-enable them). +make runruby TESTRUN_SCRIPT="--enable-gems %{SOURCE13}" + +# Check if systemtap is supported. +%{?with_systemtap:make runruby TESTRUN_SCRIPT=%{SOURCE14}} + +DISABLE_TESTS="" +MSPECOPTS="" + +# Avoid `hostname' dependency. +%{!?with_hostname:MSPECOPTS="-P 'Socket.gethostname returns the host name'"} + +# SIGSEV handler does not provide correct output on AArch64. +# https://bugs.ruby-lang.org/issues/13758 +%ifarch aarch64 +DISABLE_TESTS="$DISABLE_TESTS -n !/test_segv_\(setproctitle\|test\|loaded_features\)/" +%endif + +# Disable failing TestResolvMDNS#test_mdns_each_address test, +# which fails on Koji. +# https://bugs.ruby-lang.org/issues/14175 +sed -i '/def test_mdns_each_address$/,/^ end$/ s/^/#/' test/resolv/test_mdns.rb +# Disable Timeouting test_queue_with_trap +# https://github.com/ruby/ruby/pull/3101/ +sed -i '/^ def test_queue_with_trap$/,/^ end$/ s/^/#/g' \ + test/ruby/test_thread_queue.rb +# Disable "File.utime allows Time instances in the far future to set +# mtime and atime". +# https://bugs.ruby-lang.org/issues/16410 +MSPECOPTS="$MSPECOPTS -P 'File.utime allows Time instances in the far future to set mtime and atime'" + +# For now, disable JIT tests in RHEL 8. +# https://bugzilla.redhat.com/show_bug.cgi?id=1721553 +mv test/ruby/test_jit.rb{,.disabled} +sed \ + -e '/^ def test_pause$/,/^ end$/ s/^/#/' \ + -e '/^ def test_pause_waits_until_compaction$/,/^ end$/ s/^/#/' \ + -i test/ruby/test_rubyvm_mjit.rb + +# RHEL8 is using stronger crypto policies then Fedora ATM and upstream does +# not support them yet. Disable the RHEL8 configuration for the moment. +# https://github.com/ruby/openssl/issues/215 +OPENSSL_SYSTEM_CIPHERS_OVERRIDE=xyz_nonexistent_file OPENSSL_CONF='' \ + make check TESTS="-v $DISABLE_TESTS" MSPECOPT="-fs $MSPECOPTS" + +%if %{with bundler_tests} +cat "%{PATCH28}" | patch -p1 +cat "%{PATCH29}" | patch -p1 +# Only run specific tests, as there are some failures in other tests. +make test-bundler V=1 RSPECOPTS="--format d" BUNDLER_SPECS=bundler/definition_dep_confusion_spec.rb +%endif + +%files +%license BSDL +%license COPYING +%lang(ja) %license COPYING.ja +%license GPL +%license LEGAL +%{_bindir}/erb +%{_bindir}/%{name}%{?with_rubypick:-mri} +%{_mandir}/man1/erb* +%{_mandir}/man1/ruby* + +%files devel +%license BSDL +%license COPYING +%lang(ja) %license COPYING.ja +%license GPL +%license LEGAL + +%{_rpmconfigdir}/macros.d/macros.ruby + +%{_includedir}/* +%{_libdir}/libruby.so +%{_libdir}/pkgconfig/%{name}.pc + +%files libs +%license COPYING +%lang(ja) %license COPYING.ja +%license GPL +%license LEGAL +%doc README.md +%doc NEWS +# Exclude /usr/local directory since it is supposed to be managed by +# local system administrator. +%exclude %{ruby_sitelibdir} +%exclude %{ruby_sitearchdir} +%dir %{ruby_vendorlibdir} +%dir %{ruby_vendorarchdir} + +# List all these files explicitly to prevent surprises +# Platform independent libraries. +%dir %{ruby_libdir} +%{ruby_libdir}/*.rb +%exclude %{ruby_libdir}/irb.rb +%exclude %{ruby_libdir}/json.rb +%exclude %{ruby_libdir}/openssl.rb +%exclude %{ruby_libdir}/psych.rb +%{ruby_libdir}/cgi +%{ruby_libdir}/csv +%{ruby_libdir}/digest +%{ruby_libdir}/drb +%{ruby_libdir}/e2mmap +%{ruby_libdir}/fiddle +%{ruby_libdir}/fileutils +%{ruby_libdir}/forwardable +%{ruby_libdir}/matrix +%{ruby_libdir}/net +%{ruby_libdir}/optparse +%{ruby_libdir}/racc +%{ruby_libdir}/rexml +%{ruby_libdir}/rinda +%{ruby_libdir}/ripper +%{ruby_libdir}/rss +%{ruby_libdir}/shell +%{ruby_libdir}/syslog +%{ruby_libdir}/thwait +%{ruby_libdir}/tracer +%{ruby_libdir}/unicode_normalize +%{ruby_libdir}/uri +%{ruby_libdir}/webrick +%{ruby_libdir}/yaml + +# Platform specific libraries. +%{_libdir}/libruby.so.* +%dir %{ruby_libarchdir} +%dir %{ruby_libarchdir}/cgi +%{ruby_libarchdir}/cgi/escape.so +%{ruby_libarchdir}/continuation.so +%{ruby_libarchdir}/coverage.so +%{ruby_libarchdir}/date_core.so +%{ruby_libarchdir}/dbm.so +%dir %{ruby_libarchdir}/digest +%{ruby_libarchdir}/digest.so +%{ruby_libarchdir}/digest/bubblebabble.so +%{ruby_libarchdir}/digest/md5.so +%{ruby_libarchdir}/digest/rmd160.so +%{ruby_libarchdir}/digest/sha1.so +%{ruby_libarchdir}/digest/sha2.so +%dir %{ruby_libarchdir}/enc +%{ruby_libarchdir}/enc/big5.so +%{ruby_libarchdir}/enc/cp949.so +%{ruby_libarchdir}/enc/emacs_mule.so +%{ruby_libarchdir}/enc/encdb.so +%{ruby_libarchdir}/enc/euc_jp.so +%{ruby_libarchdir}/enc/euc_kr.so +%{ruby_libarchdir}/enc/euc_tw.so +%{ruby_libarchdir}/enc/gb18030.so +%{ruby_libarchdir}/enc/gb2312.so +%{ruby_libarchdir}/enc/gbk.so +%{ruby_libarchdir}/enc/iso_8859_1.so +%{ruby_libarchdir}/enc/iso_8859_10.so +%{ruby_libarchdir}/enc/iso_8859_11.so +%{ruby_libarchdir}/enc/iso_8859_13.so +%{ruby_libarchdir}/enc/iso_8859_14.so +%{ruby_libarchdir}/enc/iso_8859_15.so +%{ruby_libarchdir}/enc/iso_8859_16.so +%{ruby_libarchdir}/enc/iso_8859_2.so +%{ruby_libarchdir}/enc/iso_8859_3.so +%{ruby_libarchdir}/enc/iso_8859_4.so +%{ruby_libarchdir}/enc/iso_8859_5.so +%{ruby_libarchdir}/enc/iso_8859_6.so +%{ruby_libarchdir}/enc/iso_8859_7.so +%{ruby_libarchdir}/enc/iso_8859_8.so +%{ruby_libarchdir}/enc/iso_8859_9.so +%{ruby_libarchdir}/enc/koi8_r.so +%{ruby_libarchdir}/enc/koi8_u.so +%{ruby_libarchdir}/enc/shift_jis.so +%dir %{ruby_libarchdir}/enc/trans +%{ruby_libarchdir}/enc/trans/big5.so +%{ruby_libarchdir}/enc/trans/chinese.so +%{ruby_libarchdir}/enc/trans/ebcdic.so +%{ruby_libarchdir}/enc/trans/emoji.so +%{ruby_libarchdir}/enc/trans/emoji_iso2022_kddi.so +%{ruby_libarchdir}/enc/trans/emoji_sjis_docomo.so +%{ruby_libarchdir}/enc/trans/emoji_sjis_kddi.so +%{ruby_libarchdir}/enc/trans/emoji_sjis_softbank.so +%{ruby_libarchdir}/enc/trans/escape.so +%{ruby_libarchdir}/enc/trans/gb18030.so +%{ruby_libarchdir}/enc/trans/gbk.so +%{ruby_libarchdir}/enc/trans/iso2022.so +%{ruby_libarchdir}/enc/trans/japanese.so +%{ruby_libarchdir}/enc/trans/japanese_euc.so +%{ruby_libarchdir}/enc/trans/japanese_sjis.so +%{ruby_libarchdir}/enc/trans/korean.so +%{ruby_libarchdir}/enc/trans/single_byte.so +%{ruby_libarchdir}/enc/trans/transdb.so +%{ruby_libarchdir}/enc/trans/utf8_mac.so +%{ruby_libarchdir}/enc/trans/utf_16_32.so +%{ruby_libarchdir}/enc/utf_16be.so +%{ruby_libarchdir}/enc/utf_16le.so +%{ruby_libarchdir}/enc/utf_32be.so +%{ruby_libarchdir}/enc/utf_32le.so +%{ruby_libarchdir}/enc/windows_1250.so +%{ruby_libarchdir}/enc/windows_1251.so +%{ruby_libarchdir}/enc/windows_1252.so +%{ruby_libarchdir}/enc/windows_1253.so +%{ruby_libarchdir}/enc/windows_1254.so +%{ruby_libarchdir}/enc/windows_1257.so +%{ruby_libarchdir}/enc/windows_31j.so +%{ruby_libarchdir}/etc.so +%{ruby_libarchdir}/fcntl.so +%{ruby_libarchdir}/fiber.so +%{ruby_libarchdir}/fiddle.so +%{ruby_libarchdir}/gdbm.so +%dir %{ruby_libarchdir}/io +%{ruby_libarchdir}/io/nonblock.so +%{ruby_libarchdir}/io/wait.so +%{ruby_libarchdir}/nkf.so +%{ruby_libarchdir}/objspace.so +%{ruby_libarchdir}/pathname.so +%{ruby_libarchdir}/pty.so +%dir %{ruby_libarchdir}/racc +%{ruby_libarchdir}/racc/cparse.so +%dir %{ruby_libarchdir}/rbconfig +%{ruby_libarchdir}/rbconfig.rb +%{ruby_libarchdir}/rbconfig/sizeof.so +%{ruby_libarchdir}/readline.so +%{ruby_libarchdir}/ripper.so +%{ruby_libarchdir}/sdbm.so +%{ruby_libarchdir}/socket.so +%{ruby_libarchdir}/stringio.so +%{ruby_libarchdir}/strscan.so +%{ruby_libarchdir}/syslog.so +%{ruby_libarchdir}/zlib.so + +%{?with_systemtap:%{tapset_root}} + +%files -n rubygems +%{_bindir}/gem +%dir %{rubygems_dir} +%{rubygems_dir}/rubygems +%{rubygems_dir}/rubygems.rb + +# Explicitly include only RubyGems directory strucure to avoid accidentally +# packaged content. +%dir %{gem_dir} +%dir %{gem_dir}/build_info +%dir %{gem_dir}/cache +%dir %{gem_dir}/doc +%dir %{gem_dir}/extensions +%dir %{gem_dir}/gems +%dir %{gem_dir}/specifications +%dir %{gem_dir}/specifications/default +%dir %{_exec_prefix}/lib*/gems +%dir %{_exec_prefix}/lib*/gems/ruby + +%exclude %{gem_dir}/cache/* + +# TODO: Gemify these libraries +%{gem_dir}/specifications/default/cmath-1.0.0.gemspec +%{gem_dir}/specifications/default/csv-3.0.9.gemspec +%{gem_dir}/specifications/default/date-2.0.3.gemspec +%{gem_dir}/specifications/default/dbm-1.0.0.gemspec +%{gem_dir}/specifications/default/e2mmap-0.1.0.gemspec +%{gem_dir}/specifications/default/etc-1.0.1.gemspec +%{gem_dir}/specifications/default/fcntl-1.0.0.gemspec +%{gem_dir}/specifications/default/fiddle-1.0.0.gemspec +%{gem_dir}/specifications/default/fileutils-1.1.0.gemspec +%{gem_dir}/specifications/default/forwardable-1.2.0.gemspec +%{gem_dir}/specifications/default/gdbm-2.0.0.gemspec +%{gem_dir}/specifications/default/ipaddr-1.2.2.gemspec +%{gem_dir}/specifications/default/logger-1.3.0.gemspec +%{gem_dir}/specifications/default/matrix-0.1.0.gemspec +%{gem_dir}/specifications/default/mutex_m-0.1.0.gemspec +%{gem_dir}/specifications/default/ostruct-0.1.0.gemspec +%{gem_dir}/specifications/default/prime-0.1.0.gemspec +%{gem_dir}/specifications/default/rexml-3.1.9.1.gemspec +%{gem_dir}/specifications/default/rss-0.2.7.gemspec +%{gem_dir}/specifications/default/scanf-1.0.0.gemspec +%{gem_dir}/specifications/default/sdbm-1.0.0.gemspec +%{gem_dir}/specifications/default/shell-0.7.gemspec +%{gem_dir}/specifications/default/stringio-0.0.2.gemspec +%{gem_dir}/specifications/default/strscan-1.0.0.gemspec +%{gem_dir}/specifications/default/sync-0.5.0.gemspec +%{gem_dir}/specifications/default/thwait-0.1.0.gemspec +%{gem_dir}/specifications/default/tracer-0.1.0.gemspec +%{gem_dir}/specifications/default/webrick-1.4.4.gemspec +%{gem_dir}/specifications/default/zlib-1.0.0.gemspec + +%files -n rubygems-devel +%{_rpmconfigdir}/macros.d/macros.rubygems +%{_rpmconfigdir}/fileattrs/rubygems.attr +%{_rpmconfigdir}/rubygems.req +%{_rpmconfigdir}/rubygems.prov +%{_rpmconfigdir}/rubygems.con + +%files -n rubygem-rake +%{_bindir}/rake +%{gem_dir}/gems/rake-%{rake_version} +%{gem_dir}/specifications/rake-%{rake_version}.gemspec +%{_mandir}/man1/rake.1* + +%files -n rubygem-irb +%{_bindir}/irb +%{ruby_libdir}/irb* +%{gem_dir}/gems/irb-%{irb_version} +%{gem_dir}/specifications/irb-%{irb_version}.gemspec +%{_mandir}/man1/irb.1* + +%files -n rubygem-rdoc +%{_bindir}/rdoc +%{_bindir}/ri +%{gem_dir}/gems/rdoc-%{rdoc_version} +%{gem_dir}/specifications/rdoc-%{rdoc_version}.gemspec +%{_mandir}/man1/ri* + +%files doc -f .ruby-doc.en -f .ruby-doc.ja +%doc README.md +%doc ChangeLog +%{?with_systemtap:%doc ruby-exercise.stp} +%{_datadir}/ri + +%files -n rubygem-bigdecimal +%{ruby_libdir}/bigdecimal +%{ruby_libarchdir}/bigdecimal* +%{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version} +%{gem_dir}/gems/bigdecimal-%{bigdecimal_version} +%{gem_dir}/specifications/bigdecimal-%{bigdecimal_version}.gemspec + +%files -n rubygem-did_you_mean +%{gem_dir}/gems/did_you_mean-%{did_you_mean_version} +%exclude %{gem_dir}/gems/did_you_mean-%{did_you_mean_version}/.* +%{gem_dir}/specifications/did_you_mean-%{did_you_mean_version}.gemspec + +%files -n rubygem-io-console +%{ruby_libdir}/io +%{ruby_libarchdir}/io/console.so +%{_libdir}/gems/%{name}/io-console-%{io_console_version} +%{gem_dir}/gems/io-console-%{io_console_version} +%{gem_dir}/specifications/io-console-%{io_console_version}.gemspec + +%files -n rubygem-json +%{ruby_libdir}/json* +%{ruby_libarchdir}/json* +%{_libdir}/gems/%{name}/json-%{json_version} +%{gem_dir}/gems/json-%{json_version} +%{gem_dir}/specifications/json-%{json_version}.gemspec + +%files -n rubygem-minitest +%{gem_dir}/gems/minitest-%{minitest_version} +%exclude %{gem_dir}/gems/minitest-%{minitest_version}/.* +%{gem_dir}/specifications/minitest-%{minitest_version}.gemspec + +%files -n rubygem-openssl +%{ruby_libdir}/openssl +%{ruby_libdir}/openssl.rb +%{ruby_libarchdir}/openssl.so +%{_libdir}/gems/%{name}/openssl-%{openssl_version} +%{gem_dir}/gems/openssl-%{openssl_version} +%{gem_dir}/specifications/openssl-%{openssl_version}.gemspec + +%files -n rubygem-power_assert +%{gem_dir}/gems/power_assert-%{power_assert_version} +%exclude %{gem_dir}/gems/power_assert-%{power_assert_version}/.* +%{gem_dir}/specifications/power_assert-%{power_assert_version}.gemspec + +%files -n rubygem-psych +%{ruby_libdir}/psych +%{ruby_libdir}/psych.rb +%{ruby_libarchdir}/psych.so +%{_libdir}/gems/%{name}/psych-%{psych_version} +%{gem_dir}/gems/psych-%{psych_version} +%{gem_dir}/specifications/psych-%{psych_version}.gemspec + +%files -n rubygem-net-telnet +%{gem_dir}/gems/net-telnet-%{net_telnet_version} +%exclude %{gem_dir}/gems/net-telnet-%{net_telnet_version}/.* +%{gem_dir}/specifications/net-telnet-%{net_telnet_version}.gemspec + +%files -n rubygem-test-unit +%{gem_dir}/gems/test-unit-%{test_unit_version} +%{gem_dir}/specifications/test-unit-%{test_unit_version}.gemspec + +%files -n rubygem-xmlrpc +%license %{gem_dir}/gems/xmlrpc-%{xmlrpc_version}/LICENSE.txt +%dir %{gem_dir}/gems/xmlrpc-%{xmlrpc_version} +%exclude %{gem_dir}/gems/xmlrpc-%{xmlrpc_version}/.* +%{gem_dir}/gems/xmlrpc-%{xmlrpc_version}/Gemfile +%{gem_dir}/gems/xmlrpc-%{xmlrpc_version}/Rakefile +%doc %{gem_dir}/gems/xmlrpc-%{xmlrpc_version}/README.md +%{gem_dir}/gems/xmlrpc-%{xmlrpc_version}/bin +%{gem_dir}/gems/xmlrpc-%{xmlrpc_version}/lib +%{gem_dir}/gems/xmlrpc-%{xmlrpc_version}/xmlrpc.gemspec +%{gem_dir}/specifications/xmlrpc-%{xmlrpc_version}.gemspec + +%files -n rubygem-bundler +%{_bindir}/bundle +%{_bindir}/bundler +%{gem_dir}/gems/bundler-%{bundler_version} +%{gem_dir}/specifications/bundler-%{bundler_version}.gemspec +%{_mandir}/man1/bundle*.1* +%{_mandir}/man5/gemfile.5* + +%changelog +* Thu May 19 2022 Vít Ondruch - 2.6.10-109 +- Upgrade to Ruby 2.6.10. + Resolves: rhbz#2088415 +- Fix buffer overrun in String-to-Float conversion. + Resolves: CVE-2022-28739 +- Fix FTBFS due to an incompatible load directive. +- Fix a fiddle import test on an optimized glibc on Power 9. + +* Wed Dec 08 2021 Jun Aruga - 2.6.9-108 +- Upgrade to Ruby 2.6.9. +- Skip JIT tests in RHEL 8. +- Fix the issues required to start the "make test-bundler" itself. +- Fix Bundler dependency confusion. + Resolves: CVE-2020-36327 + +* Wed Apr 14 2021 Jarek Prokop - 2.6.7-107 +- Upgrade to Ruby 2.6.7. + Resolves: rhbz#1757846 +- Resolv::DNS: timeouts if multiple IPv6 name servers are given an address + containing leading zero + Resolves: rhbz#1950307 +- Fix: Rubygem-bundler: Don't use insecure tmp directory as home + allows for execution of malicious code. + Resolves: CVE-2019-3881 + +* Thu Jul 04 2019 Jun Aruga - 2.6.3-106 +- Use ffi_closure_alloc to avoid segmentation fault by libffi on aarch64. + Resolves: rhbz#1727832 +- Properly support %%prerelease in %%gemspec_ macros. + Related: rhbz#1672575 + +* Tue Jun 11 2019 Jun Aruga - 2.6.3-105 +- Update to Ruby 2.6.3 by merging Fedora master branch (commit: 1cc2a49) + * Properly generate "ruby(rubygems)" versioned dependencies. + * Extract composition of dependecy strings into helper. + * Loosen RDoc dependency. + * Upstream fix adding -C flag instead of changing directory for gem build. + * Remove obsolete Group tag + * Fix ".include =" support in openssl.cnf. + * Link IRB back to StdLib. + * Link IRB files instead of directories. + * Exclude irb.rb from ruby-libs. + Resolves: rhbz#1672575 + +* Wed Apr 17 2019 Vít Ondruch - 2.5.5-104 +- Update to Ruby 2.5.5. + * Remove Patch25: ruby-2.6.0-Update-for-tzdata-2018f.patch; subsumed + * Remove Patch11: ruby-2.6.0-Try-to-update-cert.patch; subsumed + * Remove Patch19: ruby-2.6.0-net-http-net-ftp-fix-session-resumption-with + -TLS-1.3.patch; subsumed + Resolves: rhbz#1688758 +- Don't ship .stp files when SystemTap support is disabled. + Related: rhbz#1657915 +- Fix CovScan issues. + Resolves: rhbz#1628592 + +* Fri Jan 11 2019 Jun Aruga - 2.5.3-103 +- Refresh expired certificates to fix FTBFS. + +* Tue Nov 13 2018 Vít Ondruch - 2.5.3-102 +- Fix Tokyo TZ tests. + +* Fri Oct 19 2018 Jun Aruga - 2.5.3-101 +- Update to Ruby 2.5.3. + Resolves: rhbz#1643092 + +* Mon Sep 03 2018 Vít Ondruch - 2.5.1-100 +- Properly harden package using -fstack-protector-strong. + * ruby-2.6.0-configure-fstack-protector-strong.patch + Resolves: rhbz#1624168 + +* Wed Aug 29 2018 Vít Ondruch - 2.5.1-99 +- Additional OpenSSL 1.1.1 fixes. + * ruby-2.6.0-fix-test-failure-with-TLS-1.3-maint.patch + * ruby-2.6.0-config-support-include-directive.patch + * ruby-2.6.0-use-larger-keys-for-SSL-tests.patch + Related: rhbz#1616213 + +* Tue Aug 28 2018 Jun Aruga - 2.5.1-99 +- Fix generated rdoc template issues. + * ruby-2.6.0-rdoc-6.0.1-fix-template-typo.patch + Resolves: rhbz#1612026 + +* Mon Aug 13 2018 Vít Ondruch - 2.5.1-97 +- Fix TLS 1.3 issues. + * ruby-2.6.0-fix-test-failure-with-TLS-1.3.patch + * ruby-2.6.0-net-http-net-ftp-fix-session-resumption-with-TLS-1.3.patch + Related: rhbz#1616213 + +* Sat Aug 11 2018 Troy Dawson - 2.5.1-96 +- turn off tests +- Related: bug#1614611 + +* Tue Jul 31 2018 Florian Weimer - 2.5.1-96 +- Rebuild with fixed binutils + +* Fri Jul 27 2018 Igor Gnatenko - 2.5.1-95 +- Rebuild for new binutils + +* Thu Jul 26 2018 Vít Ondruch - 2.5.1-94 +- Disable some test failing with OpenSSL 1.1.1. + +* Sat Jul 14 2018 Fedora Release Engineering - 2.5.1-94 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Thu May 10 2018 Pavel Valena - 2.5.1-93 +- Add macros to edit files lists in .gemspec + (gemspec_add_file and gemspec_remove_file). + +* Wed May 02 2018 Vít Ondruch - 2.5.1-93 +- Make %%gemspec_{add,remove}_dep modify .gemspec provided by %%setup macro. + +* Tue Apr 10 2018 Vít Ondruch - 2.5.1-92 +- Conflict requirement needs to generate dependency. +- Stop using --with-setjmp-type=setjmp on aarch64 (rhbz#1545239). + +* Thu Mar 29 2018 Pavel Valena - 2.5.1-92 +- Update to Ruby 2.5.1. + +* Mon Mar 05 2018 Vít Ondruch - 2.5.0-91 +- Don't force libraries used to build Ruby to its dependencies. +- Re-enable GMP dependency. + +* Thu Mar 01 2018 Vít Ondruch - 2.5.0-90 +- Drop GMP dependency. + +* Sat Feb 24 2018 Florian Weimer - 2.5.0-89 +- Rebuild with new LDFLAGS from redhat-rpm-config +- Use --with-setjmp-type=setjmp on aarch64 to work around gcc issue (#1545239) + +* Wed Feb 21 2018 Pavel Valena - 2.5.0-89 +- Fix: Multiple vulnerabilities in RubyGems + https://bugzilla.redhat.com/show_bug.cgi?id=1547431 + https://www.ruby-lang.org/en/news/2018/02/17/multiple-vulnerabilities-in-rubygems/ + +* Tue Feb 13 2018 Vít Ondruch - 2.5.0-89 +- Drop obsolete ldconfig scriptlets. +- Add GMP dependency. +- Use 'with' operator in RPM dependency generator. +- Add conflicts RPM generator. +- Fix thread_safe test suite segfaults. +- Fix invalid licenses. + +* Fri Feb 09 2018 Fedora Release Engineering - 2.5.0-89 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Sat Jan 20 2018 Björn Esser - 2.5.0-88 +- Rebuilt for switch to libxcrypt + +* Tue Jan 09 2018 Vít Ondruch - 2.5.0-87 +- Fix segfaults during generating of documentation. + +* Tue Jan 02 2018 Vít Ondruch - 2.5.0-86 +- Upgrade to Ruby 2.5.0. + +* Fri Oct 27 2017 Jun Aruga - 2.4.2-86 +- Add macro to remove rubypick dependency. +- Improve "with" conditional statement as inline. + +* Thu Oct 19 2017 Jun Aruga - 2.4.2-85 +- Add macros to remove systemtap, git and cmake dependencies. + +* Mon Sep 18 2017 Pavel Valena - 2.4.2-84 +- Update to Ruby 2.4.2. + +* Fri Sep 08 2017 Vít Ondruch - 2.4.1-84 +- Drop ruby-devel dependency on rubypick, which is pulled in transtitively. + +* Fri Aug 11 2017 Vít Ondruch - 2.4.1-83 +- Fix "IOError: stream closed" errors affecting Puma. +- Temporary disable checksec on PPC64LE (rhbz#1479302). + +* Thu Aug 03 2017 Fedora Release Engineering - 2.4.1-82 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Thu Jul 27 2017 Fedora Release Engineering - 2.4.1-81 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Thu Jul 20 2017 Vít Ondruch - 2.4.1-80 +- OpenSSL 1.1.0f-3 disables some weak ciphers. Adjust the package to pass + the tests suite. + +* Mon Apr 03 2017 Vít Ondruch - 2.4.1-79 +- Update to Ruby 2.4.1. + +* Thu Feb 23 2017 Vít Ondruch - 2.4.0-78 +- Fix OpenSSL symlinks. + +* Sat Feb 11 2017 Fedora Release Engineering - 2.4.0-77 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Fri Feb 03 2017 Vít Ondruch - 2.4.0-76 +- Fix GCC 7.x compatibility (rhbz#1417590). +- Use standardized multilib solution (rhbz#1412274). + +* Tue Jan 17 2017 Vít Ondruch - 2.4.0-75 +- Apply patch fixing rubygem-mongo build failures. + +* Fri Jan 13 2017 Mamoru TASAKA - 2.4.0-74 +- Rebuild again for f26-ruby24 sidetag + +* Thu Jan 12 2017 Igor Gnatenko - 2.4.0-73 +- Rebuild for readline 7.x + +* Wed Jan 11 2017 Vít Ondruch - 2.4.0-72 +- Link files into directory to avoid dir => symlink isues. + +* Mon Jan 09 2017 Vít Ondruch - 2.4.0-71 +- Add rubygem-io-console dependency for rubygem-rdoc. + +* Mon Jan 02 2017 Vít Ondruch - 2.4.0-70 +- Upgrade to Ruby 2.4.0. +- Move gemified xmlrpc into subpackage. +- Move gemified openssl into subpackage. +- Tk is removed from stdlib. +- Extend 'gem_' macros for pre-release version support. + +* Tue Nov 22 2016 Vít Ondruch - 2.3.3-61 +- Update to Ruby 2.3.3. +- Exclude json.rb from ruby-libs (rhbz#1397370). + +* Fri Nov 18 2016 Vít Ondruch - 2.3.2-60 +- Update to Ruby 2.3.2. + +* Fri Oct 21 2016 Vít Ondruch - 2.3.1-59 +- Continue to use OpenSSL 1.0 for the moment. +- Add gemspec_add_dep and gemspec_remove_dep macros. +- Harden package. + +* Wed Aug 10 2016 Vít Ondruch - 2.3.1-58 +- Workaround "an invalid stdio handle" error on PPC (rhbz#1361037). + +* Tue Jul 12 2016 Vít Ondruch - 2.3.1-57 +- Make symlinks for json gem. + +* Mon May 23 2016 Vít Ondruch - 2.3.1-56 +- Requires rubygem(json) for rubygem-rdoc (rhbz#1325022). + +* Fri Apr 29 2016 Vít Ondruch - 2.3.1-55 +- Update to Ruby 2.3.1. + +* Wed Feb 3 2016 Peter Robinson 2.3.0-54 +- Add rubypick and rubygems requires to ruby-devel to deal with BuildRequires + +* Fri Jan 15 2016 Mamoru TASAKA - 2.3.0-53 +- Backport trunk@53455 to make ruby-qt build + +* Wed Jan 06 2016 Vít Ondruch - 2.3.0-52 +- Explicitly require RDoc, since weak dependencies are ignored by default. + +* Wed Jan 06 2016 Vít Ondruch - 2.3.0-51 +- Load RubyGems prior ABRT hook to properly rescue RubyGems exceptions. + +* Mon Jan 04 2016 Vít Ondruch - 2.3.0-50 +- Upgrade to Ruby 2.3.0. +- Move gemified net-telnet into subpackage. +- Add did_you_mean subpackage. +- Add virtual provides for CCAN copylibs. +- Use weak dependencies. + +* Tue Dec 22 2015 Pavel Valena - 2.3.0-0.7.preview2 +- Add systemtap tests. + +* Mon Dec 21 2015 Vít Ondruch - 2.2.4-47 +- Update to Ruby 2.2.4. + +* Thu Dec 10 2015 Vít Ondruch - 2.2.3-46 +- Fix ABRT hook autoloading. + +* Fri Sep 04 2015 Michal Toman - 2.2.3-45 +- Add support for MIPS architecture to config.h + +* Tue Sep 01 2015 Vít Ondruch - 2.2.3-44 +- Update to Ruby 2.2.3. + +* Tue Jun 23 2015 Vít Ondruch - 2.2.2-43 +- Fix for "dh key too small" error of OpenSSL 1.0.2+. + +* Thu Jun 18 2015 Fedora Release Engineering - 2.2.2-42 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed Jun 10 2015 Vít Ondruch - 2.2.2-41 +- Fix the git BR following the git package split. + +* Mon May 04 2015 Vít Ondruch - 2.2.2-40 +- Fix upgrade path (rubygem-io-console's version was recently bumped in F21 + and makes the higher release to win). + +* Tue Apr 14 2015 Josef Stribny - 2.2.2-11 +- Bump release because of gems + +* Tue Apr 14 2015 Josef Stribny - 2.2.2-1 +- Update to Ruby 2.2.2 + +* Fri Mar 20 2015 Vít Ondruch - 2.2.1-10 +- Fix libruby.so versions in SystemTap scripts (rhbz#1202232). + +* Wed Mar 04 2015 Vít Ondruch - 2.2.1-9 +- Update to Ruby 2.2.1. + +* Sat Feb 21 2015 Till Maas - 2.2.0-8 +- Rebuilt for Fedora 23 Change + https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code + +* Thu Feb 05 2015 Vít Ondruch - 2.2.0-7 +- Fix directory ownership. + +* Wed Feb 04 2015 Vít Ondruch - 2.2.0-6 +- Initialize all load paths in operating_system.rb. + +* Tue Feb 03 2015 Vít Ondruch - 2.2.0-5 +- Make operating_system.rb more robust. +- Add RubyGems stub headers for bundled gems. + +* Thu Jan 29 2015 Vít Ondruch - 2.2.0-4 +- Add missing rubygem-test-unit dependency on rubygem-power_assert. + +* Thu Jan 15 2015 Mamoru TASAKA - 2.2.0-3 +- Bump release to avoid EVR issue on rubygem-test-unit + +* Fri Jan 02 2015 Vít Ondruch - 2.2.0-1 +- Upgrade to Ruby 2.2.0. +- Explicitly list RubyGems directories to avoid accidentaly packaged content. +- Split test-unit and power_assert gems into separate sub-packages. +- Drop libdb dependency in favor of gdbm. + +* Fri Dec 26 2014 Orion Poplwski - 2.1.5-26 +- Disbable sse2 on i668 (bug #1101811) + +* Thu Nov 20 2014 Vít Ondruch - 2.1.5-25 +- Update to Ruby 2.1.5. + +* Fri Oct 31 2014 Vít Ondruch - 2.1.4-24 +- Update to Ruby 2.1.4. +- Include only vendor directories, not their content (rhbz#1114071). +- Fix "invalid regex" warning for non-rubygem packages (rhbz#1154067). +- Use load macro introduced in RPM 4.12. + +* Mon Aug 18 2014 Fedora Release Engineering +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Tue Jun 24 2014 Peter Robinson 2.1.2-23 +- Fix FTBFS +- Specify tcl/tk 8.6 +- Add upstream patch to build with libffi 3.1 + +* Sun Jun 08 2014 Fedora Release Engineering +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Wed May 21 2014 Jaroslav Škarvada +- Rebuilt for https://fedoraproject.org/wiki/Changes/f21tcl86 + +* Tue May 20 2014 Josef Stribny - 2.1.2-21 +- Update to Ruby 2.1.2 + +* Tue May 06 2014 Vít Ondruch - 2.1.1-20 +- Remove useless exclude (rhbz#1065897). +- Extract load macro into external file and include it. +- Kill bundled certificates. + +* Wed Apr 23 2014 Vít Ondruch - 2.1.1-19 +- Correctly expand $(prefix) in some Makefiles, e.g. eruby. + +* Tue Apr 08 2014 Vít Ondruch - 2.1.1-18 +- Update to Ruby 2.1.1. +- Revert regression of Hash#reject. + +* Mon Mar 03 2014 Vít Ondruch - 2.1.0-19 +- Add RPM dependency generators for RubyGems. + +* Mon Feb 10 2014 Josef Stribny - 2.1.0-19 +- Don't link cert.pem explicitely + +* Wed Jan 15 2014 Vít Ondruch - 2.1.0-18 +- Don't generate documentation on unexpected places. +- Detect if rubygems are running under rpmbuild and install gem binary + extensions into appropriate place. +- Add support for ppc64le arch (rhbz#1053263). +- Re-enable some test cases, which are passing now with Kernel 3.12.8+. +- Backport fix for floating point issues on i686. + +* Thu Jan 02 2014 Vít Ondruch - 2.1.0-17 +- Upgrade to Ruby 2.1.0. +- Move RPM macros into /usr/lib/rpm/macros.d directory. +- Allow MD5 in OpenSSL for tests. + +* Tue Jul 30 2013 Vít Ondruch - 2.0.0.247-15 +- Move Psych symlinks to vendor dir, to prevent F18 -> F19 upgrade issues + (rhbz#988490). + +* Mon Jul 15 2013 Vít Ondruch - 2.0.0.247-14 +- Add forgotten psych.rb link into rubygem-psych to fix "private method `load' + called for Psych:Moduler" error (rhbz#979133). + +* Thu Jul 11 2013 Vít Ondruch - 2.0.0.247-13 +- Fixes multilib conlicts of .gemspec files. +- Make symlinks for psych gem to ruby stdlib dirs (rhbz#979133). +- Use system-wide cert.pem. + +* Thu Jul 04 2013 Vít Ondruch - 2.0.0.247-12 +- Fix RubyGems search paths when building gems with native extension + (rhbz#979133). + +* Tue Jul 02 2013 Vít Ondruch - 2.0.0.247-11 +- Fix RubyGems version. + +* Tue Jul 02 2013 Vít Ondruch - 2.0.0.247-10 +- Better support for build without configuration (rhbz#977941). + +* Mon Jul 01 2013 Vít Ondruch - 2.0.0.247-9 +- Update to Ruby 2.0.0-p247 (rhbz#979605). +- Fix CVE-2013-4073. +- Fix for wrong makefiles created by mkmf (rhbz#921650). +- Add support for ABRT autoloading. + +* Fri May 17 2013 Vít Ondruch - 2.0.0.195-8 +- Update to Ruby 2.0.0-p195 (rhbz#917374). +- Fix object taint bypassing in DL and Fiddle (CVE-2013-2065). +- Fix build against OpenSSL with enabled ECC curves. +- Add aarch64 support (rhbz#926463). + +* Fri Apr 19 2013 Vít Ondruch - 2.0.0.0-7 +- Macro definition moved into macros.ruby and macros.rubygems files. +- Added filtering macros. +- Filter automatically generated provides of private libraries (rhbz#947408). + +* Fri Mar 22 2013 Vít Ondruch - 2.0.0.0-6 +- Fix RbConfig::CONFIG['exec_prefix'] returns empty string (rhbz#924851). + +* Thu Mar 21 2013 Vít Ondruch - 2.0.0.0-5 +- Make Ruby buildable without rubypick. +- Prevent random test failures. + +* Fri Mar 08 2013 Mamoru TASAKA - 2.0.0.0-4 +- Don't mark rpm config file as %%config (fpc#259) + +* Tue Mar 05 2013 Vít Ondruch - 2.0.0.0-3 +- Avoid "method redefined;" warnings due to modified operating_system.rb. +- Fix strange paths created during build of binary gems. + +* Mon Feb 25 2013 Vít Ondruch - 2.0.0.0-2 +- Prevent squash of %%gem_install with following line. + +* Mon Feb 25 2013 Vít Ondruch - 2.0.0.0-1 +- Update to Ruby 2.0.0-p0. +- Change %%{ruby_extdir} to %%{ruby_extdir_mri} in preparation for better + JRuby support. + +* Mon Feb 25 2013 Mamoru TASAKA - 2.0.0.0-0.3.r39387 +- Move test-unit.gemspec to -libs subpackage for now because rubygems + 2.0.0 does not create this + +* Fri Feb 22 2013 Vít Ondruch - 2.0.0.0-0.2.r39387 +- Fix issues with wrong value of Rubygem's shebang introduced in r39267. + +* Fri Feb 22 2013 Vít Ondruch - 2.0.0.0-0.1.r39387 +- Upgrade to Ruby 2.0.0 (r39387). +- Introduce %%gem_install macro. +- Build against libdb instead of libdb4 (rhbz#894022). +- Move native extensions from exts to ruby directory. +- Enable most of the PPC test suite. +- Change ruby(abi) -> ruby(release). +- Rename ruby executable to ruby-mri, to be prepared for RubyPick. +- Add ruby(runtime_executable) virtual provide, which is later used + by RubyPick. +- RDoc now depends on JSON. +- Try to make -doc subpackage noarch again, since the new RDoc should resolve + the arch dependent issues (https://github.com/rdoc/rdoc/issues/71). +- Enable SystemTap support. +- Add TapSet for Ruby. +- Split Psych into rubygem-psych subpackage. + +* Mon Feb 11 2013 Mamoru TASAKA - 1.9.3.385-28 +- Update to 1.9.3 p385 + +* Sat Jan 19 2013 Mamoru TASAKA - 1.9.3.374-27 +- Update to 1.9.3 p374 +- Fix provided variables in pkgconfig (bug 789532: + Vít Ondruch ) + +* Fri Jan 18 2013 Mamoru TASAKA - 1.9.3.362-26 +- Provide non-versioned pkgconfig file (bug 789532) +- Use db5 on F-19 (bug 894022) + +* Wed Jan 16 2013 Mamoru TASAKA - 1.9.3.362-25 +- Backport fix for the upstream PR7629, save the proc made from the given block + (bug 895173) + +* Wed Jan 2 2013 Mamoru TASAKA - 1.9.3.362-24 +- Update to 1.9.3.362 + +* Mon Dec 03 2012 Jaromir Capik - 1.9.3.327-23 +- Skipping test_parse.rb (fails on ARM at line 787) +- http://bugs.ruby-lang.org/issues/6899 + +* Sun Nov 11 2012 Mamoru TASAKA - 1.9.3.327-23 +- Skip test_str_crypt (on rawhide) for now (upstream bug 7312) + +* Sat Nov 10 2012 Mamoru TASAKA - 1.9.3.327-22 +- Ignore some network related tests + +* Sat Nov 10 2012 Mamoru TASAKA - 1.9.3.327-21 +- Update to 1.9.3.327 +- Fix Hash-flooding DoS vulnerability on MurmurHash function + (CVE-2012-5371) + +* Sat Oct 13 2012 Mamoru TASAKA - 1.9.3.286-19 +- Update to 1.9.3 p286 +- Don't create files when NUL-containing path name is passed + (bug 865940, CVE-2012-4522) + +* Thu Oct 04 2012 Mamoru Tasaka - 1.9.3.194-18 +- Patch from trunk for CVE-2012-4464, CVE-2012-4466 + +* Thu Sep 06 2012 Vít Ondruch - 1.9.3.194-17 +- Split documentation into -doc subpackage (rhbz#854418). + +* Tue Aug 14 2012 Vít Ondruch - 1.9.3.194-16 +- Revert the dependency of ruby-libs on rubygems (rhbz#845011, rhbz#847482). + +* Wed Aug 01 2012 Vít Ondruch - 1.9.3.194-15 +- ruby-libs must require rubygems (rhbz#845011). + +* Sat Jul 21 2012 Fedora Release Engineering - 1.9.3.194-14 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jun 11 2012 Bohuslav Kabrda - 1.9.3.194-13 +- Make the bigdecimal gem a runtime dependency of Ruby. + +* Mon Jun 11 2012 Bohuslav Kabrda - 1.9.3.194-12 +- Make symlinks for bigdecimal and io-console gems to ruby stdlib dirs (RHBZ 829209). + +* Tue May 29 2012 Bohuslav Kabrda - 1.9.3.194-11 +- Fix license to contain Public Domain. +- macros.ruby now contains unexpanded macros. + +* Sun Apr 22 2012 Mamoru Tasaka - 1.9.3.194-10.1 +- Bump release + +* Fri Apr 20 2012 Vít Ondruch - 1.9.3.194-1 +- Update to Ruby 1.9.3-p194. + +* Mon Apr 09 2012 Karsten Hopp 1.9.3.125-3 +- disable check on ppc(64), RH bugzilla 803698 + +* Wed Feb 29 2012 Peter Robinson - 1.9.3.125-2 +- Temporarily disable make check on ARM until it's fixed upstream. Tracked in RHBZ 789410 + +* Mon Feb 20 2012 Vít Ondruch - 1.9.3.125-1 +- Upgrade to Ruby 1.9.3-p125. + +* Sun Jan 29 2012 Mamoru Tasaka - 1.9.3.0-7 +- Make mkmf.rb verbose by default + +* Thu Jan 26 2012 Vít Ondruch - 1.9.3.0-6 +- Relax dependencies to allow external updates of bundled gems. + +* Wed Jan 18 2012 Vít Ondruch - 1.9.3.0-5 +- Initial release of Ruby 1.9.3. +- Add rubygems dependency on io-console for user interactions. +- Gems license clarification. + +* Tue Jan 17 2012 Vít Ondruch - 1.9.3.0-4 +- Bundled gems moved into dedicated directories and subpackages. +- Create and own RubyGems directories for binary extensions. +- Fix build with GCC 4.7. + +* Mon Jan 16 2012 Vít Ondruch - 1.9.3.0-3 +- Fix RHEL build. +- Fixed directory ownership. +- Verose build output. + +* Sun Jan 15 2012 Vít Ondruch - 1.9.3.0-2 +- Install RubyGems outside of Ruby directory structure. +- RubyGems has not its own -devel subpackage. +- Enhanced macros.ruby and macros.rubygems. +- All tests are green now (bkabrda). + +* Sat Jan 14 2012 Vít Ondruch - 1.9.3.0-1 +- Initial package + +* Sat Jan 14 2012 Fedora Release Engineering - 1.8.7.357-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Thu Dec 29 2011 Mamoru Tasaka - 1.8.7.357-1 +- Update to 1.8.7p357 +- Randomize hash on process startup (CVE-2011-4815, bug 750564) + +* Fri Dec 23 2011 Dennis Gilmore - 1.8.7.352-2 +- dont normalise arm cpus to arm +- there is something weird about how ruby choses where to put bits + +* Thu Nov 17 2011 Mamoru Tasaka - 1.8.7.352-3 +- F-17: kill gdbm support for now due to licensing compatibility issue + +* Sat Oct 1 2011 Mamoru Tasaka - 1.8.7.352-2 +- F-17: rebuild against new gdbm + +* Sat Jul 16 2011 Mamoru Tasaka - 1.8.7.352-1 +- Update to 1.8.7 p352 +- CVE-2011-2686 is fixed in this version (bug 722415) +- Update ext/tk to the latest git +- Remove duplicate path entry (bug 718695) + +* Thu Jul 14 2011 Mamoru Tasaka - 1.8.7.334-4 +- Once fix FTBFS (bug 716021) + +* Mon Jul 11 2011 Dennis Gilmore - 1.8.7.334-3 +- normalise arm cpus to arm + +* Mon May 30 2011 Mamoru Tasaka - 1.8.7.334-2 +- Own %%{_normalized_cpu}-%%{_target_os} directory (bug 708816) + +* Sat Feb 19 2011 Mamoru Tasaka - 1.8.7.334-1 +- Update to 1.8.7 p334 + +* Wed Feb 09 2011 Fedora Release Engineering - 1.8.7.330-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Sun Jan 02 2011 Dennis Gilmore - 1.8.7.330-2 +- nomalise the 32 bit sparc archs to sparc + +* Sun Dec 26 2010 Mamoru Tasaka - 1.8.7.330-1 +- Update to 1.8.7 p330 +- ext/tk updated to the newest header + +* Thu Nov 4 2010 Mamoru Tasaka - 1.8.7.302-2 +- Avoid multilib conflict on -libs subpackage (bug 649174) + +* Mon Aug 23 2010 Mamoru Tasaka - 1.8.7.302-1 +- Update to 1.8.7.302 +- CVE-2010-0541 (bug 587731) is fixed in this version +- Update ext/tk to the latest head + +* Mon Aug 2 2010 Mamoru Tasaka - 1.8.7.299-5 +- More cleanup of spec file, expecially for rpmlint issue +- build ri files in %%build + +* Mon Jul 26 2010 Mamoru Tasaka - 1.8.7.299-4 +- Cleanup spec file +- Make -irb, -rdoc subpackage noarch +- Make dependencies between arch-dependent subpackages isa specific +- Improve sample documentation gathering + +* Mon Jul 12 2010 Mohammed Morsi - 1.8.7.299-3 +- updated packaged based on feedback (from mtasaka) +- added comments to all patches / sources +- obsoleted ruby-mode, as it's now provided by the emacs package itself +- readded missing documentation +- various small compatability/regression fixes + +* Tue Jul 06 2010 Mohammed Morsi - 1.8.7.299-2 +- readded bits to pull tk package from upstream source branch +- removed unecessary .tk.old dir +- renamed macros which may cause confusion, removed unused ones + +* Thu Jun 24 2010 Mohammed Morsi - 1.8.7.299-1 +- integrate more of jmeyering's and mtaska's feedback +- removed emacs bits that are now shipped with the emacs package +- various patch and spec cleanup +- rebased to ruby 1.8.7 patch 299, removed patches no longer needed: + ruby-1.8.7-openssl-1.0.patch, ruby-1.8.7-rb_gc_guard_ptr-optimization.patch + +* Wed Jun 23 2010 Mohammed Morsi - 1.8.7.249-5 +- Various fixes + +* Wed Jun 23 2010 Mohammed Morsi - 1.8.7.249-4 +- Fixed incorrect paths in 1.8.7 rpm + +* Tue Jun 22 2010 Mohammed Morsi - 1.8.7.249-3 +- Integrated Jim Meyering's feedback and changes in to: +- remove trailing blanks +- placate rpmlint +- ruby_* definitions: do not use trailing slashes in directory names +- _normalized_cpu: simplify definition + +* Mon Jun 21 2010 Mohammed Morsi - 1.8.7.249-2 +- Integrate mtasaka's feedback and changes +- patch101 ruby_1_8_7-rb_gc_guard_ptr-optimization.patch + +* Tue Jun 15 2010 Mohammed Morsi - 1.8.7.249-1 +- Initial Ruby 1.8.7 specfile + +* Wed May 19 2010 Mamoru Tasaka - 1.8.6.399-5 +- Retry for bug 559158, Simplify the OpenSSL::Digest class + pull more change commits from ruby_1_8 branch + +* Mon May 17 2010 Mamoru Tasaka - 1.8.6.399-4 +- Patch36 (ruby-1.8.x-RHASH_SIZE-rb_hash_lookup-def.patch) + also backport rb_hash_lookup definition (bug 592936) + +* Thu May 13 2010 Mamoru Tasaka - 1.8.6.399-3 +- ruby-1.8.x-null-class-must-be-Qnil.patch (bug 530407) +- Recreate some patches using upstream svn when available, and + add some comments for patches + +* Tue May 11 2010 Mamoru Tasaka - 1.8.6.399-2 +- tcltk: Give up using potentially unmaintained ruby_1_8_6 branch + and instead completely replace with ruby_1_8 branch head + (at this time, using rev 27738) + (seems to fix 560053, 590503) +- Fix Japanese encoding strings under ruby-tcltk/ext/tk/sample/ + +* Tue Apr 27 2010 Mamoru Tasaka - 1.8.6.399-1 +- Update to 1.8.6 p 399 (bug 579675) +- Patch to fix gc bug causing open4 crash (bug 580993) + +* Fri Mar 12 2010 Mamoru Tasaka - 1.8.6.388-9 +- F-14: rebuild against new gdbm + +* Thu Jan 28 2010 Mamoru Tasaka +- Once revert the previous change (patch34) + +* Wed Jan 27 2010 Jeroen van Meeuwen - 1.8.6.388-8 +- Backport openssl/digest functions providing digest and hexdigest functions + directly in OpenSSL::Digest.methods +- Make sure that Red Hat people version their changelog entries +- This is actually release #1, but now needs to be release #7 + +* Mon Jan 18 2010 Akira TAGOH - 1.8.6.388-1 +- Add conditional for RHEL. + +* Wed Jan 13 2010 Mamoru Tasaka - 1.8.6.383-6 +- CVE-2009-4492 ruby WEBrick log escape sequence (bug 554485) + +* Wed Dec 9 2009 Mamoru Tasaka - 1.8.6.383-5 +- Change mkmf.rb to use LIBRUBYARG_SHARED so that have_library() works + without libruby-static.a (bug 428384) +- And move libruby-static.a to -static subpackage + +* Thu Oct 29 2009 Mamoru Tasaka - 1.8.6.383-4 +- Use bison to regenerate parse.c to keep the original format of error + messages (bug 530275 comment 4) + +* Sun Oct 25 2009 Mamoru Tasaka - 1.8.6.383-3 +- Patch so that irb saves its history (bug 518584, ruby issue 1556) + +* Sat Oct 24 2009 Mamoru Tasaka - 1.8.6.383-2 +- Update to 1.8.6 patchlevel 383 (bug 520063) + +* Wed Oct 14 2009 Mamoru Tasaka - 1.8.6.369-5 +- Much better idea for Patch31 provided by Akira TAGOH + +* Wed Oct 14 2009 Mamoru Tasaka - 1.8.6.369-4 +- Fix the search path of ri command for ri manuals installed with gem + (bug 528787) + +* Wed Aug 26 2009 Tomas Mraz - 1.8.6.369-3 +- Rebuild against new openssl + +* Thu Jul 23 2009 Mamoru Tasaka - 1.8.6.369-2 +- Make sure that readline.so is linked against readline 5 because + Ruby is under GPLv2 + +* Sat Jun 20 2009 Jeroen van Meeuwen - 1.8.6.369-1 +- New patchlevel fixing CVE-2009-1904 +- Fix directory on ARM (#506233, Kedar Sovani) + +* Sun May 31 2009 Jeroen van Meeuwen - 1.8.6.368-1 +- New upstream release (p368) + +* Sat Apr 11 2009 Mamoru Tasaka - 1.8.6.287-8 +- Merge Review fix (#226381) + +* Wed Mar 18 2009 Jeroen van Meeuwen - 1.8.6.287-7 +- Fix regression in CVE-2008-3790 (#485383) + +* Mon Mar 16 2009 Mamoru Tasaka - 1.8.6.287-6 +- Again use -O2 optimization level +- i586 should search i386-linux directory (on <= F-11) + +* Thu Mar 05 2009 Jeroen van Meeuwen - 1.8.6.287-5 +- Rebuild for gcc4.4 + +* Fri Feb 27 2009 Jeroen van Meeuwen - 1.8.6.287-3 +- CVE-2008-5189: CGI header injection. + +* Wed Oct 8 2008 Akira TAGOH - 1.8.6.287-2 +- CVE-2008-3790: DoS vulnerability in the REXML module. + +* Sat Aug 23 2008 Akira TAGOH - 1.8.6.287-1 +- New upstream release. +- Security fixes. + - CVE-2008-3655: Ruby does not properly restrict access to critical + variables and methods at various safe levels. + - CVE-2008-3656: DoS vulnerability in WEBrick. + - CVE-2008-3657: Lack of taintness check in dl. + - CVE-2008-1447: DNS spoofing vulnerability in resolv.rb. + - CVE-2008-3443: Memory allocation failure in Ruby regex engine. +- Remove the unnecessary backported patches. + +* Thu Jul 10 2008 Tom "spot" Callaway - 1.8.6.230-5 +- rebuild against db4-4.7 + +* Tue Jul 1 2008 Akira TAGOH - 1.8.6.230-4 +- Backported from upstream SVN to fix a segfault issue with Array#fill. + +* Mon Jun 30 2008 Akira TAGOH - 1.8.6.230-3 +- Backported from upstream SVN to fix a segfault issue. (#452825) +- Backported from upstream SVN to fix an integer overflow in rb_ary_fill. + +* Wed Jun 25 2008 Akira TAGOH - 1.8.6.230-2 +- Fix a segfault issue. (#452810) + +* Tue Jun 24 2008 Akira TAGOH - 1.8.6.230-1 +- New upstream release. +- Security fixes. (#452295) + - CVE-2008-1891: WEBrick CGI source disclosure. + - CVE-2008-2662: Integer overflow in rb_str_buf_append(). + - CVE-2008-2663: Integer overflow in rb_ary_store(). + - CVE-2008-2664: Unsafe use of alloca in rb_str_format(). + - CVE-2008-2725: Integer overflow in rb_ary_splice(). + - CVE-2008-2726: Integer overflow in rb_ary_splice(). +- ruby-1.8.6.111-CVE-2007-5162.patch: removed. +- Build ruby-mode package for all archtectures. + +* Tue Mar 4 2008 Akira TAGOH - 1.8.6.114-1 +- Security fix for CVE-2008-1145. +- Improve a spec file. (#226381) + - Correct License tag. + - Fix a timestamp issue. + - Own a arch-specific directory. + +* Tue Feb 19 2008 Fedora Release Engineering - 1.8.6.111-9 +- Autorebuild for GCC 4.3 + +* Tue Feb 19 2008 Akira TAGOH - 1.8.6.111-8 +- Rebuild for gcc-4.3. + +* Tue Jan 15 2008 Akira TAGOH - 1.8.6.111-7 +- Revert the change of libruby-static.a. (#428384) + +* Fri Jan 11 2008 Akira TAGOH - 1.8.6.111-6 +- Fix an unnecessary replacement for shebang. (#426835) + +* Fri Jan 4 2008 Akira TAGOH - 1.8.6.111-5 +- Rebuild. + +* Fri Dec 28 2007 Akira TAGOH - 1.8.6.111-4 +- Clean up again. + +* Fri Dec 21 2007 Akira TAGOH - 1.8.6.111-3 +- Clean up the spec file. +- Remove ruby-man-1.4.6 stuff. this is entirely the out-dated document. + this could be replaced by ri. +- Disable the static library building. + +* Tue Dec 04 2007 Release Engineering - 1.8.6.111-2 + - Rebuild for openssl bump + +* Wed Oct 31 2007 Akira TAGOH +- Fix the dead link. + +* Mon Oct 29 2007 Akira TAGOH - 1.8.6.111-1 +- New upstream release. +- ruby-1.8.6.111-CVE-2007-5162.patch: Update a bit with backporting the changes + at trunk to enable the fix without any modifications on the users' scripts. + Note that Net::HTTP#enable_post_connection_check isn't available anymore. + If you want to disable this post-check, you should give OpenSSL::SSL::VERIFY_NONE + to Net::HTTP#verify_mode= instead of. + +* Mon Oct 15 2007 Akira TAGOH - 1.8.6.110-2 +- Enable pthread support for ppc too. (#201452) +- Fix unexpected dependencies appears in ruby-libs. (#253325) + +* Wed Oct 10 2007 Akira TAGOH - 1.8.6.110-1 +- New upstream release. + - ruby-r12567.patch: removed. +- ruby-1.8.6-CVE-2007-5162.patch: security fix for Net::HTTP that is + insufficient verification of SSL certificate. + +* Thu Aug 23 2007 Akira TAGOH - 1.8.6.36-4 +- Rebuild + +* Fri Aug 10 2007 Akira TAGOH +- Update License tag. + +* Mon Jun 25 2007 Akira TAGOH - 1.8.6.36-3 +- ruby-r12567.patch: backport patch from upstream svn to get rid of + the unnecessary declarations. (#245446) + +* Wed Jun 20 2007 Akira TAGOH - 1.8.6.36-2 +- New upstream release. + - Fix Etc::getgrgid to get the correct gid as requested. (#236647) + +* Wed Mar 28 2007 Akira TAGOH - 1.8.6-2 +- Fix search path breakage. (#234029) + +* Thu Mar 15 2007 Akira TAGOH - 1.8.6-1 +- New upstream release. +- clean up a spec file. + +* Tue Feb 13 2007 Akira TAGOH - 1.8.5.12-2 +- Rebuild + +* Mon Feb 5 2007 Akira TAGOH - 1.8.5.12-1 +- New upstream release. + +* Mon Dec 11 2006 Akira TAGOH - 1.8.5.2-1 +- security fix release. + +* Fri Oct 27 2006 Akira TAGOH - 1.8.5-4 +- security fix release. +- ruby-1.8.5-cgi-CVE-2006-5467.patch: fix a CGI multipart parsing bug that + causes the denial of service. (#212396) + +* Sun Oct 01 2006 Jesse Keating - 1.8.5-3 +- rebuilt for unwind info generation, broken in gcc-4.1.1-21 + +* Tue Sep 26 2006 Akira TAGOH - 1.8.5-2 +- fixed rbconfig.rb to refer to DESTDIR for sitearchdir. (#207311) + +* Mon Aug 28 2006 Akira TAGOH - 1.8.5-1 +- New upstream release. +- removed the unnecessary patches: + - ruby-1.8.4-no-eaccess.patch + - ruby-1.8.4-64bit-pack.patch + - ruby-1.8.4-fix-insecure-dir-operation.patch + - ruby-1.8.4-fix-insecure-regexp-modification.patch + - ruby-1.8.4-fix-alias-safe-level.patch +- build with --enable-pthread except on ppc. +- ruby-1.8.5-hash-memory-leak.patch: backported from CVS to fix a memory leak + on Hash. [ruby-talk:211233] + +* Mon Aug 7 2006 Akira TAGOH - 1.8.4-12 +- owns sitearchdir. (#201208) + +* Thu Jul 20 2006 Akira TAGOH - 1.8.4-11 +- security fixes [CVE-2006-3694] + - ruby-1.8.4-fix-insecure-dir-operation.patch: + - ruby-1.8.4-fix-insecure-regexp-modification.patch: fixed the insecure + operations in the certain safe-level restrictions. (#199538) + - ruby-1.8.4-fix-alias-safe-level.patch: fixed to not bypass the certain + safe-level restrictions. (#199543) + +* Wed Jul 12 2006 Jesse Keating - 1.8.4-10.fc6.1 +- rebuild + +* Mon Jun 19 2006 Akira TAGOH - 1.8.4-10 +- fixed the wrong file list again. moved tcltk library into ruby-tcltk. + (#195872) + +* Thu Jun 8 2006 Akira TAGOH - 1.8.4-8 +- ruby-deprecated-sitelib-search-path.patch: correct the order of search path. + +* Wed Jun 7 2006 Akira TAGOH - 1.8.4-7 +- exclude ppc64 to make ruby-mode package. right now emacs.ppc64 isn't provided + and buildsys became much stricter. +- ruby-deprecated-sitelib-search-path.patch: applied to add more search path + for backward compatiblity. +- added byacc to BuildReq. (#194161) + +* Wed May 17 2006 Akira TAGOH - 1.8.4-6 +- ruby-deprecated-search-path.patch: added the deprecated installation paths + to the search path for the backward compatibility. +- added a Provides: ruby(abi) to ruby-libs. +- ruby-1.8.4-64bit-pack.patch: backport patch from upstream to fix unpack("l") + not working on 64bit arch and integer overflow on template "w". (#189350) +- updated License tag to be more comfortable, and with a pointer to get more + details, like Python package does. (#179933) +- clean up. + +* Wed Apr 19 2006 Akira TAGOH +- ruby-rubyprefix.patch: moved all arch-independent modules under /usr/lib/ruby + and keep arch-dependent modules under /usr/lib64/ruby for 64bit archs. + so 'rubylibdir', 'sitelibdir' and 'sitedir' in Config::CONFIG points to + the kind of /usr/lib/ruby now. (#184199) + +* Mon Apr 17 2006 Akira TAGOH - 1.8.4-4 +- correct sitelibdir. (#184198) + +* Fri Feb 10 2006 Jesse Keating - 1.8.4-3.2 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 1.8.4-3.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Mon Feb 6 2006 Akira TAGOH - 1.8.4-3 +- ruby-1.8.4-no-eaccess.patch: backported from ruby CVS to avoid conflict + between newer glibc. (#179835) + +* Wed Jan 4 2006 Akira TAGOH - 1.8.4-2 +- ruby-tcltk-multilib.patch: fixed a typo. + +* Tue Dec 27 2005 Akira TAGOH - 1.8.4-1 +- New upstream release. + - fixed a missing return statement. (#140833) + - fixed an use of uninitialized variable. (#144890) + +* Fri Dec 16 2005 Akira TAGOH - 1.8.4-0.4.preview2 +- updates to 1.8.4-preview2. +- renamed the packages to ruby-* (#175765) + - irb -> ruby-irb + - rdoc -> ruby-rdoc + - ri -> ruby-ri +- added tcl-devel and tk-devel into BuildRequires. + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Thu Nov 10 2005 Akira TAGOH - 1.8.4-0.3.preview1 +- rebuilt against the latest openssl. + +* Tue Nov 1 2005 Akira TAGOH - 1.8.4-0.2.preview1 +- build-deps libX11-devel instead of xorg-x11-devel. + +* Mon Oct 31 2005 Akira TAGOH - 1.8.4-0.1.preview1 +- New upstream release. +- ruby-1.8.2-strscan-memset.patch: removed because it's no longer needed. + +* Tue Oct 4 2005 Akira TAGOH - 1.8.3-4 +- moved the documents from ruby-libs to ruby-docs, which contains the arch + specific thing and to be multilib support. (#168826) + +* Mon Oct 3 2005 Akira TAGOH - 1.8.3-3 +- fixed the wrong file list. the external library for tcl/tk was included + in ruby-libs unexpectedly. + +* Mon Sep 26 2005 Akira TAGOH - 1.8.3-2 +- ruby-multilib.patch: added another chunk for multilib. (#169127) + +* Wed Sep 21 2005 Akira TAGOH - 1.8.3-1 +- New upstream release. +- Build-Requires xorg-x11-devel instead of XFree86-devel. +- ruby-multilib.patch: applied for only 64-bit archs. +- ruby-1.8.2-xmlrpc-CAN-2005-1992.patch: removed. it has already been in upstream. + +* Tue Jun 21 2005 Akira TAGOH - 1.8.2-9 +- ruby-1.8.2-xmlrpc-CAN-2005-1992.patch: fixed the arbitrary command execution + on XMLRPC server. (#161096) + +* Thu Jun 16 2005 Akira TAGOH - 1.8.2-8 +- ruby-1.8.2-tcltk-multilib.patch: applied to get tcltklib.so built. (#160194) + +* Thu Apr 7 2005 Akira TAGOH - 1.8.2-7 +- ruby-1.8.2-deadcode.patch: removed the dead code from the source. (#146108) +- make sure that all documentation files in ruby-docs are the world- + readable. (#147279) + +* Tue Mar 22 2005 Akira TAGOH - 1.8.2-6 +- ruby-1.8.2-strscan-memset.patch: fixed an wrong usage of memset(3). + +* Tue Mar 15 2005 Akira TAGOH - 1.8.2-5 +- rebuilt + +* Tue Jan 25 2005 Akira TAGOH - 1.8.2-4 +- fixed the wrong generation of file manifest. (#146055) +- spec file clean up. + +* Mon Jan 24 2005 Akira TAGOH - 1.8.2-3 +- separated out to rdoc package. +- make the dependency of irb for rdoc. (#144708) + +* Wed Jan 12 2005 Tim Waugh - 1.8.2-2 +- Rebuilt for new readline. + +* Wed Jan 5 2005 Akira TAGOH - 1.8.2-1 +- New upstream release. +- ruby-1.8.1-ia64-stack-limit.patch: removed - it's no longer needed. +- ruby-1.8.1-cgi_session_perms.patch: likewise. +- ruby-1.8.1-cgi-dos.patch: likewise. +- generated Ruby interactive documentation - senarated package. + it's now provided as ri package. (#141806) + +* Thu Nov 11 2004 Jeff Johnson 1.8.1-10 +- rebuild against db-4.3.21. + +* Wed Nov 10 2004 Akira TAGOH - 1.8.1-9 +- ruby-1.8.1-cgi-dos.patch: security fix [CAN-2004-0983] +- ruby-1.8.1-cgi_session_perms.patch: security fix [CAN-2004-0755] + +* Fri Oct 29 2004 Akira TAGOH - 1.8.1-8 +- added openssl-devel and db4-devel into BuildRequires (#137479) + +* Wed Oct 6 2004 Akira TAGOH - 1.8.1-7 +- require emacs-common instead of emacs. + +* Wed Jun 23 2004 Akira TAGOH 1.8.1-4 +- updated the documentation. + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Tue Mar 02 2004 Elliot Lee +- rebuilt + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Wed Feb 04 2004 Akira TAGOH 1.8.1-1 +- New upstream release. +- don't use any optimization for ia64 to avoid the build failure. +- ruby-1.8.1-ia64-stack-limit.patch: applied to fix SystemStackError when the optimization is disabled. + +* Sat Dec 13 2003 Jeff Johnson 1.8.0-3 +- rebuild against db-4.2.52. + +* Thu Sep 25 2003 Jeff Johnson 1.8.0-2 +- rebuild against db-4.2.42. + +* Tue Aug 5 2003 Akira TAGOH 1.8.0-1 +- New upstream release. + +* Thu Jul 24 2003 Akira TAGOH 1.6.8-9.1 +- rebuilt + +* Thu Jul 24 2003 Akira TAGOH 1.6.8-9 +- ruby-1.6.8-castnode.patch: handling the nodes with correct cast. + use this patch now instead of ruby-1.6.8-fix-x86_64.patch. + +* Fri Jul 04 2003 Akira TAGOH 1.6.8-8 +- rebuilt + +* Fri Jul 04 2003 Akira TAGOH 1.6.8-7 +- fix the gcc warnings. (#82192) +- ruby-1.6.8-fix-x86_64.patch: correct a patch. + NOTE: DON'T USE THIS PATCH FOR BIG ENDIAN ARCHITECTURE. +- ruby-1.6.7-long2int.patch: removed. + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Fri Feb 7 2003 Jens Petersen - 1.6.8-5 +- rebuild against ucs4 tcltk + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Wed Jan 22 2003 Akira TAGOH 1.6.8-3 +- ruby-1.6.8-multilib.patch: applied to fix the search path issue on x86_64 + +* Tue Jan 21 2003 Akira TAGOH 1.6.8-2 +- ruby-1.6.8-require.patch: applied to fix the search bug in require. +- don't apply long2int patch to s390 and s390x. it doesn't work. + +* Wed Jan 15 2003 Akira TAGOH 1.6.8-1 +- New upstream release. +- removed some patches. it's no longer needed. + - ruby-1.6.7-100.patch + - ruby-1.6.7-101.patch + - ruby-1.6.7-102.patch + - ruby-1.6.7-103.patch + - 801_extmk.rb-shellwords.patch + - 801_mkmf.rb-shellwords.patch + - 804_parse.y-new-bison.patch + - 805_uri-bugfix.patch + - ruby-1.6.6-900_XXX_strtod.patch + - ruby-1.6.7-sux0rs.patch + - ruby-1.6.7-libobj.patch + +* Wed Jan 15 2003 Jens Petersen 1.6.7-14 +- rebuild to update tcltk deps + +* Mon Dec 16 2002 Elliot Lee 1.6.7-13 +- Remove ExcludeArch: x86_64 +- Fix x86_64 ruby with long2int.patch (ruby was assuming that sizeof(long) + == sizeof(int). The patch does not fix the source of the problem, just + makes it a non-issue.) +- _smp_mflags + +* Tue Dec 10 2002 Tim Powers 1.6.7-12 +- rebuild to fix broken tcltk deps + +* Tue Oct 22 2002 Akira TAGOH 1.6.7-11 +- use %%configure macro instead of configure script. +- use the latest config.{sub,guess}. +- get archname from rbconfig.rb for %%dir +- applied some patches from Debian: + - 801_extmk.rb-shellwords.patch: use Shellwords + - 801_mkmf.rb-shellwords.patch: mkmf.rb creates bad Makefile. the Makefile + links libruby.a to the target. + - 803_sample-fix-shbang.patch: all sample codes should be + s|/usr/local/bin|/usr/bin|g + - 804_parse.y-new-bison.patch: fix syntax warning. + - 805_uri-bugfix.patch: uri.rb could not handle correctly broken mailto-uri. +- add ExcludeArch x86_64 temporarily to fix Bug#74581. Right now ruby can't be + built on x86_64. + +* Tue Aug 27 2002 Akira TAGOH 1.6.7-10 +- moved sitedir to /usr/lib/ruby/site_ruby again according as our perl and + python. +- ruby-1.6.7-resolv1.patch, ruby-1.6.7-resolv2.patch: applied to fix 'Too many + open files - "/etc/resolv.conf"' issue. (Bug#64830) + +* Thu Jul 18 2002 Akira TAGOH 1.6.7-9 +- add the owned directory. + +* Fri Jul 12 2002 Akira TAGOH 1.6.7-8 +- fix typo. + +* Thu Jul 04 2002 Akira TAGOH 1.6.7-7 +- removed the ruby-mode-xemacs because it's merged to the xemacs sumo. + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Wed Jun 19 2002 Akira TAGOH 1.6.7-5 +- fix the stripped binary. +- use the appropriate macros. + +* Sun May 26 2002 Tim Powers +- automated rebuild + +* Thu May 23 2002 Akira TAGOH 1.6.7-3 +- ruby-1.6.7-libobj.patch: applied to fix autoconf2.53 error. + +* Mon Mar 18 2002 Akira TAGOH 1.6.7-2 +- ruby-man-1.4.6-jp.tar.bz2: removed. +- ruby-refm-rdp-1.4.7-ja-html.tar.bz2: uses it instead of. +- ruby-1.6.7-500-marshal-proc.patch, ruby-1.6.7-501-class-var.patch: + removed. +- ruby-1.6.7-100.patch: applied a bug fix patch. + (ruby-dev#16274: patch for 'wm state') + (PR#206ja: SEGV handle EXIT) +- ruby-1.6.7-101.patch: applied a bug fix patch. + (ruby-list#34313: singleton should not be Marshal.dump'ed) + (ruby-dev#16411: block local var) +- ruby-1.6.7-102.patch: applied a bug fix patch. + (handling multibyte chars is partially broken) +- ruby-1.6.7-103.patch: applied a bug fix patch. + (ruby-dev#16462: preserve reference for GC, but link should be cut) + +* Fri Mar 8 2002 Akira TAGOH 1.6.7-1 +- New upstream release. +- ruby-1.6.6-100.patch, ruby-1.6.6-501-ruby-mode.patch: + removed. these patches no longer should be needed. +- ruby-1.6.7-500-marshal-proc.patch: applied a fix patch. + (ruby-dev#16178: Marshal::dump should call Proc#call.) +- ruby-1.6.7-501-class-var.patch: applied a fix patch. + (ruby-talk#35157: class vars broken in 1.6.7) + +* Wed Feb 27 2002 Akira TAGOH 1.6.6-5 +- Disable alpha because nothing is xemacs for alpha now. + +* Tue Feb 5 2002 Akira TAGOH 1.6.6-3 +- Fixed the duplicate files. + +* Tue Feb 5 2002 Akira TAGOH 1.6.6-2 +- Fixed the missing %%defattr + +* Fri Feb 1 2002 Akira TAGOH 1.6.6-1 +- New upstream release. +- Applied bug fix patches: + - ruby-1.6.6-501-ruby-mode.patch: ruby-talk#30479: disables font-lock + coloring. + - ruby-1.6.6-100.patch: ruby-talk#30203: Ruby 1.6.6 bug and fix + ruby-list#33047: regex bug + PR#230: problem with -d in 1.6.6 +- Added ruby-mode and ruby-mode-xemacs packages. +- Ruby works fine for ia64. so re-enable to build with ia64. + (probably it should be worked for alpha) + +* Wed Jan 09 2002 Tim Powers +- automated rebuild + +* Thu Jul 19 2001 Bernhard Rosenkraenzer 1.6.4-2 +- Remove Japanese description and summaries; they belong in specspo and + break rpm +- Clean up specfile +- Mark language specific files (README.jp) as such +- bzip2 sources +- rename the libruby package to ruby-libs for consistency +- Exclude ia64 (doesn't build - the code doesn't seem to be 64-bit clean + [has been excluded on alpha forever]) + +* Tue Jul 17 2001 Akira TAGOH 1.6.4-1 +- rebuild for Red Hat 7.2 + +* Mon Jun 04 2001 akira yamada +- upgrade to nwe upstream version 1.6.4. + +* Mon Apr 02 2001 akira yamada +- applied patch: + - fixed method cache bug. etc. (Patch103, Patch104) + +* Tue Mar 27 2001 akira yamada +- applied patch: + - fixed marshal for bignum bug. + - fixed scope of constant variables bug. + +* Tue Mar 20 2001 akira yamada +- upgraded to new upstream version 1.6.3. + +* Fri Feb 09 2001 akira yamada +- fixed bad group for libruby. +- Applied patch: upgraded to cvs version (2001-02-08): + fixed minor bugs. + +* Thu Jan 18 2001 akira yamada +- Applied patch: upgraded to cvs version (2001-01-15): + fixed minor bugs(e.g. ruby makes extention librares too large...). + +* Wed Jan 10 2001 akira yamada +- Applied patch: upgraded to cvs version (2001-01-09): + fixed minor bugs. + +* Sat Dec 30 2000 akira yamada +- Applied bug fix patch. + +* Mon Dec 25 2000 akira yamada +- Updated to new upstream version 1.6.2. + +* Fri Dec 22 2000 akira yamada +- Removed ruby_cvs.2000122019.patch, added ruby_cvs.2000122215.patch + (upgraded ruby to latest cvs version, 1.6.2-preview4). + +* Wed Dec 20 2000 akira yamada +- Removed ruby_cvs.2000121413.patch, added ruby_cvs.2000122019.patch + (upgraded ruby to latest cvs version). +- new package: libruby + +* Thu Dec 14 2000 akira yamada +- Removed ruby_cvs.2000101901.patch, added ruby_cvs.2000121413.patch + (upgraded ruby to latest cvs version). +- Removed ruby-dev.11262.patch, ruby-dev.11265.patch, + and ruby-dev.11268.patch (included into above patch). + +* Sun Nov 12 2000 MACHINO, Satoshi 1.6.1-0vl9 +- build on gcc-2.95.3 + +* Thu Oct 19 2000 akira yamada +- Added ruby-dev.11268.patch. + +* Thu Oct 19 2000 akira yamada +- Removed ruby_cvs.2000101117.patch and added ruby_cvs.2000101901.patch + (upgraded ruby to latest cvs version). +- Added ruby-dev.11262.patch. +- Added ruby-dev.11265.patch. + +* Wed Oct 11 2000 akira yamada +- Removed ruby_cvs.2000100313.patch and added ruby_cvs.2000101117.patch + (upgraded ruby to latest cvs version). + +* Mon Oct 09 2000 akira yamada +- Removed ruby_cvs.2000100313.patch and added ruby_cvs.2000100313.patch + (upgraded ruby to latest cvs version). + +* Tue Oct 03 2000 akira yamada +- Removed ruby_cvs.2000100218.patch and added ruby_cvs.2000100313.patch + (upgraded ruby to latest cvs version). + +* Mon Oct 02 2000 akira yamada +- Removed ruby_cvs.2000092718.patch and added ruby_cvs.2000100218.patch + (upgraded ruby to latest cvs version). + +* Wed Sep 27 2000 akira yamada +- Updated to upstream version 1.6.1. +- Removed ruby_cvs.2000082901.patch and added ruby_cvs.2000092718.patch + (upgraded ruby to latest cvs version). + +* Tue Aug 29 2000 akira yamada +- Updated to version 1.4.6. +- removed ruby-dev.10123.patch(included into ruby-1.4.6). +- Added ruby_cvs.2000082901.patch(upgraded ruby to latest cvs version). + +* Tue Jun 27 2000 akira yamada +- Updated manuals to version 1.4.5. + +* Sun Jun 25 2000 akira yamada +- Added ruby-dev.10123.patch. + +* Sat Jun 24 2000 akira yamada +- Updated to version 1.4.5. +- Removed ruby_cvs.2000062401.patch(included into ruby-1.4.5). + +* Thu Jun 22 2000 akira yamada +- Updated to version 1.4.4(06/22/2000 CVS). +- Removed ruby-dev.10054.patch(included into ruby_cvs.patch). + +* Thu Jun 22 2000 akira yamada +- Renamed to ruby_cvs20000620.patch from ruby_cvs.patch. + +* Tue Jun 20 2000 akira yamada +- Updated to version 1.4.4(06/20/2000 CVS). +- Removed ruby-list.23190.patch(included into ruby_cvs.patch). +- Added ruby-dev.10054.patch. + +* Thu Jun 15 2000 akira yamada +- Updated to version 1.4.4(06/12/2000 CVS). +- Added manuals and FAQs. +- Split into ruby, ruby-devel, ruby-tcltk, ruby-docs, irb. + +* Tue Jun 13 2000 Mitsuo Hamada +- Updated to version 1.4.4 + +* Wed Dec 08 1999 Atsushi Yamagata +- Updated to version 1.4.3 + +* Mon Sep 20 1999 Atsushi Yamagata +- Updated to version 1.4.2 (Sep 18) + +* Fri Sep 17 1999 Atsushi Yamagata +- Updated to version 1.4.2 + +* Tue Aug 17 1999 Atsushi Yamagata +- Updated to version 1.4.0 + +* Fri Jul 23 1999 Atsushi Yamagata +- 2nd release +- Updated to version 1.2.6(15 Jul 1999) +- striped %%{prefix}/bin/ruby + +* Mon Jun 28 1999 Atsushi Yamagata +- Updated to version 1.2.6(21 Jun 1999) + +* Wed Apr 14 1999 Atsushi Yamagata +- Updated to version 1.2.5 + +* Fri Apr 09 1999 Atsushi Yamagata +- Updated to version 1.2.4 + +* Fri Dec 25 1998 Toru Hoshina +- Version up to 1.2 stable. + +* Fri Nov 27 1998 Toru Hoshina +- Version up to 1.1c9. + +* Thu Nov 19 1998 Toru Hoshina +- Version up to 1.1c8, however it appear short life :-P + +* Fri Nov 13 1998 Toru Hoshina +- Version up. + +* Tue Sep 22 1998 Toru Hoshina +- To make a libruby.so. + +* Mon Sep 21 1998 Toru Hoshina +- Modified SPEC in order to install libruby.a so that it should be used by + another ruby entention. +- 2nd release. + +* Mon Mar 9 1998 Shoichi OZAWA +- Added a powerPC arch part. Thanks, MURATA Nobuhiro diff --git a/rubygem-bundler-2.1.0-dont-use-insecure-temporary-directory-as-home-directory.patch b/rubygem-bundler-2.1.0-dont-use-insecure-temporary-directory-as-home-directory.patch new file mode 100644 index 0000000..794a65d --- /dev/null +++ b/rubygem-bundler-2.1.0-dont-use-insecure-temporary-directory-as-home-directory.patch @@ -0,0 +1,157 @@ +From 65cfebb041c454c246aaf32a177b0243915a9998 Mon Sep 17 00:00:00 2001 +From: fatkodima +Date: Fri, 1 Nov 2019 23:06:10 +0200 +Subject: [PATCH] Don't use insecure temporary directory as home directory + +--- + lib/bundler.rb | 29 +++++++++++--------------- + spec/bundler/bundler_spec.rb | 38 +++++++++-------------------------- + spec/bundler/settings_spec.rb | 2 +- + 3 files changed, 22 insertions(+), 47 deletions(-) + +diff --git a/lib/bundler.rb b/lib/bundler.rb +index 2ada6fe7891..b184f7e69c6 100644 +--- a/lib/bundler.rb ++++ b/lib/bundler.rb +@@ -170,8 +170,7 @@ def user_home + end + + if warning +- Kernel.send(:require, "etc") +- user_home = tmp_home_path(Etc.getlogin, warning) ++ user_home = tmp_home_path(warning) + Bundler.ui.warn "#{warning}\nBundler will use `#{user_home}' as your home directory temporarily.\n" + user_home + else +@@ -180,21 +180,6 @@ def user_home + end + end + +- def tmp_home_path(login, warning) +- login ||= "unknown" +- Kernel.send(:require, "tmpdir") +- path = Pathname.new(Dir.tmpdir).join("bundler", "home") +- SharedHelpers.filesystem_access(path) do |tmp_home_path| +- unless tmp_home_path.exist? +- tmp_home_path.mkpath +- tmp_home_path.chmod(0o777) +- end +- tmp_home_path.join(login).tap(&:mkpath) +- end +- rescue RuntimeError => e +- raise e.exception("#{warning}\nBundler also failed to create a temporary home directory at `#{path}':\n#{e}") +- end +- + def user_bundle_path(dir = "home") + env_var, fallback = case dir + when "home" +@@ -555,6 +555,17 @@ def configure_gem_home + Bundler.rubygems.clear_paths + end + ++ def tmp_home_path(warning) ++ Kernel.send(:require, "tmpdir") ++ SharedHelpers.filesystem_access(Dir.tmpdir) do ++ path = Bundler.tmp ++ at_exit { Bundler.rm_rf(path) } ++ path ++ end ++ rescue RuntimeError => e ++ raise e.exception("#{warning}\nBundler also failed to create a temporary home directory':\n#{e}") ++ end ++ + # @param env [Hash] + def with_env(env) + backup = ENV.to_hash +diff --git a/spec/bundler/bundler/bundler_spec.rb b/spec/bundler/bundler/bundler_spec.rb +index 74cf7ae05d3..247838600bf 100644 +--- a/spec/bundler/bundler/bundler_spec.rb ++++ b/spec/bundler/bundler/bundler_spec.rb +@@ -233,16 +233,13 @@ + path = "/home/oggy" + allow(Bundler.rubygems).to receive(:user_home).and_return(path) + allow(File).to receive(:directory?).with(path).and_return false +- allow(Etc).to receive(:getlogin).and_return("USER") +- allow(Dir).to receive(:tmpdir).and_return("/TMP") +- allow(FileTest).to receive(:exist?).with("/TMP/bundler/home").and_return(true) +- expect(FileUtils).to receive(:mkpath).with("/TMP/bundler/home/USER") ++ allow(Bundler).to receive(:tmp).and_return(Pathname.new("/tmp/trulyrandom")) + message = < +Date: Tue, 22 Jan 2019 09:37:23 +0900 +Subject: [PATCH] Avoid rdoc hook when it's failed to load rdoc library. + + Fixed #2483 +--- + lib/rubygems/rdoc.rb | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/rubygems/rdoc.rb b/lib/rubygems/rdoc.rb +index dfaf7c55bf..4e16fbb86f 100644 +--- a/lib/rubygems/rdoc.rb ++++ b/lib/rubygems/rdoc.rb +@@ -18,7 +18,7 @@ + module Gem + RDoc = ::RDoc::RubygemsHook + end ++ ++ Gem.done_installing(&Gem::RDoc.method(:generation_hook)) + rescue LoadError + end +- +-Gem.done_installing(&Gem::RDoc.method(:generation_hook)) diff --git a/rubygems-3.0.3-Restore-gem-build-behavior-and-introdcue-the-C-flag-to-gem-build.patch b/rubygems-3.0.3-Restore-gem-build-behavior-and-introdcue-the-C-flag-to-gem-build.patch new file mode 100644 index 0000000..fa4f0c3 --- /dev/null +++ b/rubygems-3.0.3-Restore-gem-build-behavior-and-introdcue-the-C-flag-to-gem-build.patch @@ -0,0 +1,88 @@ +From f4061357d812e9033f07ae3f8f44c4e26839f1e5 Mon Sep 17 00:00:00 2001 +From: bronzdoc +Date: Mon, 14 Jan 2019 09:46:29 -0600 +Subject: [PATCH] Restore gem build behavior and introdcue the "-C" flag to gem + build + +--- + lib/rubygems/commands/build_command.rb | 41 +++++++++++++------ + .../test_gem_commands_build_command.rb | 1 + + 2 files changed, 29 insertions(+), 13 deletions(-) + +diff --git a/lib/rubygems/commands/build_command.rb b/lib/rubygems/commands/build_command.rb +index e59471e976..761b80ee94 100644 +--- a/lib/rubygems/commands/build_command.rb ++++ b/lib/rubygems/commands/build_command.rb +@@ -18,6 +18,10 @@ def initialize + add_option '-o', '--output FILE', 'output gem with the given filename' do |value, options| + options[:output] = value + end ++ ++ add_option '-C PATH', '', 'Run as if gem build was started in instead of the current working directory.' do |value, options| ++ options[:build_path] = value ++ end + end + + def arguments # :nodoc: +@@ -60,25 +64,36 @@ def execute + end + + if File.exist? gemspec +- Dir.chdir(File.dirname(gemspec)) do +- spec = Gem::Specification.load File.basename(gemspec) +- +- if spec +- Gem::Package.build( +- spec, +- options[:force], +- options[:strict], +- options[:output] +- ) +- else +- alert_error "Error loading gemspec. Aborting." +- terminate_interaction 1 ++ spec = Gem::Specification.load(gemspec) ++ ++ if options[:build_path] ++ Dir.chdir(File.dirname(gemspec)) do ++ spec = Gem::Specification.load File.basename(gemspec) ++ build_package(spec) + end ++ else ++ build_package(spec) + end ++ + else + alert_error "Gemspec file not found: #{gemspec}" + terminate_interaction 1 + end + end + ++ private ++ ++ def build_package(spec) ++ if spec ++ Gem::Package.build( ++ spec, ++ options[:force], ++ options[:strict], ++ options[:output] ++ ) ++ else ++ alert_error "Error loading gemspec. Aborting." ++ terminate_interaction 1 ++ end ++ end + end +diff --git a/test/rubygems/test_gem_commands_build_command.rb b/test/rubygems/test_gem_commands_build_command.rb +index ac82a408c7..02d1b98e8f 100644 +--- a/test/rubygems/test_gem_commands_build_command.rb ++++ b/test/rubygems/test_gem_commands_build_command.rb +@@ -207,6 +207,7 @@ def test_execute_outside_dir + gs.write @gem.to_ruby + end + ++ @cmd.options[:build_path] = gemspec_dir + @cmd.options[:args] = [gemspec_file] + + use_ui @ui do diff --git a/rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch b/rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch new file mode 100644 index 0000000..433d03e --- /dev/null +++ b/rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch @@ -0,0 +1,44 @@ +From bb0f57aeb4de36a3b2b8b8cb01d25b32af0357d3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +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 + diff --git a/rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch b/rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch new file mode 100644 index 0000000..d5a0673 --- /dev/null +++ b/rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch @@ -0,0 +1,261 @@ +From e80e7a3d0b3d72f7af7286b935702b3fab117008 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +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?= +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?= +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?= +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?= +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 + diff --git a/rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch b/rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch new file mode 100644 index 0000000..b405b5f --- /dev/null +++ b/rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch @@ -0,0 +1,105 @@ +From 558128594de16add5b453833fd5b043a24c1b7f5 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +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 +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 +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) diff --git a/rubygems.attr b/rubygems.attr new file mode 100644 index 0000000..5793bf7 --- /dev/null +++ b/rubygems.attr @@ -0,0 +1,6 @@ +%__rubygems_requires %{_rpmconfigdir}/rubygems.req +%__rubygems_provides %{_rpmconfigdir}/rubygems.prov +%__rubygems_conflicts %{_rpmconfigdir}/rubygems.con +# In non-gem packages, the %%{gem_name} macro is not available and the macro +# stays unexpanded which leads to "invalid regex" error (rhbz#1154067). +%__rubygems_path ^%{?gem_name:%{gem_spec}}%{!?gem_name:this_should_never_match_anything}$ diff --git a/rubygems.con b/rubygems.con new file mode 100644 index 0000000..1a99ed0 --- /dev/null +++ b/rubygems.con @@ -0,0 +1,52 @@ +#!/usr/bin/ruby + +require 'rubygems/package' + +module RubyGemsReq + module Helpers + # Keep only '!=' requirements. + def self.conflicts(requirements) + conflicts = requirements.select {|r| r.first == '!='} + end + + # Converts Gem::Requirement into array of requirements strings compatible + # with RPM .spec file. + def self.requirement_versions_to_rpm(requirement) + self.conflicts(requirement.requirements).map do |op, version| + version == Gem::Version.new(0) ? "" : "= #{version}" + end + end + end + + # Report conflicting gem dependencies including their version. + def self.gem_depenencies(specification) + specification.runtime_dependencies.each do |dependency| + conflict_strings = Helpers::requirement_versions_to_rpm(dependency.requirement).map do |requirement| + requirement_string = "rubygem(#{dependency.name}) #{requirement}" + end + if conflict_strings.length > 0 + conflict_string = conflict_strings.join(' with ') + conflict_string.prepend('(').concat(')') if conflict_strings.length > 1 + puts conflict_string + end + end + end + + # Reports all conflicts specified by all provided .gemspec files. + def self.conflicts + while filename = gets + filename.strip! + begin + specification = Gem::Specification.load filename + + gem_depenencies(specification) + rescue => e + # Ignore all errors. + end + end + end +end + +if __FILE__ == $0 + RubyGemsReq::conflicts +end diff --git a/rubygems.prov b/rubygems.prov new file mode 100644 index 0000000..f23ec3f --- /dev/null +++ b/rubygems.prov @@ -0,0 +1,36 @@ +#!/usr/bin/ruby + +require 'rubygems/package' + +module RubyGemsProv + module Helpers + # If there is some prelease version files, such as rc1 (i.e. non-numeric + # field), prepend this field by tilde instead of dot. + def self.normalize_prerelease(version) + if version.prerelease? + prerelease = version.version.sub /^#{version.release}\./, '' + "#{version.release}~#{prerelease}" + else + version.release + end + end + end + + # Reports all functionality gem provides. + def self.provides + while filename = gets + filename.strip! + begin + specification = Gem::Specification.load filename + + puts "rubygem(#{specification.name}) = #{Helpers::normalize_prerelease(specification.version)}" + rescue => e + # Ignore all errors. + end + end + end +end + +if __FILE__ == $0 + RubyGemsProv::provides +end diff --git a/rubygems.req b/rubygems.req new file mode 100644 index 0000000..38e4a9c --- /dev/null +++ b/rubygems.req @@ -0,0 +1,88 @@ +#!/usr/bin/ruby + +require 'rubygems/package' + +module RubyGemsReq + module Helpers + # Expands '~>' and '!=' gem requirements. + def self.expand_requirement(requirements) + requirements.inject([]) do |output, r| + output.concat case r.first + when '~>' + expand_pessimistic_requirement(r) + when '!=' + # If there is only the conflict requirement, we still need to depend + # on the specified gem. + if requirements.size == 1 + Gem::Requirement.default.requirements + else + [] + end + else + [r] + end + end.reject {|r| r.empty? } + end + + # Expands the pessimistic version operator '~>' into equivalent '>=' and + # '<' pair. + def self.expand_pessimistic_requirement(requirement) + next_version = Gem::Version.create(requirement.last).bump + return ['>=', requirement.last], ['<', next_version] + end + + # Converts Gem::Requirement into array of requirements strings compatible + # 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}" + 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) + 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) + end + end + + # Reports all requirements specified by all provided .gemspec files. + def self.requires + while filename = gets + filename.strip! + begin + specification = Gem::Specification.load filename + + rubygems_dependency(specification) + gem_depenencies(specification) + rescue => e + # Ignore all errors. + end + end + end +end + +if __FILE__ == $0 + RubyGemsReq::requires +end diff --git a/sources b/sources new file mode 100644 index 0000000..5bb9ec3 --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA1 (ruby-2.6.10.tar.xz) = e91de95735d0af32238903c7c58d2b660433e0cc diff --git a/test_abrt.rb b/test_abrt.rb new file mode 100644 index 0000000..6d110ba --- /dev/null +++ b/test_abrt.rb @@ -0,0 +1,7 @@ +if !!$LOADED_FEATURES.detect { |f| f =~ /abrt\.rb/ } + exit true +else + puts 'ERROR: ABRT hook was not loaded.' + + exit false +end diff --git a/test_systemtap.rb b/test_systemtap.rb new file mode 100644 index 0000000..5784e2d --- /dev/null +++ b/test_systemtap.rb @@ -0,0 +1,65 @@ +require 'set' + +LIBRUBY_SO = 'libruby.so' +PROBES_D = 'probes.d' + +# These probes are excluded by VM_COLLECT_USAGE_DETAILS ifdef. +EXCLUDE_PROBES = Set.new %w(insn insn__operand) + +## Detect SystemTap section headers presence + +stap_headers = [ + '\.stapsdt\.base', + '\.note\.stapsdt' +] + +header_regexp = %r{ (#{stap_headers.join('|')}) } + +section_headers = `readelf -S "#{LIBRUBY_SO}"` +detected_stap_headers = section_headers.scan(header_regexp).flatten + +# Assume there are both headers until this is proven wrong ;) +unless detected_stap_headers.size == 2 + puts 'ERROR: SystemTap (DTrace) headers were not detected in resulting library.' + exit false +end + +## Find if every declared probe is propagated to resulting library + +# Colect probes specified in probes.d file. +probes_declared = [] + +File.open(PROBES_D) do |file| + file.each_line do |line| + if probe = line[/probe (\S+)\(.*\);/, 1] + probes_declared << probe + end + end +end + +probes_declared = Set.new probes_declared + +unless EXCLUDE_PROBES.subset? probes_declared + puts 'ERROR: Change in SystemTap (DTrace) probes definition file detected.' + exit false +end + +probes_declared -= EXCLUDE_PROBES + +# Detect probes in resulting library. +get_probes_detected = %r{ +^\s*Provider:\s+ruby,\s+Name:\s+(\S+),\s+.*$ +} + +probes_detected = `eu-readelf -n "#{LIBRUBY_SO}"` + +probes_detected = Set.new probes_detected.scan(get_probes_detected).flatten + +# Both sets must be equal, otherwise something is wrong. +unless probes_declared == probes_detected + puts 'ERROR: SystemTap (DTrace) probes were not correctly propagated into resulting library.' + puts " Undetected probes: #{(probes_declared - probes_detected).sort.join(', ')}\n", + " Additional detected probes: #{(probes_detected - probes_declared).sort.join(', ')}" + + exit false +end