From 1b641ac57f5a8f196c2cbf62818b5c37ff5ef9e9 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Wed, 5 May 2021 13:30:43 +0200 Subject: [PATCH 001/141] Fix FTBFS due to an incompatible load. The FTBFS has started to happen with rpm-4.16.90-0.git15395.2.fc35. root.log ``` DEBUG util.py:444: error: line 116: Unknown tag: /chroot_tmpdir/srpm_unpacked/SOURCES/macros.ruby ``` As the `%{?load:...}` is undocumented, it is gone. https://github.com/rpm-software-management/rpm/issues/1669 --- ruby.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby.spec b/ruby.spec index 1f5b66c..1b70681 100644 --- a/ruby.spec +++ b/ruby.spec @@ -113,8 +113,8 @@ 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}} +%{load:%{SOURCE4}} +%{load:%{SOURCE5}} # Fix ruby_version abuse. # https://bugs.ruby-lang.org/issues/11002 From fbaee91204d6c968dd3f45eb5e038b0a14e4b518 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Fri, 14 May 2021 17:16:38 +0200 Subject: [PATCH 002/141] ruby.rpmlintrc: Ignore non executable template files for Bundler. The template files do not have to have executable bits. Ignore the following errors. ``` rubygem-bundler.noarch: E: non-executable-script /usr/share/gems/gems/bundler-2.2.15/lib/bundler/templates/Executable 644 /usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> rubygem-bundler.noarch: E: non-executable-script /usr/share/gems/gems/bundler-2.2.15/lib/bundler/templates/Executable.bundler 644 /usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> rubygem-bundler.noarch: E: non-executable-script /usr/share/gems/gems/bundler-2.2.15/lib/bundler/templates/Executable.standalone 644 /usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> rubygem-bundler.noarch: E: non-executable-script /usr/share/gems/gems/bundler-2.2.15/lib/bundler/templates/newgem/bin/console.tt 644 /usr/bin/env ruby rubygem-bundler.noarch: E: non-executable-script /usr/share/gems/gems/bundler-2.2.15/lib/bundler/templates/newgem/bin/setup.tt 644 /usr/bin/env bash rubygem-bundler.noarch: E: non-executable-script /usr/share/gems/gems/bundler-2.2.15/lib/bundler/templates/newgem/exe/newgem.tt 644 /usr/bin/env ruby ``` --- ruby.rpmlintrc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ruby.rpmlintrc b/ruby.rpmlintrc index 823778b..37ba619 100644 --- a/ruby.rpmlintrc +++ b/ruby.rpmlintrc @@ -9,3 +9,6 @@ addFilter(r'^ruby\.(spec|src):\d+: W: unversioned-explicit-provides bundled\(cca 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 ') From 26bc979446231456744eb95d11a8888160797db4 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Wed, 28 Apr 2021 20:53:04 +0200 Subject: [PATCH 003/141] ruby.rpmlintrc: Ignore the non-executable-script errors in bundled gems. The bundled gem files permissions are overridden as 644 by `make install`. Ignore following errors in bundled gems. ``` rubygem-power_assert.noarch: E: non-executable-script /usr/share/gems/gems/power_assert-1.2.0/bin/console 644 /usr/bin/env ruby rubygem-power_assert.noarch: E: non-executable-script /usr/share/gems/gems/power_assert-1.2.0/bin/setup 644 /usr/bin/env bash rubygem-rake.noarch: E: non-executable-script /usr/share/gems/gems/rake-13.0.3/bin/bundle 644 /usr/bin/env ruby rubygem-rake.noarch: E: non-executable-script /usr/share/gems/gems/rake-13.0.3/bin/console 644 /usr/bin/env ruby rubygem-rake.noarch: E: non-executable-script /usr/share/gems/gems/rake-13.0.3/bin/rake 644 /usr/bin/env ruby rubygem-rake.noarch: E: non-executable-script /usr/share/gems/gems/rake-13.0.3/bin/rdoc 644 /usr/bin/env ruby rubygem-rake.noarch: E: non-executable-script /usr/share/gems/gems/rake-13.0.3/bin/rubocop 644 /usr/bin/env ruby rubygem-rake.noarch: E: non-executable-script /usr/share/gems/gems/rake-13.0.3/bin/setup 644 /usr/bin/env bash rubygem-rbs.noarch: E: non-executable-script /usr/share/gems/gems/rbs-1.0.4/bin/annotate-with-rdoc 644 /usr/bin/env ruby rubygem-rbs.noarch: E: non-executable-script /usr/share/gems/gems/rbs-1.0.4/bin/console 644 /usr/bin/env ruby rubygem-rbs.noarch: E: non-executable-script /usr/share/gems/gems/rbs-1.0.4/bin/query-rdoc 644 /usr/bin/env ruby rubygem-rbs.noarch: E: non-executable-script /usr/share/gems/gems/rbs-1.0.4/bin/rbs-prof 644 /usr/bin/env ruby rubygem-rbs.noarch: E: non-executable-script /usr/share/gems/gems/rbs-1.0.4/bin/setup 644 /usr/bin/env bash rubygem-rbs.noarch: E: non-executable-script /usr/share/gems/gems/rbs-1.0.4/bin/sort 644 /usr/bin/env ruby rubygem-rbs.noarch: E: non-executable-script /usr/share/gems/gems/rbs-1.0.4/bin/steep 644 /bin/sh rubygem-rbs.noarch: E: non-executable-script /usr/share/gems/gems/rbs-1.0.4/bin/test_runner.rb 644 /usr/bin/env ruby rubygem-test-unit.noarch: E: non-executable-script /usr/share/gems/gems/test-unit-3.3.7/test/run-test.rb 644 /usr/bin/env ruby ``` --- ruby.rpmlintrc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ruby.rpmlintrc b/ruby.rpmlintrc index 37ba619..e39116f 100644 --- a/ruby.rpmlintrc +++ b/ruby.rpmlintrc @@ -12,3 +12,30 @@ addFilter(r'^ruby\.(spec|src):\d+: W: unversioned-explicit-provides bundled\(cca # 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 ') From 882d68b75c2161208e006b74f1c9bccd2db608e9 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Wed, 28 Apr 2021 20:53:04 +0200 Subject: [PATCH 004/141] ruby.rpmlintrc: Ignore a false positive missing-call-to-chdir-with-chroot error. The `chroot` in the `dir.c` is just used as a Ruby binding `Dir.chroot` for the function. Ignore the following error. ``` ruby-libs.x86_64: E: missing-call-to-chdir-with-chroot /usr/lib64/libruby.so.3.0.1 ``` --- ruby.rpmlintrc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ruby.rpmlintrc b/ruby.rpmlintrc index e39116f..1a67b89 100644 --- a/ruby.rpmlintrc +++ b/ruby.rpmlintrc @@ -39,3 +39,14 @@ addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/ 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/.]+$') From a09dbbec17022249e57af69d5b1aeb12a95c23c6 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Fri, 14 May 2021 18:00:25 +0200 Subject: [PATCH 005/141] ruby.rpmlintrc: Ignore a shared-lib-without-dependency-information error. Nothing referred and no dependency information should be no problem. Ignore the following error. ``` ruby-libs.x86_64: E: shared-lib-without-dependency-information /usr/lib64/ruby/enc/gb2312.so ``` --- ruby.rpmlintrc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ruby.rpmlintrc b/ruby.rpmlintrc index 1a67b89..fd3c655 100644 --- a/ruby.rpmlintrc +++ b/ruby.rpmlintrc @@ -50,3 +50,7 @@ addFilter(r'^rubygem-test-unit\.noarch: E: non-executable-script /usr/share/gems # 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$') From e6a3dff909d08791a7a2cf99b7c232673fc50663 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Wed, 12 May 2021 14:52:37 +0200 Subject: [PATCH 006/141] ruby.rpmlintrc: Remove prefix match. A result of ruby.spec file depends on how the spec file is called by rpmlint. ``` $ rpmlint ruby.spec ruby.spec:20: E: use-of-RPM_SOURCE_DIR .. 0 packages and 1 specfiles checked; 3 errors, 4 warnings. $ rpmlint ./ruby.spec ./ruby.spec:20: E: use-of-RPM_SOURCE_DIR .. 0 packages and 1 specfiles checked; 3 errors, 4 warnings. ``` --- ruby.rpmlintrc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ruby.rpmlintrc b/ruby.rpmlintrc index fd3c655..bc72c06 100644 --- a/ruby.rpmlintrc +++ b/ruby.rpmlintrc @@ -2,13 +2,13 @@ # 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$') +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\)$') +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 ') From 6b2ff68f33447f7769ad8265b0dd966f007eab9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Mon, 17 May 2021 08:54:53 +0200 Subject: [PATCH 007/141] Pass ldflags to gem install We have them, so we may as well pass them. This also fixes building ruby gems with clang. --- macros.rubygems | 2 +- ruby.spec | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/macros.rubygems b/macros.rubygems index 3f72b14..8c4d067 100644 --- a/macros.rubygems +++ b/macros.rubygems @@ -22,7 +22,7 @@ %gem_install(d:n:) \ mkdir -p %{-d*}%{!?-d:.%{gem_dir}} \ \ -CONFIGURE_ARGS="--with-cflags='%{optflags}' --with-cxxflags='%{optflags}' $CONFIGURE_ARGS" \\\ +CONFIGURE_ARGS="--with-cflags='%{optflags}' --with-cxxflags='%{optflags}' --with-ldflags='%{build_ldflags}' $CONFIGURE_ARGS" \\\ gem install \\\ -V \\\ --local \\\ diff --git a/ruby.spec b/ruby.spec index 1b70681..ecc0576 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 148 +%global release 149 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -1355,6 +1355,9 @@ MSPECOPTS="" %changelog +* Mon May 17 2021 Timm Bäder - 3.0.1-149 +- Pass ldflags to gem install via CONFIGURE_ARGS + * Tue Apr 06 2021 Vít Ondruch - 3.0.1-148 - Upgrade to Ruby 3.0.1. From 63065e7db7a3b02085280efbc783435ae40b9f1a Mon Sep 17 00:00:00 2001 From: Jarek Prokop Date: Tue, 13 Jul 2021 14:54:44 +0200 Subject: [PATCH 008/141] Upgrade to Ruby 3.0.2. - Fix command injection vulnerability in RDoc. Resolves: CVE-2021-31799 - Fix FTP PASV command response can cause Net::FTP to connect to arbitrary host. Resolves: CVE-2021-31810 - Fix StartTLS stripping vulnerability in Net::IMAP. Resolves: CVE-2021-32066 - Fix dependencies of gems with explicit source installed from a different source. Resolves: CVE-2020-36327 --- ...0-Enable-configuration-of-archlibdir.patch | 2 +- ...ed-paths-when-empty-version-string-i.patch | 2 +- ruby-2.1.0-always-use-i386.patch | 2 +- ruby-2.1.0-custom-rubygems-location.patch | 8 +++---- ruby-2.3.0-ruby_version.patch | 10 ++++---- ruby.spec | 24 ++++++++++++++----- sources | 2 +- 7 files changed, 31 insertions(+), 19 deletions(-) diff --git a/ruby-2.1.0-Enable-configuration-of-archlibdir.patch b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch index 9759776..32806da 100644 --- a/ruby-2.1.0-Enable-configuration-of-archlibdir.patch +++ b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch @@ -11,7 +11,7 @@ diff --git a/configure.ac b/configure.ac index d261ea57b5..3c13076b82 100644 --- a/configure.ac +++ b/configure.ac -@@ -3211,6 +3211,11 @@ AS_IF([test ${multiarch+set}], [ +@@ -3240,6 +3240,11 @@ AS_IF([test ${multiarch+set}], [ ]) archlibdir='${libdir}/${arch}' 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 index 2e751cb..118203c 100644 --- 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 @@ -14,7 +14,7 @@ diff --git a/configure.ac b/configure.ac index c42436c23d..d261ea57b5 100644 --- a/configure.ac +++ b/configure.ac -@@ -3852,7 +3852,8 @@ AS_CASE(["$ruby_version_dir_name"], +@@ -3881,7 +3881,8 @@ AS_CASE(["$ruby_version_dir_name"], ruby_version_dir=/'${ruby_version_dir_name}' if test -z "${ruby_version_dir_name}"; then diff --git a/ruby-2.1.0-always-use-i386.patch b/ruby-2.1.0-always-use-i386.patch index c1b3942..de58295 100644 --- a/ruby-2.1.0-always-use-i386.patch +++ b/ruby-2.1.0-always-use-i386.patch @@ -11,7 +11,7 @@ diff --git a/configure.ac b/configure.ac index 3c13076b82..93af30321d 100644 --- a/configure.ac +++ b/configure.ac -@@ -3916,6 +3916,8 @@ AC_SUBST(vendorarchdir)dnl +@@ -3945,6 +3945,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 diff --git a/ruby-2.1.0-custom-rubygems-location.patch b/ruby-2.1.0-custom-rubygems-location.patch index 1646675..b7157ff 100644 --- a/ruby-2.1.0-custom-rubygems-location.patch +++ b/ruby-2.1.0-custom-rubygems-location.patch @@ -15,7 +15,7 @@ diff --git a/configure.ac b/configure.ac index 93af30321d..bc13397e0e 100644 --- a/configure.ac +++ b/configure.ac -@@ -3888,6 +3888,10 @@ AC_ARG_WITH(vendorarchdir, +@@ -3917,6 +3917,10 @@ AC_ARG_WITH(vendorarchdir, [vendorarchdir=$withval], [vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby'${ruby_version_dir}}${multiarch-'${vendorlibdir}/${sitearch}'}]) @@ -26,7 +26,7 @@ index 93af30321d..bc13397e0e 100644 AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) RUBY_EXEC_PREFIX='' -@@ -3912,6 +3916,7 @@ AC_SUBST(sitearchdir)dnl +@@ -3941,6 +3941,7 @@ AC_SUBST(sitearchdir)dnl AC_SUBST(vendordir)dnl AC_SUBST(vendorlibdir)dnl AC_SUBST(vendorarchdir)dnl @@ -67,7 +67,7 @@ diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb index e9110a17ca..76a1f0a315 100755 --- a/tool/rbinstall.rb +++ b/tool/rbinstall.rb -@@ -348,6 +348,7 @@ def CONFIG.[](name, mandatory = false) +@@ -349,6 +349,7 @@ def CONFIG.[](name, mandatory = false) vendorlibdir = CONFIG["vendorlibdir"] vendorarchlibdir = CONFIG["vendorarchdir"] end @@ -75,7 +75,7 @@ index e9110a17ca..76a1f0a315 100755 mandir = CONFIG["mandir", true] docdir = CONFIG["docdir", true] enable_shared = CONFIG["ENABLE_SHARED"] == 'yes' -@@ -580,7 +581,16 @@ def stub +@@ -581,7 +581,16 @@ def stub install?(:local, :comm, :lib) do prepare "library scripts", rubylibdir noinst = %w[*.txt *.rdoc *.gemspec] diff --git a/ruby-2.3.0-ruby_version.patch b/ruby-2.3.0-ruby_version.patch index f596602..4fd6530 100644 --- a/ruby-2.3.0-ruby_version.patch +++ b/ruby-2.3.0-ruby_version.patch @@ -20,7 +20,7 @@ diff --git a/configure.ac b/configure.ac index 80b137e380..63cd3b4f8b 100644 --- a/configure.ac +++ b/configure.ac -@@ -3803,9 +3803,6 @@ AS_CASE(["$target_os"], +@@ -3832,9 +3832,6 @@ AS_CASE(["$target_os"], rubyw_install_name='$(RUBYW_INSTALL_NAME)' ]) @@ -30,7 +30,7 @@ index 80b137e380..63cd3b4f8b 100644 rubyarchprefix=${multiarch+'${archlibdir}/${RUBY_BASE_NAME}'}${multiarch-'${rubylibprefix}/${arch}'} AC_ARG_WITH(rubyarchprefix, AS_HELP_STRING([--with-rubyarchprefix=DIR], -@@ -3828,56 +3825,62 @@ AC_ARG_WITH(ridir, +@@ -3857,56 +3857,62 @@ AC_ARG_WITH(ridir, AC_SUBST(ridir) AC_SUBST(RI_BASE_NAME) @@ -120,7 +120,7 @@ index 80b137e380..63cd3b4f8b 100644 AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) -@@ -3894,6 +3897,7 @@ AC_SUBST(sitearchincludedir)dnl +@@ -3923,6 +3923,7 @@ AC_SUBST(sitearchincludedir)dnl AC_SUBST(arch)dnl AC_SUBST(sitearch)dnl AC_SUBST(ruby_version)dnl @@ -171,7 +171,7 @@ diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb index d4c110e..d39c9a6 100755 --- a/tool/rbinstall.rb +++ b/tool/rbinstall.rb -@@ -438,7 +438,7 @@ def CONFIG.[](name, mandatory = false) +@@ -439,7 +439,7 @@ def CONFIG.[](name, mandatory = false) install?(:doc, :rdoc) do if $rdocdir @@ -274,7 +274,7 @@ diff --git a/configure.ac b/configure.ac index a00f2b6776..999e2d6d5d 100644 --- a/configure.ac +++ b/configure.ac -@@ -81,7 +81,7 @@ RUBY_BASE_NAME=`echo ruby | sed "$program_transform_name"` +@@ -107,7 +107,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) diff --git a/ruby.spec b/ruby.spec index ecc0576..50134e6 100644 --- a/ruby.spec +++ b/ruby.spec @@ -1,6 +1,6 @@ %global major_version 3 %global minor_version 0 -%global teeny_version 1 +%global teeny_version 2 %global major_minor_version %{major_version}.%{minor_version} %global ruby_version %{major_minor_version}.%{teeny_version} @@ -22,7 +22,7 @@ %endif -%global release 149 +%global release 150 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -30,11 +30,11 @@ %global rubygems_dir %{_datadir}/rubygems # Bundled libraries versions -%global rubygems_version 3.2.15 +%global rubygems_version 3.2.22 %global rubygems_molinillo_version 0.7.0 # Default gems. -%global bundler_version 2.2.15 +%global bundler_version 2.2.22 %global bundler_connection_pool_version 2.2.2 %global bundler_fileutils_version 1.4.1 %global bundler_molinillo_version 0.7.0 @@ -52,7 +52,7 @@ %global openssl_version 2.2.0 %global psych_version 3.3.0 %global racc_version 1.5.1 -%global rdoc_version 6.3.0 +%global rdoc_version 6.3.1 # Bundled gems. %global minitest_version 5.14.2 @@ -1162,7 +1162,7 @@ MSPECOPTS="" %{gem_dir}/specifications/default/logger-1.4.3.gemspec %{gem_dir}/specifications/default/matrix-0.3.1.gemspec %{gem_dir}/specifications/default/mutex_m-0.1.1.gemspec -%{gem_dir}/specifications/default/net-ftp-0.1.1.gemspec +%{gem_dir}/specifications/default/net-ftp-0.1.2.gemspec %{gem_dir}/specifications/default/net-http-0.1.1.gemspec %{gem_dir}/specifications/default/net-imap-0.1.1.gemspec %{gem_dir}/specifications/default/net-pop-0.1.1.gemspec @@ -1355,6 +1355,18 @@ MSPECOPTS="" %changelog +* Tue Jul 13 2021 Jarek Prokop - 3.0.2-150 +- Upgrade to Ruby 3.0.2. +- Fix command injection vulnerability in RDoc. + Resolves: CVE-2021-31799 +- Fix FTP PASV command response can cause Net::FTP to connect to arbitrary host. + Resolves: CVE-2021-31810 +- Fix StartTLS stripping vulnerability in Net::IMAP. + Resolves: CVE-2021-32066 +- Fix dependencies of gems with explicit source installed from a different + source. + Resolves: CVE-2020-36327 + * Mon May 17 2021 Timm Bäder - 3.0.1-149 - Pass ldflags to gem install via CONFIGURE_ARGS diff --git a/sources b/sources index bed9a6d..fc750ca 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (ruby-3.0.1.tar.xz) = 97d2e883656060846b304368d9d836e2f3ef39859c36171c9398a0573818e4ed75bfd7460f901a9553f7f53518c505327a66e74f83704a881469f5ac61fe13d7 +SHA512 (ruby-3.0.2.tar.xz) = 0f702e2d8ca1342a9d4284dbdd234a3588e057b92566353aa7c21835cf09a3932864b2acf459a976960a1704e9befa562155d36b98b7cda8bd99526e10a374c4 From 089c0a1928d85de7827f8d79fc7d3cb4c822a7f1 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 23 Jul 2021 11:43:38 +0000 Subject: [PATCH 009/141] - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- ruby.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ruby.spec b/ruby.spec index 50134e6..9f01a3a 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 150 +%global release 151 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -1355,6 +1355,9 @@ MSPECOPTS="" %changelog +* Fri Jul 23 2021 Fedora Release Engineering +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + * Tue Jul 13 2021 Jarek Prokop - 3.0.2-150 - Upgrade to Ruby 3.0.2. - Fix command injection vulnerability in RDoc. From 1170d812fe0cd43aeddf7f15a63c2e6db3af8059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Tue, 24 Aug 2021 17:29:31 +0200 Subject: [PATCH 010/141] Enable LTO. --- ...et-rid-of-type-punning-pointer-casts.patch | 186 ++++++++++++++++++ ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch | 58 ++++++ ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch | 29 +++ ruby.spec | 24 ++- 4 files changed, 292 insertions(+), 5 deletions(-) create mode 100644 ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch create mode 100644 ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch create mode 100644 ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch 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..b5c80ad --- /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 +@@ -1636,9 +1636,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)); + +@@ -1705,8 +1707,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 +1024,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 +1034,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 +1079,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 +1108,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 +1129,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..9d218e5 --- /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 +@@ -1592,14 +1592,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 */ +@@ -1664,7 +1681,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-addr2line-DW_FORM_ref_addr.patch b/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch new file mode 100644 index 0000000..74636e5 --- /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 +@@ -1137,12 +1137,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.spec b/ruby.spec index 9f01a3a..2b92a6d 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 151 +%global release 152 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -80,10 +80,6 @@ %bcond_without hardening_test %endif -# LTO appears to cause some issue to SEGV handler. -# https://bugs.ruby-lang.org/issues/17052 -%define _lto_cflags %{nil} - Summary: An interpreter of object-oriented scripting language Name: ruby Version: %{ruby_version} @@ -150,6 +146,18 @@ Patch9: ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1920533 # https://bugs.ruby-lang.org/issues/17585 Patch15: ruby-dwarf5-avoid_crash-r1.patch +# Fix segfaults with enabled LTO. +# https://bugs.ruby-lang.org/issues/18062 +# https://github.com/ruby/ruby/pull/4716 +Patch16: ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch +# DWARF5/LTO fixes for SIGSEV handler. +# https://bugs.ruby-lang.org/issues/17052 +# https://github.com/ruby/ruby/commit/72317b333b85eed483ad00bcd4f40944019a7c13 +Patch17: ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch +# https://bugs.ruby-lang.org/issues/17052#note-9 +# https://bugs.ruby-lang.org/attachments/download/8974/ruby-addr2line-DW_FORM_ref_addr.patch +# https://github.com/ruby/ruby/commit/a9977ba2f9863e3fb1b2346589ebbca67d80536c +Patch18: ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch # Avoid possible timeout errors in TestBugReporter#test_bug_reporter_add. # https://bugs.ruby-lang.org/issues/16492 Patch19: ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch @@ -598,6 +606,9 @@ rm -rf ext/fiddle/libffi* %patch6 -p1 %patch9 -p1 %patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 %patch19 -p1 # Provide an example of usage of the tapset: @@ -1355,6 +1366,9 @@ MSPECOPTS="" %changelog +* Tue Aug 24 2021 Vít Ondruch - 3.0.2-152 +- Enable LTO. + * Fri Jul 23 2021 Fedora Release Engineering - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild From 11a27766bd500e054f71bcbc283e12bacb2a275e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Tue, 24 Aug 2021 18:23:20 +0200 Subject: [PATCH 011/141] Load user installed RubyGems plugins. --- ruby.spec | 5 ++ ...load-user-installed-rubygems-plugins.patch | 61 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 rubygems-3.2.26-Also-load-user-installed-rubygems-plugins.patch diff --git a/ruby.spec b/ruby.spec index 2b92a6d..6ad233c 100644 --- a/ruby.spec +++ b/ruby.spec @@ -142,6 +142,9 @@ Patch6: ruby-2.7.0-Initialize-ABRT-hook.patch # hardening features of glibc (rhbz#1361037). # https://bugs.ruby-lang.org/issues/12666 Patch9: ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch +# Load user installed RubyGems plugins. +# https://github.com/rubygems/rubygems/issues/4823 +Patch10: rubygems-3.2.26-Also-load-user-installed-rubygems-plugins.patch # Fix DWARF5 support. # https://bugzilla.redhat.com/show_bug.cgi?id=1920533 # https://bugs.ruby-lang.org/issues/17585 @@ -605,6 +608,7 @@ rm -rf ext/fiddle/libffi* %patch5 -p1 %patch6 -p1 %patch9 -p1 +%patch10 -p1 %patch15 -p1 %patch16 -p1 %patch17 -p1 @@ -1368,6 +1372,7 @@ MSPECOPTS="" %changelog * Tue Aug 24 2021 Vít Ondruch - 3.0.2-152 - Enable LTO. +- Load user installed RubyGems plugins. * Fri Jul 23 2021 Fedora Release Engineering - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild diff --git a/rubygems-3.2.26-Also-load-user-installed-rubygems-plugins.patch b/rubygems-3.2.26-Also-load-user-installed-rubygems-plugins.patch new file mode 100644 index 0000000..7af6df6 --- /dev/null +++ b/rubygems-3.2.26-Also-load-user-installed-rubygems-plugins.patch @@ -0,0 +1,61 @@ +From 82960c262fea081cdd3df14ebe573ff1c4925d0c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +Date: Fri, 6 Aug 2021 12:21:23 +0200 +Subject: [PATCH] Also load user installed rubygems plugins + +--- + lib/rubygems.rb | 4 +++- + test/rubygems/test_gem.rb | 25 +++++++++++++++++++++++++ + 2 files changed, 28 insertions(+), 1 deletion(-) + +diff --git a/lib/rubygems.rb b/lib/rubygems.rb +index a631cde8bf8..17881e2e0e9 100644 +--- a/lib/rubygems.rb ++++ b/lib/rubygems.rb +@@ -1063,7 +1063,9 @@ def self.load_plugin_files(plugins) # :nodoc: + # Find rubygems plugin files in the standard location and load them + + def self.load_plugins +- load_plugin_files Gem::Util.glob_files_in_dir("*#{Gem.plugin_suffix_pattern}", plugindir) ++ Gem.path.each do |gem_path| ++ load_plugin_files Gem::Util.glob_files_in_dir("*#{Gem.plugin_suffix_pattern}", plugindir(gem_path)) ++ end + end + + ## +diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb +index 0d4b1571ca7..da154dac75b 100644 +--- a/test/rubygems/test_gem.rb ++++ b/test/rubygems/test_gem.rb +@@ -1581,6 +1581,31 @@ def test_load_plugins + assert_equal %w[plugin], PLUGINS_LOADED + end + ++ def test_load_user_installed_plugins ++ plugin_path = File.join "lib", "rubygems_plugin.rb" ++ ++ Dir.chdir @tempdir do ++ FileUtils.mkdir_p 'lib' ++ File.open plugin_path, "w" do |fp| ++ fp.puts "class TestGem; PLUGINS_LOADED << 'plugin'; end" ++ end ++ ++ foo = util_spec 'foo', '1' do |s| ++ s.files << plugin_path ++ end ++ ++ install_gem_user foo ++ end ++ ++ Gem.paths = { "GEM_PATH" => [Gem.dir, Gem.user_dir].join(File::PATH_SEPARATOR) } ++ ++ gem 'foo' ++ ++ Gem.load_plugins ++ ++ assert_equal %w[plugin], PLUGINS_LOADED ++ end ++ + def test_load_env_plugins + with_plugin('load') { Gem.load_env_plugins } + assert_equal :loaded, TEST_PLUGIN_LOAD rescue nil From d75a6c86f9dde0e5d79e67a962a1846718a2965e Mon Sep 17 00:00:00 2001 From: Sahana Prasad Date: Tue, 14 Sep 2021 19:13:53 +0200 Subject: [PATCH 012/141] Rebuilt with OpenSSL 3.0.0 --- ruby.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ruby.spec b/ruby.spec index 6ad233c..414eb19 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 152 +%global release 153 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -1370,6 +1370,9 @@ MSPECOPTS="" %changelog +* Tue Sep 14 2021 Sahana Prasad +- Rebuilt with OpenSSL 3.0.0 + * Tue Aug 24 2021 Vít Ondruch - 3.0.2-152 - Enable LTO. - Load user installed RubyGems plugins. From 78a9fbc351cf0e12b653a69438a9e6b9d1292246 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Fri, 1 Oct 2021 14:30:59 +0200 Subject: [PATCH 013/141] Add AC_PROG_CC to make C++ compiler dependency optional on autoconf >= 2.70. Resolves: rhbz#1999479 --- ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch | 27 +++++++++++++++++++ ruby.spec | 4 +++ 2 files changed, 31 insertions(+) create mode 100644 ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch diff --git a/ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch b/ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch new file mode 100644 index 0000000..1bd20bd --- /dev/null +++ b/ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch @@ -0,0 +1,27 @@ +From 912a8dcfc5369d840dcd6bf0f88ee0bac7d902d6 Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Thu, 30 Sep 2021 18:24:37 +0900 +Subject: [PATCH] Needs `AC_PROG_CC` + +Although `AC_PROG_CC_C99` has been obsolete, `AC_PROG_CC` is not +and the latter is necessary not to make C++ compiler mandatory. +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index b24a8f59b0..c7059ee1ec 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -203,7 +203,7 @@ rb_test_CXXFLAGS=${CXXFLAGS+yes} + # BSD's ports and MacPorts prefix GNU binutils with 'g' + + dnl Seems necessarily in order to add -std=gnu99 option for gcc 4.9. +-m4_version_prereq([2.70], [], [AC_PROG_CC_C99]) ++m4_version_prereq([2.70], [AC_PROG_CC], [AC_PROG_CC_C99]) + + AC_PROG_CXX + AC_PROG_CPP +-- +2.31.1 + diff --git a/ruby.spec b/ruby.spec index 414eb19..eb43d42 100644 --- a/ruby.spec +++ b/ruby.spec @@ -164,6 +164,9 @@ Patch18: ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch # Avoid possible timeout errors in TestBugReporter#test_bug_reporter_add. # https://bugs.ruby-lang.org/issues/16492 Patch19: ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch +# Add AC_PROG_CC to make C++ compiler dependency optional on autoconf >= 2.70. +# https://github.com/ruby/ruby/commit/912a8dcfc5369d840dcd6bf0f88ee0bac7d902d6 +Patch20: ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -614,6 +617,7 @@ rm -rf ext/fiddle/libffi* %patch17 -p1 %patch18 -p1 %patch19 -p1 +%patch20 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . From c4f8814a9393d7c0fb5870a5d6c7c1a4dd6958d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Fri, 5 Nov 2021 20:55:56 +0100 Subject: [PATCH 014/141] Fix OpenSSL 3.0 compatibility. Resolves: rhbz#2021922 --- ...-more-support-for-generic-pkey-types.patch | 1004 ++++++++++++ ...-specific-options-in-sign-and-verify.patch | 358 ++++ ...gn_raw-verify_raw-and-verify_recover.patch | 1319 +++++++++++++++ ...eous-changes-for-OpenSSL-3.0-support.patch | 142 ++ ruby-3.1.0-Properly-exclude-test-cases.patch | 93 ++ ...-Refactor-PEM-DER-serialization-code.patch | 1450 +++++++++++++++++ ruby-3.1.0-SSL_read-EOF-handling.patch | 16 + ruby-3.1.0-Support-OpenSSL-3.0.patch | 1101 +++++++++++++ ruby-3.1.0-Use-EVP-API-in-more-places.patch | 831 ++++++++++ ...face-to-generate-parameters-and-keys.patch | 1113 +++++++++++++ ...t_digest-do-not-test-constants-for-l.patch | 29 + ...t_pkcs12-fix-test-failures-with-Open.patch | 439 +++++ ...t_pkey-use-EC-keys-for-PKey.generate.patch | 67 + ...t_ssl-relax-regex-to-match-OpenSSL-s.patch | 31 + ...tils-remove-dup_public-helper-method.patch | 265 +++ ruby.spec | 94 ++ ...ished-name-which-will-be-correctly-p.patch | 44 + ...0-Switch-from-DES-CBC-to-AES-256-CBC.patch | 106 ++ ...se-OpenSSL-constants-for-error-codes.patch | 75 + 19 files changed, 8577 insertions(+) create mode 100644 ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch create mode 100644 ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch create mode 100644 ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch create mode 100644 ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch create mode 100644 ruby-3.1.0-Properly-exclude-test-cases.patch create mode 100644 ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch create mode 100644 ruby-3.1.0-SSL_read-EOF-handling.patch create mode 100644 ruby-3.1.0-Support-OpenSSL-3.0.patch create mode 100644 ruby-3.1.0-Use-EVP-API-in-more-places.patch create mode 100644 ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch create mode 100644 ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch create mode 100644 ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch create mode 100644 ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch create mode 100644 ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch create mode 100644 ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch create mode 100644 rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch create mode 100644 rubygems-3.2.30-Switch-from-DES-CBC-to-AES-256-CBC.patch create mode 100644 rubygems-3.2.30-Use-OpenSSL-constants-for-error-codes.patch 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-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-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..afb3a87 --- /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), (int)RSTRING_LEN(sig), ec)) { +- case 1: return Qtrue; +- case 0: return Qfalse; +- default: break; +- } +- +- ossl_raise(eECError, "ECDSA_verify"); +- +- UNREACHABLE; +-} +- + /* + * 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-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..3a0e03b --- /dev/null +++ b/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch @@ -0,0 +1,142 @@ +From 8f948ed68a4ed6c05ff66d822711e3b70ae4bb3f Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 27 Sep 2021 13:32:03 +0900 +Subject: [PATCH 1/3] 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 +@@ -43,6 +43,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/3] 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 +@@ -166,7 +166,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") +@@ -175,6 +175,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 +@@ -242,4 +242,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 +@@ -816,7 +816,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/3] 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 +@@ -1522,8 +1522,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 + 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..3b88433 --- /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 insertion(+), 3 deletion(-) + +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-SSL_read-EOF-handling.patch b/ruby-3.1.0-SSL_read-EOF-handling.patch new file mode 100644 index 0000000..fb08773 --- /dev/null +++ b/ruby-3.1.0-SSL_read-EOF-handling.patch @@ -0,0 +1,16 @@ +diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c +index 3b425ca..40e748c 100644 +--- a/ext/openssl/ossl_ssl.c ++++ b/ext/openssl/ossl_ssl.c +@@ -1844,6 +1844,11 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) + return str; + + GetSSL(self, ssl); ++ ++#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF ++ SSL_set_options(ssl, SSL_OP_IGNORE_UNEXPECTED_EOF); ++#endif ++ + io = rb_attr_get(self, id_i_io); + GetOpenFile(io, fptr); + if (ssl_started(ssl)) { diff --git a/ruby-3.1.0-Support-OpenSSL-3.0.patch b/ruby-3.1.0-Support-OpenSSL-3.0.patch new file mode 100644 index 0000000..e701ad0 --- /dev/null +++ b/ruby-3.1.0-Support-OpenSSL-3.0.patch @@ -0,0 +1,1101 @@ +From bc9cbef395fc8fc7f81c3911b92966abc693169a Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 24 Oct 2021 17:50:18 +0900 +Subject: [PATCH 01/10] test/openssl/test_cipher: update test_ciphers + +Do not attempt to actually use all algorithms. Not all algorithms listed +in OpenSSL::Cipher.ciphers are always available; some may belong to the +legacy provider in OpenSSL 3.0. +--- + 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 178f5aba0e..395183b22d 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 +-- +2.32.0 + + +From f73998da49d2cd273b38b542ddd49a4ceaf5bfa9 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Wed, 3 Nov 2021 23:31:29 +0900 +Subject: [PATCH 02/10] test/openssl/test_pkey_rsa: test concatenated PEM + parsing + +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 behavior 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 4548bdb2cf..327449ae03 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 +-- +2.32.0 + + +From eb44c4c0eff7a63f9b0bc5d7a7a0df014f1c1b62 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 20 Mar 2021 23:16:16 +0900 +Subject: [PATCH 03/10] pkey: use OSSL_DECODER to load encrypted PEM on OpenSSL + 3.0 + +The routines to load pkeys (PEM_read_bio_* and d2i_* functions) have +been rewritten around the newly introduced OSSL_DECODER API in OpenSSL +3.0. They now first try to decrypt and parse a PEM block, and then check +the kind. Since we try to parse a given string using each of them in +turn, this means the password callback may now be called more than once. + +Let's use the OSSL_DECODER API directly on OpenSSL 3.0 to avoid this +from happening. +--- + 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 ba909c7632..4eab598942 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: +-- +2.32.0 + + +From 588165c3235a23f0df58c8ec50ad6f46a05580f1 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 20 Mar 2021 23:16:41 +0900 +Subject: [PATCH 04/10] pkey: assume a pkey always has public key components on + OpenSSL 3.0 + +Do not check the key components in this way because they are not +necessarily accessible in this way. +--- + 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 4eab598942..a805b4dc99 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 * +-- +2.32.0 + + +From 4c362a1fad72fd570985e4f401ba534456252cb3 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 12 Apr 2021 10:43:46 +0900 +Subject: [PATCH 05/10] 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 as a string rather than a 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 a805b4dc99..73a54eb2fb 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) { +-- +2.32.0 + + +From 013c8552b845a8607f9a0639a07e1515fe067cd3 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 12 Apr 2021 13:55:10 +0900 +Subject: [PATCH 06/10] pkey: do not check NULL argument in ossl_pkey_new() + +Since the function takes the ownership, the caller is supposed to know +that the lifetime of the object - that is, it is never NULL. In fact, +it is properly checked by the caller in all code paths. +--- + 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 73a54eb2fb..5320d70a48 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 629c16ae1f..d57e9c0f15 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); +-- +2.32.0 + + +From 2a9f958d71922303f223d4dcc15049d7dfa962a9 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 12 Apr 2021 18:32:40 +0900 +Subject: [PATCH 07/10] pkey: lazily initialize EVP_PKEY + +Allocate an EVP_PKEY when the content is ready: when #initialize +or #initialize_copy is called, rather than when OpenSSL::PKey::PKey is +allocated. + +This simplifies #initialize's and the upcoming generic #initialize_copy +implementation. +--- + ext/openssl/ossl_pkey.c | 15 ++---- + ext/openssl/ossl_pkey.h | 19 +++----- + ext/openssl/ossl_pkey_dh.c | 69 ++++++++++++++++++++-------- + ext/openssl/ossl_pkey_dsa.c | 87 +++++++++++++++++++++-------------- + ext/openssl/ossl_pkey_ec.c | 92 ++++++++++++++++++++----------------- + ext/openssl/ossl_pkey_rsa.c | 91 +++++++++++++++++++++--------------- + 6 files changed, 217 insertions(+), 156 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 5320d70a48..9ddfaafe7c 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; + } + +@@ -528,16 +528,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 d57e9c0f15..ac386717d7 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -15,21 +15,14 @@ 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 GetPKey0(obj, pkey) \ ++ TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)) + #define GetPKey(obj, pkey) do {\ +- TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \ ++ GetPKey0((obj), (pkey)); \ + if (!(pkey)) { \ + rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\ + } \ +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index ca782bbe59..7d8e0fa502 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -76,7 +76,10 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) + BIO *in; + VALUE arg; + +- GetPKey(self, pkey); ++ GetPKey0(self, 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(); +@@ -84,22 +87,44 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) + ossl_raise(eDHError, "DH_new"); + } + 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); +- } ++ int type; ++ ++ arg = ossl_to_der_if_possible(arg); ++ in = ossl_obj2bio(&arg); ++ ++ /* First try DER-encoded parameters */ ++ dh = d2i_DHparams_bio(in, NULL); ++ OSSL_BIO_reset(in); ++ if (dh) { ++ BIO_free(in); ++ goto legacy; ++ } ++ ++ /* Use the generic routine - parses PEM-encoded parameters */ ++ 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)); ++ } ++ RTYPEDDATA_DATA(self) = pkey; ++ return self; + } +- if (!EVP_PKEY_assign_DH(pkey, dh)) { +- DH_free(dh); +- ossl_raise(eDHError, NULL); ++ ++ legacy: ++ if (dh) { ++ 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 +135,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"); ++ GetPKey0(self, 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 +157,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 7af00eebec..1bba6c54b7 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -83,12 +83,16 @@ VALUE eDSAError; + static VALUE + ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) + { +- EVP_PKEY *pkey, *tmp; +- DSA *dsa = NULL; ++ EVP_PKEY *pkey; ++ DSA *dsa; + BIO *in; + VALUE arg, pass; ++ int type; ++ ++ GetPKey0(self, 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) { +@@ -97,36 +101,41 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) + ossl_raise(eDSAError, "DSA_new"); + } + 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); ++ pass = ossl_pem_passwd_value(pass); ++ arg = ossl_to_der_if_possible(arg); ++ in = ossl_obj2bio(&arg); ++ ++ dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey, ++ PEM_STRING_DSA_PUBLIC, ++ in, NULL, NULL, NULL); ++ OSSL_BIO_reset(in); ++ if (dsa) ++ goto legacy; ++ ++ 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)); + } +- 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); ++ RTYPEDDATA_DATA(self) = pkey; ++ return self; + } + ++ legacy: ++ if (dsa) { ++ 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"); ++ GetPKey0(self, 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 f52e67079d..bec9937bc6 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,55 @@ 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"); ++ GetPKey0(self, 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; +- +- 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; ++ ossl_raise(eECError, "EC_KEY_new"); ++ } ++ else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { ++ ec = ec_key_new_from_group(arg); ++ } ++ else { + 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); ++ arg = ossl_to_der_if_possible(arg); ++ in = ossl_obj2bio(&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; + } +- BIO_free(in); + +- if (!ec) { +- ossl_clear_error(); +- ec = ec_key_new_from_group(arg); +- } ++ 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; + } + +- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { +- EC_KEY_free(ec); +- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); ++ legacy: ++ if (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(self) = pkey; + return self; + } + +@@ -195,18 +202,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"); ++ GetPKey0(self, 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 8ebd3ec559..446150c8af 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -76,12 +76,16 @@ VALUE eRSAError; + static VALUE + ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + { +- EVP_PKEY *pkey, *tmp; +- RSA *rsa = NULL; ++ EVP_PKEY *pkey; ++ RSA *rsa; + BIO *in; + VALUE arg, pass; ++ int type; ++ ++ GetPKey0(self, 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) { +@@ -90,37 +94,45 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + ossl_raise(eRSAError, "RSA_new"); + } + 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); ++ 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); ++ OSSL_BIO_reset(in); ++ if (rsa) ++ goto legacy; ++ rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); ++ OSSL_BIO_reset(in); ++ if (rsa) ++ goto legacy; ++ ++ /* 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)); + } +- 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"); ++ RTYPEDDATA_DATA(self) = pkey; ++ return self; + } + ++ legacy: ++ if (rsa) { ++ 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 +142,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"); ++ GetPKey0(self, 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; + } +-- +2.32.0 + + +From 0ea28ac73e094bbb379b0915a67d44582e5e20da Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Thu, 22 Apr 2021 18:29:30 +0900 +Subject: [PATCH 08/10] pkey: deprecate OpenSSL::PKey::{RSA,DSA,DH}#set_* + methods + +The underlying OpenSSL functions, {RSA,DSA,DH}_set_*() are removed in +OpenSSL 3.0. + +Since the plan is to make EVP_PKEY immutable, there will be no direct +replacement for them and we have no choice here. + +It is suggested for users to use OpenSSL::PKey.from_data instead, +which construct a pkey from all necessary parameters at once. +--- + ext/openssl/ossl_pkey.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index ac386717d7..f6ad961937 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -130,6 +130,8 @@ static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALU + BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\ + BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\ + \ ++ rb_warning(#_keytype"#set_"#_group"= is incompatible with " \ ++ "OpenSSL 3.0; check OpenSSL::PKey.from_data"); \ + Get##_type(self, obj); \ + if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \ + (orig_bn2 && !(bn2 = BN_dup(orig_bn2))) || \ +@@ -160,6 +162,8 @@ static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \ + BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\ + BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\ + \ ++ rb_warning(#_keytype"#set_"#_group"= is incompatible with " \ ++ "OpenSSL 3.0; check OpenSSL::PKey.from_data"); \ + Get##_type(self, obj); \ + if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \ + (orig_bn2 && !(bn2 = BN_dup(orig_bn2)))) { \ +-- +2.32.0 + + +From 6fda9b5c292fbaae2eb7d6c8e15f1ff53ae7e50c Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 21 Sep 2021 18:29:59 +0900 +Subject: [PATCH 09/10] test/openssl/test_pkey_ec: update test_check_key for + OpenSSL 3.0 + +OpenSSL::PKey::EC#generate_key! or #private_key= will not work on +OpenSSL 3.0. +--- + test/openssl/test_pkey_ec.rb | 32 +++++++++++++++++++------------- + 1 file changed, 19 insertions(+), 13 deletions(-) + +diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb +index d62f1b5eb8..730ad28062 100644 +--- a/test/openssl/test_pkey_ec.rb ++++ b/test/openssl/test_pkey_ec.rb +@@ -60,22 +60,28 @@ 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) ++ EnvUtil.suppress_warning do ++ key2.private_key += 1 ++ assert_raise(OpenSSL::PKey::ECError) { key2.check_key } ++ end ++ end + end + + def test_sign_verify +-- +2.32.0 + + +From b63c0cb012981613463bdf4d80dcaedfa494a0d0 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 22 Oct 2021 16:24:07 +0900 +Subject: [PATCH 10/10] pkey/dh: deprecate OpenSSL::PKey::DH#generate_key! + +OpenSSL 3.0.0 has made keys immutable, so PKey::DH#generate_key! can't +work on it anymore. + +It's advised to use OpenSSL::PKey.generate_key instead. +--- + ext/openssl/lib/openssl/pkey.rb | 26 ++++++++++++++++++++++---- + test/openssl/test_pkey_dh.rb | 33 ++++++++++++++++++--------------- + 2 files changed, 40 insertions(+), 19 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index f6bf5892b0..cad376855d 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -61,14 +61,32 @@ 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! ++ msg = "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \ ++ "use OpenSSL::PKey.generate_key instead" ++ if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000 ++ raise DHError, msg ++ else ++ warn "#{caller(1, 1)[0]}: warning: #{msg}" ++ end ++ + unless priv_key + tmp = OpenSSL::PKey.generate_key(self) + set_key(tmp.pub_key, tmp.priv_key) +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index 757704caf6..248f4ebb42 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,17 @@ def test_public_key + end + + def test_generate_key +- dh = Fixtures.pkey("dh1024").public_key # creates a copy +- assert_no_key(dh) +- dh.generate_key! +- assert_key(dh) +- end +- +- def test_key_exchange +- dh = Fixtures.pkey("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 ++ EnvUtil.suppress_warning { # 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) ++ ++ dh2 = dh.public_key ++ dh2.generate_key! ++ assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key)) ++ } ++ end if !openssl?(3, 0, 0) + + def test_params_ok? + dh0 = Fixtures.pkey("dh1024") +-- +2.32.0 + 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..4938949 --- /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 +@@ -173,6 +173,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-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..acb706e --- /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("HMAC_CTX_new") +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-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..f638047 --- /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 +@@ -955,7 +955,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..23c73ba --- /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 +@@ -305,32 +305,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.spec b/ruby.spec index eb43d42..d0bb381 100644 --- a/ruby.spec +++ b/ruby.spec @@ -167,6 +167,71 @@ Patch19: ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch # Add AC_PROG_CC to make C++ compiler dependency optional on autoconf >= 2.70. # https://github.com/ruby/ruby/commit/912a8dcfc5369d840dcd6bf0f88ee0bac7d902d6 Patch20: ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch +# Allow to exclude test with fully qualified name. +# https://bugs.ruby-lang.org/issues/16936 +# https://github.com/ruby/ruby/pull/5026 +Patch21: ruby-3.1.0-Properly-exclude-test-cases.patch + + +# OpenSSL 3.0 compatibility patches + +# Switch from legacy DES-CBC to AES-256-CBC. +# https://github.com/rubygems/rubygems/pull/4986 +Patch30: rubygems-3.2.30-Switch-from-DES-CBC-to-AES-256-CBC.patch +# Fix test broken by wrongly formatted distinguished name submitted to +# `OpenSSL::X509::Name.parse`. +# https://github.com/ruby/openssl/issues/470 +# https://github.com/rubygems/rubygems/pull/5030 +Patch31: rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch +# Fix TestGemRequest#test_verify_certificate_extra_message compatibility +# with OpenSSL 3.x. +# https://github.com/rubygems/rubygems/pull/5040 +Patch32: rubygems-3.2.30-Use-OpenSSL-constants-for-error-codes.patch + +# Refactor PEM/DER serialization code. +# https://github.com/ruby/openssl/pull/328 +Patch40: ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch +# Implement more 'generic' operations using the EVP API. +# https://github.com/ruby/openssl/pull/329 +Patch41: ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch +# Allow setting algorithm-specific options in #sign and #verify. +# https://github.com/ruby/openssl/pull/374 +Patch42: ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch +# Use high level EVP interface to generate parameters and keys. +# https://github.com/ruby/openssl/pull/397 +Patch43: ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch +# Use EVP API in more places. +# https://github.com/ruby/openssl/pull/436 +Patch44: ruby-3.1.0-Use-EVP-API-in-more-places.patch +# Implement PKey#{encrypt,decrypt,sign_raw,verify_{raw,verify_recover}}. +# https://github.com/ruby/openssl/pull/382 +Patch45: ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch +# Fix `OpenSSL::TestSSL#test_dup` test failure. +# https://github.com/ruby/openssl/commit/7b66eaa2dbabb6570dbbbdfac24c4dcdcc6793d7 +Patch46: ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch +# Fix `OpenSSL::TestDigest#test_digest_constants` test case. +# https://github.com/ruby/openssl/commit/a3e59f4c2e200c76ef1d93945ff8737a05715e17 +Patch47: ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch +# Fix `OpenSSL::TestSSL#test_connect_certificate_verify_failed_exception_message` +# test case. +# https://github.com/ruby/openssl/commit/b5a0a198505452c7457b192da2e5cd5dda04f23d +Patch48: ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch +# Fix `OpenSSL::TestPKCS12#test_{new_with_no_keys,new_with_one_key_and_one_cert}` +# test failures. +# https://github.com/ruby/openssl/commit/998406d18f2acf73090e9fd9d92a7b4227ac593b +Patch49: ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch +# Fix `OpenSSL::TestPKey#test_s_generate_key` test case. +# https://github.com/ruby/openssl/commit/c732387ee5aaa8c5a9717e8b3ffebb3d7430e99a +Patch50: ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch +# Miscellaneous changes for OpenSSL 3.0 support. +# https://github.com/ruby/openssl/pull/468 +Patch51: ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch +# Support OpenSSL 3.0. +# https://github.com/ruby/openssl/pull/399 +Patch52: ruby-3.1.0-Support-OpenSSL-3.0.patch +# Fix `TestPumaControlCli#test_control_ssl` testcase in Puma. +# https://github.com/ruby/openssl/pull/399#issuecomment-966239736 +Patch53: ruby-3.1.0-SSL_read-EOF-handling.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -618,6 +683,24 @@ rm -rf ext/fiddle/libffi* %patch18 -p1 %patch19 -p1 %patch20 -p1 +%patch21 -p1 +%patch30 -p1 +%patch31 -p1 +%patch32 -p1 +%patch40 -p1 +%patch41 -p1 +%patch42 -p1 +%patch43 -p1 +%patch44 -p1 +%patch45 -p1 +%patch46 -p1 +%patch47 -p1 +%patch48 -p1 +%patch49 -p1 +%patch50 -p1 +%patch51 -p1 +%patch52 -p1 +%patch53 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -896,6 +979,13 @@ MSPECOPTS="" # Avoid `hostname' dependency. %{!?with_hostname:MSPECOPTS="-P 'Socket.gethostname returns the host name'"} +# Some tests are failing upstream due to OpenSSL 3.x compatibility. +# https://github.com/ruby/openssl/pull/399/checks?check_run_id=3716152870 +DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestEC#test_check_key/" +DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestPKeyDH#test_derive_key/" +DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestPKeyDH#test_key_exchange/" +DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" + # Give an option to increase the timeout in tests. # https://bugs.ruby-lang.org/issues/16921 %{?test_timeout_scale:RUBY_TEST_TIMEOUT_SCALE="%{test_timeout_scale}"} \ @@ -1374,6 +1464,10 @@ MSPECOPTS="" %changelog +* Fri Nov 05 2021 Vít Ondruch - 3.0.2-153 +- Fix OpenSSL 3.0 compatibility. + Resolves: rhbz#2021922 + * Tue Sep 14 2021 Sahana Prasad - Rebuilt with OpenSSL 3.0.0 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..4cd1752 --- /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 +@@ -476,7 +476,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.30-Switch-from-DES-CBC-to-AES-256-CBC.patch b/rubygems-3.2.30-Switch-from-DES-CBC-to-AES-256-CBC.patch new file mode 100644 index 0000000..e50f581 --- /dev/null +++ b/rubygems-3.2.30-Switch-from-DES-CBC-to-AES-256-CBC.patch @@ -0,0 +1,106 @@ +From 467be1c90bda755710943e9e2a42a42262dde909 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Thu, 14 Oct 2021 09:46:03 +0200 +Subject: [PATCH] Switch from DES-CBC to AES-256-CBC. + +DES-CBS is considered legacy and disabled in OpenSSL 3.x+ [[1], [2]]. +This cause causes Ruby test failures: + +~~~ +ruby -v: ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux] +/builddir/build/BUILD/ruby-3.0.2/lib/rubygems/test_case.rb:1542:in `initialize': Neither PUB key nor PRIV key (OpenSSL::PKey::RSAError) + from /builddir/build/BUILD/ruby-3.0.2/lib/rubygems/test_case.rb:1542:in `new' + from /builddir/build/BUILD/ruby-3.0.2/lib/rubygems/test_case.rb:1542:in `load_key' + from /builddir/build/BUILD/ruby-3.0.2/lib/rubygems/test_case.rb:1562:in `' + from /builddir/build/BUILD/ruby-3.0.2/lib/rubygems/test_case.rb:105:in `' + from :85:in `require' + from :85:in `require' + from /builddir/build/BUILD/ruby-3.0.2/test/rdoc/test_rdoc_rubygems_hook.rb:2:in `' + from :85:in `require' + from :85:in `require' + from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1049:in `block in non_options' + from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1043:in `each' + from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1043:in `non_options' + from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:65:in `process_args' + from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:143:in `process_args' + from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1237:in `process_args' + from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1242:in `run' + from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1249:in `run' + from /builddir/build/BUILD/ruby-3.0.2/tool/test/runner.rb:23:in `' + from ./test/runner.rb:11:in `require_relative' + from ./test/runner.rb:11:in `
' +~~~ + +Therefore use AES-256-CBC instead. This is essentially revert of +ca228b76b, which was fixing https://github.com/jruby/jruby/issues/919 + +[1]: https://github.com/openssl/openssl/blob/master/doc/man7/migration_guide.pod#legacy-algorithms +[2]: https://github.com/openssl/openssl/blob/master/doc/man7/OSSL_PROVIDER-legacy.pod +--- + test/rubygems/encrypted_private_key.pem | 52 ++++++++++++------------- + 1 file changed, 26 insertions(+), 26 deletions(-) + +diff --git a/test/rubygems/encrypted_private_key.pem b/test/rubygems/encrypted_private_key.pem +index 868f332b7c..d9667689a6 100644 +--- a/test/rubygems/encrypted_private_key.pem ++++ b/test/rubygems/encrypted_private_key.pem +@@ -1,30 +1,30 @@ + -----BEGIN RSA PRIVATE KEY----- + Proc-Type: 4,ENCRYPTED +-DEK-Info: DES-CBC,4E38D58B5A059DB6 ++DEK-Info: AES-256-CBC,CB6FD0B173EF450C6EE21A01DD785C1D + +-IgWLfnHVnkErKkhysrUMoE0ubkRDtJXZv9KR02jGGFk/kGqWyTqPk08uzhwVNM+l +-eOk0qfPykkJM3KZgqTsD6xfA1D5WqFp5mLoFXVVTn9I3acSZsqOY0FweCipwdVpI +-x+9Fl+v62kIW06dOjyWLE1abed9hHiXesGGsD87/RJSywy4OBxOcrhR1fJLK4ElR +-ya0UzI7rWnmZMChjaZBssfzT1DR79/dARXhon2m5EiIJDjMpc8BKGYlQy5RHCHwA +-cnrhUTTvsggZbQtmLZ/yVx8FSJ273XpYR0pmwbw4j1R+zeXQRK5MroBnCfOGcYa7 +-rmpERmDW3VAuxXR20SUAGdo1XOMTDe1uLbaotn6e56pXghIaYROTPS+HsuOkAZGY +-OYWEkUoyog4l4n+h/C1umFfTFGvKNATLgDugONFvTw/PLbjvl+sWMy2QfqH0MlNB +-DIUPxhEVCFD9oB4nfB86WDAmPp1DH9/IBet/21kbQ2eTIzakTdG3XiC+xzAQRu68 +-EOCTbasFWGxlCix66gt4xWMLksEg8UhWSpjS3/HsifrKyNMB8sfUFYmZmOYMW4mf +-NuEtpBL3AdHNObN8nQ75HfehukzNpbYVRsLzWrVgtxvXHVpnvoCCpCvQBMHeRZxK +-6m028mhH1m6yYE/uGFiRKLrN7BKAttbUiqnGgVIg/lQQilFWwylxQ6aXqJGmNgxa +-oihzWZRlXivIhhrM7VMnLoKAF/YfmWpP3zahGpBQGfObtPtm44R0ezXPdtsivnyu +-CmFOPGzRNMKZtH/lwVhuIIK3AFIGDsRRP9ySN4YfjQZnTdu2sRlxBnANP9m8W9T2 +-p+C4zVkDYAbsuWq2HpHwsdL8gqIiXeptsHLqkNw+ulSSLyeBCgM9fpV3RsNGjwqu +-k8QLb1CYp2VX46CE8UKvOd/nyFnEsD+EAc3WangEwA41m2IaXcbs9Au7xsG9oacZ +-DrxlJVNxlxO9YyP9dNOTfP0fHIiygKQQY2aU3y3oRneu7ogYES5V2mUNH7cYUWVL +-CHPXAoUXJErvDQ/opW2DroA9Eqv9sST6WqBf6LXRcWU0ntfzcFUbEqgmCmB7Cbu2 +-8udEn6iWilQahLyDoAShLkU7+Tk78Z1c6RuqjyY4VboZPzxrTYK8YIXzwX+jj9bG +-KIIGS5eghK185+AjlwtzJ7MBdoL323YIik6uOZluhnJHLaxjxUXGa1VqDgsyqGi7 +-ISRMTpVTrbR+UtoEi4ZhMjobtFUr7lGkt24VkXwBKdoyryj4RPHGdp7Tf6XDJufQ +-+KKhqt8QrpOTPiMskFN2disOSF5/YZCmtT84nkhU7Hf1lkQ2kfx1zfNk0GqYYXOW +-zHOAczy8gWBRetDMnhRYohDzQGWn//b+2Wr2n1RD8D9kyjMRhpFMYfQGfRcuPGjW +-91k/T0XFcjcjeZPL9s+HITmrh7zg5WxbCfTEp91j3Oy1bns196SY77TE0BzUsqR2 +-geJggcUMEfyvHiiCMtijmSSD9nf8tNIxLVL8Jaf1coA6e1CrlHnYAu2f/Q3GIcvU +-EEEmw+cZRwsk4fffYzh5psxxGdXKBv1KcQ/CeBhZL0WJsCp2y5oxwg== ++KqHn2Df8hSuwNE+W+60MnGtc6xpoXmF3iN25iVwcN67krYn+N6cBhjFeXwXccYwJ ++2gHSu4iEK9Qe32vK0yuv8N9h/fmsabZl0TotnEem/pqO5T8W4LxyK+Rw0s6RB30S ++C+mUisRADTanAxyBxsNU8xR8OAUNMAAxV1me6It0W2lfNE3t5jg/Kr0NWMoRUNRx ++dkE6WlD5D8jBeC3QdZ6OuE7QXOCEAWAjcFMc0d1WJq2t2r3TrLVfTH7EOoRyvL1H ++rrFRx/dEW1UJfM6P11wB5R0nhg3rDXF7oDFszjwO/3tzARke0NZuN37l301lYRl1 ++aolO6sShJLa0Ml/TgNcJw0S6rc6a1Z52gTfQKztKcL1UX4HLZg75zKmn6qfatMBC ++iXn+pQRYNsOPQ5h4r7lBBqvuV+gBw+rN768tYpZ2/YVDaygxETHcZAFCdAw/JNbP ++d0XPIbP79NRrCgzSo58LKQGuOQf3Hh0vp1YS+MilMtm/eogoj1enSPM+ymStHRwG ++i+D00xCQ6blSOZ2eUUBJXt11YzP22GYnv+XTR/5kGKkTIvoRMfd+39bQyR32IEv2 ++Z+yweAGQInD94eifT9ObbIayJ47y01KP0+Vj6hz4RCFsmJKsYiai5JiKlmf7lV9w ++7zH3TtCOx/xSyomesXVRkqvFkdyeguU72kXc5tiMPaDXGCOeV0GWyR1GU1DUX9/K ++60E7ym0Wx77WGMKk2fkirZzBdOeliyCRUXd7ccN2rBCjTwtjAUIk27lwzdUaTUv7 ++EmjauDvSMFtir58c+zjlLmBaSQOzKcj0KXMp0Oucls9bD85WGGbGyzGhTa0AZ+/+ ++cCEJt7RAwW0kTEO/uO+BAZe/zBoi9ek+QBn54FK3E7CXfS4Oi9Qbc3fwlVyTlVmz ++ZGrCncO0TIVGErFWK24Z7lX8rBnk8enfnamrPfKtwn4LG9aDfhSj8DtisjlRUVT5 ++chDQ+CCi9rh3wXh28lyS+nXJ3yFidCzRgcsc3PpN/c4DNRggZc+C/KDw+J2FW+8Y ++p65OliBQHQcG0PnCa2xRyCGevytPG0rfNDgyaY33dPEo90mBLVcwLbzGiSGBHgFl ++pr8A/rqbnFpRO39NYbACeRFCqPpzyzfARCCcjcDoFrENdIaJui0fjlBkoV3B/KiK ++EVjDcgwt1HAtz8bV2YJ+OpQbhD7E90e2vTRMuXAH21Ygo32VOS0LRlCRc9ZyZW4z ++PTyO/6a+FbXZ1zhVJxu/0bmBERZ14WVmWq56oxQav8knpxYeYPgpEmIZnrHnJ1Ko ++UoXcc8Hy4NKtaBmDcaF8TCobNsRZTxO/htqpdyNsOrBSsnX2kP5D/O1l1vuVYi1/ ++RYfUqL9dvGzvfsFuuDDjDlQ/fIA6pFzJV3fy4KJHlF1r33qaE/lNMdpKljBwvUII ++Vog4cGmzxssqK5q9kuogcuyeOuFODjBNW4qt0WylSi9bwwy3ZwaZLRqhngz6+tCV ++Jp45Gk881XiVe3aVU0l+4DmJJ9/5vwqjH5Vo/GJqFU6gzB+Zv/0plYeNkuE0Xo2z ++ecdxnGKVPl42q44lvczjDw2KX0ahxQrfrbcl48//zR295u9POzCL97d6zpioI2NR + -----END RSA PRIVATE KEY----- +-- +2.32.0 + diff --git a/rubygems-3.2.30-Use-OpenSSL-constants-for-error-codes.patch b/rubygems-3.2.30-Use-OpenSSL-constants-for-error-codes.patch new file mode 100644 index 0000000..8fe139e --- /dev/null +++ b/rubygems-3.2.30-Use-OpenSSL-constants-for-error-codes.patch @@ -0,0 +1,75 @@ +From 8acf8e95dcaebe227f779271b8213c15eceb846f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Mon, 1 Nov 2021 18:40:06 +0100 +Subject: [PATCH] Use OpenSSL constants for error codes. + +This fixes the following test error testing against OpenSSL 3.x: + +~~~ + 2) Failure: +TestGemRequest#test_verify_certificate_extra_message [/builddir/build/BUILD/ruby-3.0.2/test/rubygems/test_gem_request.rb:358]: +<"ERROR: SSL verification error at depth 0: invalid CA certificate (24)\n" + +"ERROR: Certificate is an invalid CA certificate\n"> expected but was +<"ERROR: SSL verification error at depth 0: invalid CA certificate (79)\n" + +"ERROR: Certificate is an invalid CA certificate\n">. +~~~ + +Where the root cause is this OpenSSL commit: + +https://github.com/openssl/openssl/commit/1e41dadfa7b9f792ed0f4714a3d3d36f070cf30e + +It seems that OpenSSL upstream considers the constant value just an +implementation detail and therefore this changes the test case to +follow the suite. +--- + test/rubygems/test_gem_request.rb | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/test/rubygems/test_gem_request.rb b/test/rubygems/test_gem_request.rb +index 66477be7bc..47654f6fa4 100644 +--- a/test/rubygems/test_gem_request.rb ++++ b/test/rubygems/test_gem_request.rb +@@ -328,30 +328,36 @@ def test_user_agent_revision_missing + + def test_verify_certificate + pend if Gem.java_platform? ++ ++ error_number = OpenSSL::X509::V_ERR_OUT_OF_MEM ++ + store = OpenSSL::X509::Store.new + context = OpenSSL::X509::StoreContext.new store +- context.error = OpenSSL::X509::V_ERR_OUT_OF_MEM ++ context.error = error_number + + use_ui @ui do + Gem::Request.verify_certificate context + end + +- assert_equal "ERROR: SSL verification error at depth 0: out of memory (17)\n", ++ assert_equal "ERROR: SSL verification error at depth 0: out of memory (#{error_number})\n", + @ui.error + end + + def test_verify_certificate_extra_message + pend if Gem.java_platform? ++ ++ error_number = OpenSSL::X509::V_ERR_INVALID_CA ++ + store = OpenSSL::X509::Store.new + context = OpenSSL::X509::StoreContext.new store +- context.error = OpenSSL::X509::V_ERR_INVALID_CA ++ context.error = error_number + + use_ui @ui do + Gem::Request.verify_certificate context + end + + expected = <<-ERROR +-ERROR: SSL verification error at depth 0: invalid CA certificate (24) ++ERROR: SSL verification error at depth 0: invalid CA certificate (#{error_number}) + ERROR: Certificate is an invalid CA certificate + ERROR + +-- +2.32.0 + From d584a5bfb39b8c0aad7d644ac85d9e48e3bcc814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Thu, 25 Nov 2021 17:46:12 +0100 Subject: [PATCH 015/141] Upgrade to Ruby 3.0.3. --- ruby-2.1.0-custom-rubygems-location.patch | 4 +- ruby-2.3.0-ruby_version.patch | 8 +- ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch | 2 +- ...onf.rb-require-OpenSSL-version-1.0.1.patch | 84 ++++++++++++++ ...et-rid-of-type-punning-pointer-casts.patch | 16 +-- ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch | 4 +- ...gn_raw-verify_raw-and-verify_recover.patch | 16 +-- ...eous-changes-for-OpenSSL-3.0-support.patch | 4 +- ruby-3.1.0-Properly-exclude-test-cases.patch | 2 +- ruby-3.1.0-SSL_read-EOF-handling.patch | 2 +- ...h => ruby-3.1.0-Support-GCCs-DWARF-5.patch | 44 +++++--- ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch | 2 +- ...t_ssl-relax-regex-to-match-OpenSSL-s.patch | 2 +- ...tils-remove-dup_public-helper-method.patch | 2 +- ruby.spec | 83 +++++++------- ...load-user-installed-rubygems-plugins.patch | 61 ---------- ...ished-name-which-will-be-correctly-p.patch | 2 +- ...0-Switch-from-DES-CBC-to-AES-256-CBC.patch | 106 ------------------ ...se-OpenSSL-constants-for-error-codes.patch | 75 ------------- sources | 2 +- 20 files changed, 185 insertions(+), 336 deletions(-) create mode 100644 ruby-3.0.3-ext-openssl-extconf.rb-require-OpenSSL-version-1.0.1.patch rename ruby-dwarf5-avoid_crash-r1.patch => ruby-3.1.0-Support-GCCs-DWARF-5.patch (80%) delete mode 100644 rubygems-3.2.26-Also-load-user-installed-rubygems-plugins.patch delete mode 100644 rubygems-3.2.30-Switch-from-DES-CBC-to-AES-256-CBC.patch delete mode 100644 rubygems-3.2.30-Use-OpenSSL-constants-for-error-codes.patch diff --git a/ruby-2.1.0-custom-rubygems-location.patch b/ruby-2.1.0-custom-rubygems-location.patch index b7157ff..f7862fa 100644 --- a/ruby-2.1.0-custom-rubygems-location.patch +++ b/ruby-2.1.0-custom-rubygems-location.patch @@ -26,7 +26,7 @@ index 93af30321d..bc13397e0e 100644 AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) RUBY_EXEC_PREFIX='' -@@ -3941,6 +3941,7 @@ AC_SUBST(sitearchdir)dnl +@@ -3941,6 +3945,7 @@ AC_SUBST(sitearchdir)dnl AC_SUBST(vendordir)dnl AC_SUBST(vendorlibdir)dnl AC_SUBST(vendorarchdir)dnl @@ -75,7 +75,7 @@ index e9110a17ca..76a1f0a315 100755 mandir = CONFIG["mandir", true] docdir = CONFIG["docdir", true] enable_shared = CONFIG["ENABLE_SHARED"] == 'yes' -@@ -581,7 +581,16 @@ def stub +@@ -581,7 +582,16 @@ def stub install?(:local, :comm, :lib) do prepare "library scripts", rubylibdir noinst = %w[*.txt *.rdoc *.gemspec] diff --git a/ruby-2.3.0-ruby_version.patch b/ruby-2.3.0-ruby_version.patch index 4fd6530..b0a73a9 100644 --- a/ruby-2.3.0-ruby_version.patch +++ b/ruby-2.3.0-ruby_version.patch @@ -30,7 +30,7 @@ index 80b137e380..63cd3b4f8b 100644 rubyarchprefix=${multiarch+'${archlibdir}/${RUBY_BASE_NAME}'}${multiarch-'${rubylibprefix}/${arch}'} AC_ARG_WITH(rubyarchprefix, AS_HELP_STRING([--with-rubyarchprefix=DIR], -@@ -3857,56 +3857,62 @@ AC_ARG_WITH(ridir, +@@ -3857,56 +3854,62 @@ AC_ARG_WITH(ridir, AC_SUBST(ridir) AC_SUBST(RI_BASE_NAME) @@ -120,7 +120,7 @@ index 80b137e380..63cd3b4f8b 100644 AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) -@@ -3923,6 +3923,7 @@ AC_SUBST(sitearchincludedir)dnl +@@ -3923,6 +3926,7 @@ AC_SUBST(sitearchincludedir)dnl AC_SUBST(arch)dnl AC_SUBST(sitearch)dnl AC_SUBST(ruby_version)dnl @@ -237,7 +237,7 @@ diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index b25068405d..e9fef4a311 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb -@@ -1452,7 +1452,8 @@ def test_self_use_paths +@@ -1440,7 +1440,8 @@ def test_self_use_paths def test_self_user_dir parts = [@userhome, '.gem', Gem.ruby_engine] @@ -247,7 +247,7 @@ index b25068405d..e9fef4a311 100644 FileUtils.mkdir_p File.join(parts) -@@ -1530,7 +1531,7 @@ def test_self_vendor_dir +@@ -1516,7 +1517,7 @@ def test_self_vendor_dir vendordir(File.join(@tempdir, 'vendor')) do expected = File.join RbConfig::CONFIG['vendordir'], 'gems', diff --git a/ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch b/ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch index db6737d..599a6e6 100644 --- a/ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch +++ b/ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch @@ -8,7 +8,7 @@ on Red Hat platforms. This workaround rhbz#1361037 --- - test/fiddle/helper.rb | 3 +++ + test/fiddle/helper.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/fiddle/helper.rb b/test/fiddle/helper.rb 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.1.0-Get-rid-of-type-punning-pointer-casts.patch b/ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch index b5c80ad..ae8f722 100644 --- 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 @@ -6,7 +6,7 @@ Subject: [PATCH] Get rid of type-punning pointer casts [Bug #18062] --- vm_eval.c | 4 +++- vm_insnhelper.c | 7 +++++-- - vm_method.c | 41 +++++++++++++++++++++++++--------------- + vm_method.c | 41 ++++++++++++++++++++++++++--------------- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/vm_eval.c b/vm_eval.c @@ -30,7 +30,7 @@ diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 14928b2afe8e..e186376b24d7 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c -@@ -1636,9 +1636,11 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci) +@@ -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; @@ -43,7 +43,7 @@ index 14928b2afe8e..e186376b24d7 100644 const int ccs_len = ccs->len; VM_ASSERT(vm_ccs_verify(ccs, mid, klass)); -@@ -1705,8 +1707,9 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci) +@@ -1706,8 +1708,9 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci) if (ccs == NULL) { VM_ASSERT(cc_tbl != NULL); @@ -123,7 +123,7 @@ index 016dba1dbb18..1fd0bd57f7ca 100644 RB_DEBUG_COUNTER_INC(cc_invalidate_negative); } -@@ -1023,6 +1024,7 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_ +@@ -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; @@ -131,7 +131,7 @@ index 016dba1dbb18..1fd0bd57f7ca 100644 if (me) { if (me->defined_class == 0) { -@@ -1032,7 +1034,8 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_ +@@ -1032,7 +1035,8 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_ mtbl = RCLASS_CALLABLE_M_TBL(defined_class); @@ -141,7 +141,7 @@ index 016dba1dbb18..1fd0bd57f7ca 100644 RB_DEBUG_COUNTER_INC(mc_cme_complement_hit); VM_ASSERT(callable_method_entry_p(cme)); VM_ASSERT(!METHOD_ENTRY_INVALIDATED(cme)); -@@ -1076,9 +1079,10 @@ cached_callable_method_entry(VALUE klass, ID mid) +@@ -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); @@ -154,7 +154,7 @@ index 016dba1dbb18..1fd0bd57f7ca 100644 VM_ASSERT(vm_ccs_p(ccs)); if (LIKELY(!METHOD_ENTRY_INVALIDATED(ccs->cme))) { -@@ -1104,12 +1108,14 @@ cache_callable_method_entry(VALUE klass, ID mid, const rb_callable_method_entry_ +@@ -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; @@ -170,7 +170,7 @@ index 016dba1dbb18..1fd0bd57f7ca 100644 VM_ASSERT(ccs->cme == cme); } else { -@@ -1123,8 +1129,12 @@ negative_cme(ID mid) +@@ -1123,8 +1130,12 @@ negative_cme(ID mid) { rb_vm_t *vm = GET_VM(); const rb_callable_method_entry_t *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 index 9d218e5..86f534d 100644 --- a/ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch +++ b/ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch @@ -13,7 +13,7 @@ diff --git a/addr2line.c b/addr2line.c index fed1a8da84e5..92c6da5e3bea 100644 --- a/addr2line.c +++ b/addr2line.c -@@ -1592,14 +1592,31 @@ di_read_cu(DebugInfoReader *reader) +@@ -1593,14 +1593,31 @@ di_read_cu(DebugInfoReader *reader) } static void @@ -47,7 +47,7 @@ index fed1a8da84e5..92c6da5e3bea 100644 if (!di_read_die(reader, &die)) goto finish; /* enumerate abbrev */ -@@ -1664,7 +1681,7 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces, +@@ -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: 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 index afb3a87..a558cec 100644 --- 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 @@ -1100,15 +1100,15 @@ index 829529d4b9..f52e67079d 100644 - StringValue(data); - StringValue(sig); - -- switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(sig), (int)RSTRING_LEN(sig), ec)) { -- case 1: return Qtrue; -- case 0: return Qfalse; -- default: break; +- 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"); - } -- -- ossl_raise(eECError, "ECDSA_verify"); -- -- UNREACHABLE; -} - /* 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 index 3a0e03b..f03f28a 100644 --- 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 @@ -95,7 +95,7 @@ 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 -@@ -816,7 +816,7 @@ ossl_ts_resp_verify(int argc, VALUE *argv, VALUE self) +@@ -820,7 +820,7 @@ ossl_ts_resp_verify(int argc, VALUE *argv, VALUE self) X509_up_ref(cert); } @@ -126,7 +126,7 @@ 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 -@@ -1522,8 +1522,8 @@ ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) +@@ -1535,8 +1535,8 @@ ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) static inline int ssl_started(SSL *ssl) { diff --git a/ruby-3.1.0-Properly-exclude-test-cases.patch b/ruby-3.1.0-Properly-exclude-test-cases.patch index 3b88433..ca2cd9b 100644 --- a/ruby-3.1.0-Properly-exclude-test-cases.patch +++ b/ruby-3.1.0-Properly-exclude-test-cases.patch @@ -63,7 +63,7 @@ method name. This resolves [Bug #16936]. --- tool/lib/minitest/unit.rb | 12 +++++++++--- - 1 file changed, 9 insertion(+), 3 deletion(-) + 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 diff --git a/ruby-3.1.0-SSL_read-EOF-handling.patch b/ruby-3.1.0-SSL_read-EOF-handling.patch index fb08773..1c5660f 100644 --- a/ruby-3.1.0-SSL_read-EOF-handling.patch +++ b/ruby-3.1.0-SSL_read-EOF-handling.patch @@ -2,7 +2,7 @@ diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 3b425ca..40e748c 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c -@@ -1844,6 +1844,11 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) +@@ -1870,6 +1870,11 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) return str; GetSSL(self, ssl); diff --git a/ruby-dwarf5-avoid_crash-r1.patch b/ruby-3.1.0-Support-GCCs-DWARF-5.patch similarity index 80% rename from ruby-dwarf5-avoid_crash-r1.patch rename to ruby-3.1.0-Support-GCCs-DWARF-5.patch index c14642b..d9b434a 100644 --- a/ruby-dwarf5-avoid_crash-r1.patch +++ b/ruby-3.1.0-Support-GCCs-DWARF-5.patch @@ -1,6 +1,18 @@ +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 @@ +@@ -159,11 +159,12 @@ typedef struct obj_info { struct dwarf_section debug_info; struct dwarf_section debug_line; struct dwarf_section debug_ranges; @@ -14,7 +26,7 @@ static struct dwarf_section * obj_dwarf_section_at(obj_info_t *obj, int n) -@@ -173,6 +174,7 @@ +@@ -173,6 +174,7 @@ obj_dwarf_section_at(obj_info_t *obj, int n) &obj->debug_info, &obj->debug_line, &obj->debug_ranges, @@ -22,7 +34,7 @@ &obj->debug_str }; if (n < 0 || DWARF_SECTION_COUNT <= n) { -@@ -411,7 +413,7 @@ +@@ -411,7 +413,7 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line, FILL_LINE(); break; case DW_LNS_advance_pc: @@ -31,7 +43,7 @@ addr += a; break; case DW_LNS_advance_line: { -@@ -450,7 +452,7 @@ +@@ -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: @@ -40,7 +52,7 @@ op = *p++; switch (op) { case DW_LNE_end_sequence: -@@ -807,6 +809,18 @@ +@@ -808,6 +810,18 @@ enum DW_FORM_addrx4 = 0x2c }; @@ -59,10 +71,11 @@ enum { VAL_none = 0, VAL_cstr = 1, -@@ -961,6 +975,23 @@ +@@ -961,6 +975,23 @@ debug_info_reader_init(DebugInfoReader *reader, obj_info_t *obj) + reader->current_low_pc = 0; } - static void ++static void +di_skip_die_attributes(char **p) +{ + for (;;) { @@ -79,11 +92,10 @@ + } +} + -+static void + static void di_read_debug_abbrev_cu(DebugInfoReader *reader) { - uint64_t prev = 0; -@@ -974,12 +1005,7 @@ +@@ -975,12 +1006,7 @@ di_read_debug_abbrev_cu(DebugInfoReader *reader) prev = abbrev_number; uleb128(&p); /* tag */ p++; /* has_children */ @@ -97,7 +109,7 @@ } } -@@ -1243,12 +1269,7 @@ +@@ -1244,12 +1270,7 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number) /* skip 255th record */ uleb128(&p); /* tag */ p++; /* has_children */ @@ -111,7 +123,7 @@ 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); -@@ -1256,12 +1277,7 @@ +@@ -1257,12 +1278,7 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number) } uleb128(&p); /* tag */ p++; /* has_children */ @@ -125,7 +137,7 @@ } return p; } -@@ -1389,6 +1405,21 @@ +@@ -1390,6 +1406,21 @@ ranges_set(ranges_t *ptr, DebugInfoValue *v) } } @@ -147,7 +159,7 @@ static uintptr_t ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr) { -@@ -1402,8 +1433,50 @@ +@@ -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 */ @@ -199,7 +211,7 @@ for (;;) { uintptr_t from = read_uintptr(&p); uintptr_t to = read_uintptr(&p); -@@ -1747,6 +1820,7 @@ +@@ -1750,6 +1823,7 @@ fill_lines(int num_traces, void **traces, int check_debuglink, ".debug_info", ".debug_line", ".debug_ranges", @@ -207,7 +219,7 @@ ".debug_str" }; -@@ -2003,6 +2077,7 @@ +@@ -2006,6 +2080,7 @@ found_mach_header: "__debug_info", "__debug_line", "__debug_ranges", diff --git a/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch b/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch index 74636e5..b8f727d 100644 --- a/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch +++ b/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch @@ -11,7 +11,7 @@ diff --git a/addr2line.c b/addr2line.c index 8ee4416650d3..fed1a8da84e5 100644 --- a/addr2line.c +++ b/addr2line.c -@@ -1137,12 +1137,12 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa +@@ -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: 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 index f638047..c9421bc 100644 --- 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 @@ -15,7 +15,7 @@ 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 -@@ -955,7 +955,9 @@ def test_connect_certificate_verify_failed_exception_message +@@ -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 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 index 23c73ba..2019380 100644 --- 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 @@ -227,7 +227,7 @@ 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 -@@ -305,32 +305,6 @@ def check_component(base, test, keys) +@@ -313,32 +313,6 @@ def check_component(base, test, keys) assert_equal base.send(comp), test.send(comp) } end diff --git a/ruby.spec b/ruby.spec index d0bb381..7530e95 100644 --- a/ruby.spec +++ b/ruby.spec @@ -1,6 +1,6 @@ %global major_version 3 %global minor_version 0 -%global teeny_version 2 +%global teeny_version 3 %global major_minor_version %{major_version}.%{minor_version} %global ruby_version %{major_minor_version}.%{teeny_version} @@ -22,7 +22,7 @@ %endif -%global release 153 +%global release 154 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -30,12 +30,12 @@ %global rubygems_dir %{_datadir}/rubygems # Bundled libraries versions -%global rubygems_version 3.2.22 +%global rubygems_version 3.2.32 %global rubygems_molinillo_version 0.7.0 # Default gems. -%global bundler_version 2.2.22 -%global bundler_connection_pool_version 2.2.2 +%global bundler_version 2.2.32 +%global bundler_connection_pool_version 2.3.0 %global bundler_fileutils_version 1.4.1 %global bundler_molinillo_version 0.7.0 %global bundler_net_http_persistent_version 4.0.0 @@ -49,20 +49,20 @@ %global io_console_version 0.5.7 %global irb_version 1.3.5 %global json_version 2.5.1 -%global openssl_version 2.2.0 -%global psych_version 3.3.0 -%global racc_version 1.5.1 -%global rdoc_version 6.3.1 +%global openssl_version 2.2.1 +%global psych_version 3.3.2 +%global racc_version 1.5.2 +%global rdoc_version 6.3.3 # Bundled gems. %global minitest_version 5.14.2 %global power_assert_version 1.2.0 %global rake_version 13.0.3 -%global rbs_version 1.0.4 +%global rbs_version 1.4.0 %global test_unit_version 3.3.7 %global rexml_version 3.2.5 %global rss_version 0.2.9 -%global typeprof_version 0.12.0 +%global typeprof_version 0.15.2 %global tapset_libdir %(echo %{_libdir} | sed 's/64//')* @@ -142,13 +142,11 @@ Patch6: ruby-2.7.0-Initialize-ABRT-hook.patch # hardening features of glibc (rhbz#1361037). # https://bugs.ruby-lang.org/issues/12666 Patch9: ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch -# Load user installed RubyGems plugins. -# https://github.com/rubygems/rubygems/issues/4823 -Patch10: rubygems-3.2.26-Also-load-user-installed-rubygems-plugins.patch # Fix DWARF5 support. # https://bugzilla.redhat.com/show_bug.cgi?id=1920533 # https://bugs.ruby-lang.org/issues/17585 -Patch15: ruby-dwarf5-avoid_crash-r1.patch +# https://github.com/ruby/ruby/pull/4240 +Patch15: ruby-3.1.0-Support-GCCs-DWARF-5.patch # Fix segfaults with enabled LTO. # https://bugs.ruby-lang.org/issues/18062 # https://github.com/ruby/ruby/pull/4716 @@ -175,18 +173,15 @@ Patch21: ruby-3.1.0-Properly-exclude-test-cases.patch # OpenSSL 3.0 compatibility patches -# Switch from legacy DES-CBC to AES-256-CBC. -# https://github.com/rubygems/rubygems/pull/4986 -Patch30: rubygems-3.2.30-Switch-from-DES-CBC-to-AES-256-CBC.patch +# Revert OpenSSL < 3.x enforcement. +# https://github.com/ruby/openssl/commit/202ff1372a40a8adf9aac74bfe8a39141b0c57e5 +Patch30: ruby-3.0.3-ext-openssl-extconf.rb-require-OpenSSL-version-1.0.1.patch + # Fix test broken by wrongly formatted distinguished name submitted to # `OpenSSL::X509::Name.parse`. # https://github.com/ruby/openssl/issues/470 # https://github.com/rubygems/rubygems/pull/5030 Patch31: rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch -# Fix TestGemRequest#test_verify_certificate_extra_message compatibility -# with OpenSSL 3.x. -# https://github.com/rubygems/rubygems/pull/5040 -Patch32: rubygems-3.2.30-Use-OpenSSL-constants-for-error-codes.patch # Refactor PEM/DER serialization code. # https://github.com/ruby/openssl/pull/328 @@ -676,7 +671,6 @@ rm -rf ext/fiddle/libffi* %patch5 -p1 %patch6 -p1 %patch9 -p1 -%patch10 -p1 %patch15 -p1 %patch16 -p1 %patch17 -p1 @@ -684,9 +678,8 @@ rm -rf ext/fiddle/libffi* %patch19 -p1 %patch20 -p1 %patch21 -p1 -%patch30 -p1 +%patch30 -p1 -R %patch31 -p1 -%patch32 -p1 %patch40 -p1 %patch41 -p1 %patch42 -p1 @@ -1243,30 +1236,30 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" %{_rpmconfigdir}/rubygems.con %files default-gems -%{gem_dir}/specifications/default/english-0.7.1.gemspec %{gem_dir}/specifications/default/abbrev-0.1.0.gemspec %{gem_dir}/specifications/default/base64-0.1.0.gemspec %{gem_dir}/specifications/default/benchmark-0.1.1.gemspec -%{gem_dir}/specifications/default/cgi-0.2.0.gemspec +%{gem_dir}/specifications/default/cgi-0.2.1.gemspec %{gem_dir}/specifications/default/csv-3.1.9.gemspec -%{gem_dir}/specifications/default/date-3.1.0.gemspec +%{gem_dir}/specifications/default/date-3.1.3.gemspec %{gem_dir}/specifications/default/dbm-1.1.0.gemspec -%{gem_dir}/specifications/default/debug-0.1.0.gemspec +%{gem_dir}/specifications/default/debug-0.2.1.gemspec %{gem_dir}/specifications/default/delegate-0.2.0.gemspec %{gem_dir}/specifications/default/did_you_mean-%{did_you_mean_version}.gemspec %{gem_dir}/specifications/default/digest-3.0.0.gemspec -%{gem_dir}/specifications/default/drb-2.0.4.gemspec +%{gem_dir}/specifications/default/drb-2.0.5.gemspec +%{gem_dir}/specifications/default/english-0.7.1.gemspec %{gem_dir}/specifications/default/erb-%{erb_version}.gemspec -%{gem_dir}/specifications/default/etc-1.2.0.gemspec -%{gem_dir}/specifications/default/fcntl-1.0.0.gemspec -%{gem_dir}/specifications/default/fiddle-1.0.6.gemspec +%{gem_dir}/specifications/default/etc-1.3.0.gemspec +%{gem_dir}/specifications/default/fcntl-1.0.1.gemspec +%{gem_dir}/specifications/default/fiddle-1.0.8.gemspec %{gem_dir}/specifications/default/fileutils-1.5.0.gemspec %{gem_dir}/specifications/default/find-0.1.0.gemspec %{gem_dir}/specifications/default/forwardable-1.3.2.gemspec %{gem_dir}/specifications/default/gdbm-2.1.0.gemspec %{gem_dir}/specifications/default/getoptlong-0.1.1.gemspec %{gem_dir}/specifications/default/io-nonblock-0.1.0.gemspec -%{gem_dir}/specifications/default/io-wait-0.1.0.gemspec +%{gem_dir}/specifications/default/io-wait-0.2.0.gemspec %{gem_dir}/specifications/default/ipaddr-1.2.2.gemspec %{gem_dir}/specifications/default/logger-1.4.3.gemspec %{gem_dir}/specifications/default/matrix-0.3.1.gemspec @@ -1275,33 +1268,33 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" %{gem_dir}/specifications/default/net-http-0.1.1.gemspec %{gem_dir}/specifications/default/net-imap-0.1.1.gemspec %{gem_dir}/specifications/default/net-pop-0.1.1.gemspec -%{gem_dir}/specifications/default/net-protocol-0.1.0.gemspec +%{gem_dir}/specifications/default/net-protocol-0.1.1.gemspec %{gem_dir}/specifications/default/net-smtp-0.2.1.gemspec %{gem_dir}/specifications/default/nkf-0.1.0.gemspec %{gem_dir}/specifications/default/observer-0.1.1.gemspec %{gem_dir}/specifications/default/open3-0.1.1.gemspec %{gem_dir}/specifications/default/open-uri-0.1.0.gemspec -%{gem_dir}/specifications/default/optparse-0.1.0.gemspec +%{gem_dir}/specifications/default/optparse-0.1.1.gemspec %{gem_dir}/specifications/default/openssl-%{openssl_version}.gemspec %{gem_dir}/specifications/default/ostruct-0.3.1.gemspec %{gem_dir}/specifications/default/pathname-0.1.0.gemspec -%{gem_dir}/specifications/default/pp-0.1.0.gemspec -%{gem_dir}/specifications/default/prettyprint-0.1.0.gemspec +%{gem_dir}/specifications/default/pp-0.2.1.gemspec +%{gem_dir}/specifications/default/prettyprint-0.1.1.gemspec %{gem_dir}/specifications/default/prime-0.1.2.gemspec %{gem_dir}/specifications/default/pstore-0.1.1.gemspec %{gem_dir}/specifications/default/racc-%{racc_version}.gemspec %{gem_dir}/specifications/default/readline-0.0.2.gemspec %{gem_dir}/specifications/default/readline-ext-0.1.1.gemspec %{gem_dir}/specifications/default/reline-0.2.5.gemspec -%{gem_dir}/specifications/default/resolv-0.2.0.gemspec +%{gem_dir}/specifications/default/resolv-0.2.1.gemspec %{gem_dir}/specifications/default/resolv-replace-0.1.0.gemspec -%{gem_dir}/specifications/default/rinda-0.1.0.gemspec +%{gem_dir}/specifications/default/rinda-0.1.1.gemspec %{gem_dir}/specifications/default/securerandom-0.1.0.gemspec %{gem_dir}/specifications/default/set-1.0.1.gemspec %{gem_dir}/specifications/default/shellwords-0.1.0.gemspec %{gem_dir}/specifications/default/singleton-0.1.1.gemspec -%{gem_dir}/specifications/default/stringio-3.0.0.gemspec -%{gem_dir}/specifications/default/strscan-3.0.0.gemspec +%{gem_dir}/specifications/default/stringio-3.0.1.gemspec +%{gem_dir}/specifications/default/strscan-3.0.1.gemspec %{gem_dir}/specifications/default/syslog-0.1.0.gemspec %{gem_dir}/specifications/default/tempfile-0.1.1.gemspec %{gem_dir}/specifications/default/time-0.1.0.gemspec @@ -1314,7 +1307,7 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" %{gem_dir}/specifications/default/weakref-0.1.1.gemspec #%%{gem_dir}/specifications/default/win32ole-1.8.8.gemspec %{gem_dir}/specifications/default/yaml-0.1.1.gemspec -%{gem_dir}/specifications/default/zlib-1.1.0.gemspec +%{gem_dir}/specifications/default/zlib-2.0.0.gemspec %{gem_dir}/gems/erb-%{erb_version} # Use standalone rubygem-racc if Racc binary is required. Shipping this @@ -1408,7 +1401,6 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" %doc %{gem_dir}/gems/rbs-%{rbs_version}/README.md %{gem_dir}/gems/rbs-%{rbs_version}/Rakefile %{gem_dir}/gems/rbs-%{rbs_version}/Steepfile -%{gem_dir}/gems/rbs-%{rbs_version}/bin %{gem_dir}/gems/rbs-%{rbs_version}/core %doc %{gem_dir}/gems/rbs-%{rbs_version}/docs %{gem_dir}/gems/rbs-%{rbs_version}/exe @@ -1464,6 +1456,9 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" %changelog +* Thu Nov 25 2021 Vít Ondruch - 3.0.2-154 +- Upgrade to Ruby 3.0.3. + * Fri Nov 05 2021 Vít Ondruch - 3.0.2-153 - Fix OpenSSL 3.0 compatibility. Resolves: rhbz#2021922 diff --git a/rubygems-3.2.26-Also-load-user-installed-rubygems-plugins.patch b/rubygems-3.2.26-Also-load-user-installed-rubygems-plugins.patch deleted file mode 100644 index 7af6df6..0000000 --- a/rubygems-3.2.26-Also-load-user-installed-rubygems-plugins.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 82960c262fea081cdd3df14ebe573ff1c4925d0c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?David=20Rodr=C3=ADguez?= -Date: Fri, 6 Aug 2021 12:21:23 +0200 -Subject: [PATCH] Also load user installed rubygems plugins - ---- - lib/rubygems.rb | 4 +++- - test/rubygems/test_gem.rb | 25 +++++++++++++++++++++++++ - 2 files changed, 28 insertions(+), 1 deletion(-) - -diff --git a/lib/rubygems.rb b/lib/rubygems.rb -index a631cde8bf8..17881e2e0e9 100644 ---- a/lib/rubygems.rb -+++ b/lib/rubygems.rb -@@ -1063,7 +1063,9 @@ def self.load_plugin_files(plugins) # :nodoc: - # Find rubygems plugin files in the standard location and load them - - def self.load_plugins -- load_plugin_files Gem::Util.glob_files_in_dir("*#{Gem.plugin_suffix_pattern}", plugindir) -+ Gem.path.each do |gem_path| -+ load_plugin_files Gem::Util.glob_files_in_dir("*#{Gem.plugin_suffix_pattern}", plugindir(gem_path)) -+ end - end - - ## -diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb -index 0d4b1571ca7..da154dac75b 100644 ---- a/test/rubygems/test_gem.rb -+++ b/test/rubygems/test_gem.rb -@@ -1581,6 +1581,31 @@ def test_load_plugins - assert_equal %w[plugin], PLUGINS_LOADED - end - -+ def test_load_user_installed_plugins -+ plugin_path = File.join "lib", "rubygems_plugin.rb" -+ -+ Dir.chdir @tempdir do -+ FileUtils.mkdir_p 'lib' -+ File.open plugin_path, "w" do |fp| -+ fp.puts "class TestGem; PLUGINS_LOADED << 'plugin'; end" -+ end -+ -+ foo = util_spec 'foo', '1' do |s| -+ s.files << plugin_path -+ end -+ -+ install_gem_user foo -+ end -+ -+ Gem.paths = { "GEM_PATH" => [Gem.dir, Gem.user_dir].join(File::PATH_SEPARATOR) } -+ -+ gem 'foo' -+ -+ Gem.load_plugins -+ -+ assert_equal %w[plugin], PLUGINS_LOADED -+ end -+ - def test_load_env_plugins - with_plugin('load') { Gem.load_env_plugins } - assert_equal :loaded, TEST_PLUGIN_LOAD rescue nil 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 index 4cd1752..433d03e 100644 --- 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 @@ -30,7 +30,7 @@ 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 -@@ -476,7 +476,7 @@ def self.email_to_name(email_address) +@@ -510,7 +510,7 @@ def self.email_to_name(email_address) dcs = dcs.split '.' diff --git a/rubygems-3.2.30-Switch-from-DES-CBC-to-AES-256-CBC.patch b/rubygems-3.2.30-Switch-from-DES-CBC-to-AES-256-CBC.patch deleted file mode 100644 index e50f581..0000000 --- a/rubygems-3.2.30-Switch-from-DES-CBC-to-AES-256-CBC.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 467be1c90bda755710943e9e2a42a42262dde909 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Thu, 14 Oct 2021 09:46:03 +0200 -Subject: [PATCH] Switch from DES-CBC to AES-256-CBC. - -DES-CBS is considered legacy and disabled in OpenSSL 3.x+ [[1], [2]]. -This cause causes Ruby test failures: - -~~~ -ruby -v: ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux] -/builddir/build/BUILD/ruby-3.0.2/lib/rubygems/test_case.rb:1542:in `initialize': Neither PUB key nor PRIV key (OpenSSL::PKey::RSAError) - from /builddir/build/BUILD/ruby-3.0.2/lib/rubygems/test_case.rb:1542:in `new' - from /builddir/build/BUILD/ruby-3.0.2/lib/rubygems/test_case.rb:1542:in `load_key' - from /builddir/build/BUILD/ruby-3.0.2/lib/rubygems/test_case.rb:1562:in `' - from /builddir/build/BUILD/ruby-3.0.2/lib/rubygems/test_case.rb:105:in `' - from :85:in `require' - from :85:in `require' - from /builddir/build/BUILD/ruby-3.0.2/test/rdoc/test_rdoc_rubygems_hook.rb:2:in `' - from :85:in `require' - from :85:in `require' - from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1049:in `block in non_options' - from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1043:in `each' - from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1043:in `non_options' - from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:65:in `process_args' - from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:143:in `process_args' - from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1237:in `process_args' - from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1242:in `run' - from /builddir/build/BUILD/ruby-3.0.2/tool/lib/test/unit.rb:1249:in `run' - from /builddir/build/BUILD/ruby-3.0.2/tool/test/runner.rb:23:in `' - from ./test/runner.rb:11:in `require_relative' - from ./test/runner.rb:11:in `
' -~~~ - -Therefore use AES-256-CBC instead. This is essentially revert of -ca228b76b, which was fixing https://github.com/jruby/jruby/issues/919 - -[1]: https://github.com/openssl/openssl/blob/master/doc/man7/migration_guide.pod#legacy-algorithms -[2]: https://github.com/openssl/openssl/blob/master/doc/man7/OSSL_PROVIDER-legacy.pod ---- - test/rubygems/encrypted_private_key.pem | 52 ++++++++++++------------- - 1 file changed, 26 insertions(+), 26 deletions(-) - -diff --git a/test/rubygems/encrypted_private_key.pem b/test/rubygems/encrypted_private_key.pem -index 868f332b7c..d9667689a6 100644 ---- a/test/rubygems/encrypted_private_key.pem -+++ b/test/rubygems/encrypted_private_key.pem -@@ -1,30 +1,30 @@ - -----BEGIN RSA PRIVATE KEY----- - Proc-Type: 4,ENCRYPTED --DEK-Info: DES-CBC,4E38D58B5A059DB6 -+DEK-Info: AES-256-CBC,CB6FD0B173EF450C6EE21A01DD785C1D - --IgWLfnHVnkErKkhysrUMoE0ubkRDtJXZv9KR02jGGFk/kGqWyTqPk08uzhwVNM+l --eOk0qfPykkJM3KZgqTsD6xfA1D5WqFp5mLoFXVVTn9I3acSZsqOY0FweCipwdVpI --x+9Fl+v62kIW06dOjyWLE1abed9hHiXesGGsD87/RJSywy4OBxOcrhR1fJLK4ElR --ya0UzI7rWnmZMChjaZBssfzT1DR79/dARXhon2m5EiIJDjMpc8BKGYlQy5RHCHwA --cnrhUTTvsggZbQtmLZ/yVx8FSJ273XpYR0pmwbw4j1R+zeXQRK5MroBnCfOGcYa7 --rmpERmDW3VAuxXR20SUAGdo1XOMTDe1uLbaotn6e56pXghIaYROTPS+HsuOkAZGY --OYWEkUoyog4l4n+h/C1umFfTFGvKNATLgDugONFvTw/PLbjvl+sWMy2QfqH0MlNB --DIUPxhEVCFD9oB4nfB86WDAmPp1DH9/IBet/21kbQ2eTIzakTdG3XiC+xzAQRu68 --EOCTbasFWGxlCix66gt4xWMLksEg8UhWSpjS3/HsifrKyNMB8sfUFYmZmOYMW4mf --NuEtpBL3AdHNObN8nQ75HfehukzNpbYVRsLzWrVgtxvXHVpnvoCCpCvQBMHeRZxK --6m028mhH1m6yYE/uGFiRKLrN7BKAttbUiqnGgVIg/lQQilFWwylxQ6aXqJGmNgxa --oihzWZRlXivIhhrM7VMnLoKAF/YfmWpP3zahGpBQGfObtPtm44R0ezXPdtsivnyu --CmFOPGzRNMKZtH/lwVhuIIK3AFIGDsRRP9ySN4YfjQZnTdu2sRlxBnANP9m8W9T2 --p+C4zVkDYAbsuWq2HpHwsdL8gqIiXeptsHLqkNw+ulSSLyeBCgM9fpV3RsNGjwqu --k8QLb1CYp2VX46CE8UKvOd/nyFnEsD+EAc3WangEwA41m2IaXcbs9Au7xsG9oacZ --DrxlJVNxlxO9YyP9dNOTfP0fHIiygKQQY2aU3y3oRneu7ogYES5V2mUNH7cYUWVL --CHPXAoUXJErvDQ/opW2DroA9Eqv9sST6WqBf6LXRcWU0ntfzcFUbEqgmCmB7Cbu2 --8udEn6iWilQahLyDoAShLkU7+Tk78Z1c6RuqjyY4VboZPzxrTYK8YIXzwX+jj9bG --KIIGS5eghK185+AjlwtzJ7MBdoL323YIik6uOZluhnJHLaxjxUXGa1VqDgsyqGi7 --ISRMTpVTrbR+UtoEi4ZhMjobtFUr7lGkt24VkXwBKdoyryj4RPHGdp7Tf6XDJufQ --+KKhqt8QrpOTPiMskFN2disOSF5/YZCmtT84nkhU7Hf1lkQ2kfx1zfNk0GqYYXOW --zHOAczy8gWBRetDMnhRYohDzQGWn//b+2Wr2n1RD8D9kyjMRhpFMYfQGfRcuPGjW --91k/T0XFcjcjeZPL9s+HITmrh7zg5WxbCfTEp91j3Oy1bns196SY77TE0BzUsqR2 --geJggcUMEfyvHiiCMtijmSSD9nf8tNIxLVL8Jaf1coA6e1CrlHnYAu2f/Q3GIcvU --EEEmw+cZRwsk4fffYzh5psxxGdXKBv1KcQ/CeBhZL0WJsCp2y5oxwg== -+KqHn2Df8hSuwNE+W+60MnGtc6xpoXmF3iN25iVwcN67krYn+N6cBhjFeXwXccYwJ -+2gHSu4iEK9Qe32vK0yuv8N9h/fmsabZl0TotnEem/pqO5T8W4LxyK+Rw0s6RB30S -+C+mUisRADTanAxyBxsNU8xR8OAUNMAAxV1me6It0W2lfNE3t5jg/Kr0NWMoRUNRx -+dkE6WlD5D8jBeC3QdZ6OuE7QXOCEAWAjcFMc0d1WJq2t2r3TrLVfTH7EOoRyvL1H -+rrFRx/dEW1UJfM6P11wB5R0nhg3rDXF7oDFszjwO/3tzARke0NZuN37l301lYRl1 -+aolO6sShJLa0Ml/TgNcJw0S6rc6a1Z52gTfQKztKcL1UX4HLZg75zKmn6qfatMBC -+iXn+pQRYNsOPQ5h4r7lBBqvuV+gBw+rN768tYpZ2/YVDaygxETHcZAFCdAw/JNbP -+d0XPIbP79NRrCgzSo58LKQGuOQf3Hh0vp1YS+MilMtm/eogoj1enSPM+ymStHRwG -+i+D00xCQ6blSOZ2eUUBJXt11YzP22GYnv+XTR/5kGKkTIvoRMfd+39bQyR32IEv2 -+Z+yweAGQInD94eifT9ObbIayJ47y01KP0+Vj6hz4RCFsmJKsYiai5JiKlmf7lV9w -+7zH3TtCOx/xSyomesXVRkqvFkdyeguU72kXc5tiMPaDXGCOeV0GWyR1GU1DUX9/K -+60E7ym0Wx77WGMKk2fkirZzBdOeliyCRUXd7ccN2rBCjTwtjAUIk27lwzdUaTUv7 -+EmjauDvSMFtir58c+zjlLmBaSQOzKcj0KXMp0Oucls9bD85WGGbGyzGhTa0AZ+/+ -+cCEJt7RAwW0kTEO/uO+BAZe/zBoi9ek+QBn54FK3E7CXfS4Oi9Qbc3fwlVyTlVmz -+ZGrCncO0TIVGErFWK24Z7lX8rBnk8enfnamrPfKtwn4LG9aDfhSj8DtisjlRUVT5 -+chDQ+CCi9rh3wXh28lyS+nXJ3yFidCzRgcsc3PpN/c4DNRggZc+C/KDw+J2FW+8Y -+p65OliBQHQcG0PnCa2xRyCGevytPG0rfNDgyaY33dPEo90mBLVcwLbzGiSGBHgFl -+pr8A/rqbnFpRO39NYbACeRFCqPpzyzfARCCcjcDoFrENdIaJui0fjlBkoV3B/KiK -+EVjDcgwt1HAtz8bV2YJ+OpQbhD7E90e2vTRMuXAH21Ygo32VOS0LRlCRc9ZyZW4z -+PTyO/6a+FbXZ1zhVJxu/0bmBERZ14WVmWq56oxQav8knpxYeYPgpEmIZnrHnJ1Ko -+UoXcc8Hy4NKtaBmDcaF8TCobNsRZTxO/htqpdyNsOrBSsnX2kP5D/O1l1vuVYi1/ -+RYfUqL9dvGzvfsFuuDDjDlQ/fIA6pFzJV3fy4KJHlF1r33qaE/lNMdpKljBwvUII -+Vog4cGmzxssqK5q9kuogcuyeOuFODjBNW4qt0WylSi9bwwy3ZwaZLRqhngz6+tCV -+Jp45Gk881XiVe3aVU0l+4DmJJ9/5vwqjH5Vo/GJqFU6gzB+Zv/0plYeNkuE0Xo2z -+ecdxnGKVPl42q44lvczjDw2KX0ahxQrfrbcl48//zR295u9POzCL97d6zpioI2NR - -----END RSA PRIVATE KEY----- --- -2.32.0 - diff --git a/rubygems-3.2.30-Use-OpenSSL-constants-for-error-codes.patch b/rubygems-3.2.30-Use-OpenSSL-constants-for-error-codes.patch deleted file mode 100644 index 8fe139e..0000000 --- a/rubygems-3.2.30-Use-OpenSSL-constants-for-error-codes.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 8acf8e95dcaebe227f779271b8213c15eceb846f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Mon, 1 Nov 2021 18:40:06 +0100 -Subject: [PATCH] Use OpenSSL constants for error codes. - -This fixes the following test error testing against OpenSSL 3.x: - -~~~ - 2) Failure: -TestGemRequest#test_verify_certificate_extra_message [/builddir/build/BUILD/ruby-3.0.2/test/rubygems/test_gem_request.rb:358]: -<"ERROR: SSL verification error at depth 0: invalid CA certificate (24)\n" + -"ERROR: Certificate is an invalid CA certificate\n"> expected but was -<"ERROR: SSL verification error at depth 0: invalid CA certificate (79)\n" + -"ERROR: Certificate is an invalid CA certificate\n">. -~~~ - -Where the root cause is this OpenSSL commit: - -https://github.com/openssl/openssl/commit/1e41dadfa7b9f792ed0f4714a3d3d36f070cf30e - -It seems that OpenSSL upstream considers the constant value just an -implementation detail and therefore this changes the test case to -follow the suite. ---- - test/rubygems/test_gem_request.rb | 14 ++++++++++---- - 1 file changed, 10 insertions(+), 4 deletions(-) - -diff --git a/test/rubygems/test_gem_request.rb b/test/rubygems/test_gem_request.rb -index 66477be7bc..47654f6fa4 100644 ---- a/test/rubygems/test_gem_request.rb -+++ b/test/rubygems/test_gem_request.rb -@@ -328,30 +328,36 @@ def test_user_agent_revision_missing - - def test_verify_certificate - pend if Gem.java_platform? -+ -+ error_number = OpenSSL::X509::V_ERR_OUT_OF_MEM -+ - store = OpenSSL::X509::Store.new - context = OpenSSL::X509::StoreContext.new store -- context.error = OpenSSL::X509::V_ERR_OUT_OF_MEM -+ context.error = error_number - - use_ui @ui do - Gem::Request.verify_certificate context - end - -- assert_equal "ERROR: SSL verification error at depth 0: out of memory (17)\n", -+ assert_equal "ERROR: SSL verification error at depth 0: out of memory (#{error_number})\n", - @ui.error - end - - def test_verify_certificate_extra_message - pend if Gem.java_platform? -+ -+ error_number = OpenSSL::X509::V_ERR_INVALID_CA -+ - store = OpenSSL::X509::Store.new - context = OpenSSL::X509::StoreContext.new store -- context.error = OpenSSL::X509::V_ERR_INVALID_CA -+ context.error = error_number - - use_ui @ui do - Gem::Request.verify_certificate context - end - - expected = <<-ERROR --ERROR: SSL verification error at depth 0: invalid CA certificate (24) -+ERROR: SSL verification error at depth 0: invalid CA certificate (#{error_number}) - ERROR: Certificate is an invalid CA certificate - ERROR - --- -2.32.0 - diff --git a/sources b/sources index fc750ca..2b40f22 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (ruby-3.0.2.tar.xz) = 0f702e2d8ca1342a9d4284dbdd234a3588e057b92566353aa7c21835cf09a3932864b2acf459a976960a1704e9befa562155d36b98b7cda8bd99526e10a374c4 +SHA512 (ruby-3.0.3.tar.xz) = bb9ea426278d5a7ac46595296f03b82d43df8b7db41045cdf85611e05e26c703c53f700494cd7cf5d4c27fa953bdc5c144317d7720812db0a6e3b6f4bc4d2e00 From dbe75d1cb511ff84e7d934c0209e596365eedb59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Wed, 8 Dec 2021 12:10:25 +0100 Subject: [PATCH 016/141] Fix wrong version in changelog. --- ruby.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby.spec b/ruby.spec index 7530e95..fe6184e 100644 --- a/ruby.spec +++ b/ruby.spec @@ -1456,7 +1456,7 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" %changelog -* Thu Nov 25 2021 Vít Ondruch - 3.0.2-154 +* Thu Nov 25 2021 Vít Ondruch - 3.0.3-154 - Upgrade to Ruby 3.0.3. * Fri Nov 05 2021 Vít Ondruch - 3.0.2-153 From 5d3688479ab299cbd5657f9a503463a04d963d65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Fri, 10 Dec 2021 17:05:02 +0100 Subject: [PATCH 017/141] Fix loading of default gems. Resolves: rhbz#2027099 --- ruby.spec | 11 +- ...ng_system-rb-customizations-too-late.patch | 262 ++++++++++++++++++ 2 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch diff --git a/ruby.spec b/ruby.spec index fe6184e..dc2b5da 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 154 +%global release 155 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -169,6 +169,10 @@ Patch20: ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch # https://bugs.ruby-lang.org/issues/16936 # https://github.com/ruby/ruby/pull/5026 Patch21: ruby-3.1.0-Properly-exclude-test-cases.patch +# Fix loading of default gems. +# https://bugzilla.redhat.com/show_bug.cgi?id=2027099 +# https://github.com/rubygems/rubygems/pull/5154 +Patch22: rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch # OpenSSL 3.0 compatibility patches @@ -678,6 +682,7 @@ rm -rf ext/fiddle/libffi* %patch19 -p1 %patch20 -p1 %patch21 -p1 +%patch22 -p1 %patch30 -p1 -R %patch31 -p1 %patch40 -p1 @@ -1456,6 +1461,10 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" %changelog +* Thu Dec 09 2021 Vít Ondruch - 3.0.3-155 +- Fix loading of default gems. + Resolves: rhbz#2027099 + * Thu Nov 25 2021 Vít Ondruch - 3.0.3-154 - Upgrade to Ruby 3.0.3. 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..d61020d --- /dev/null +++ b/rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch @@ -0,0 +1,262 @@ +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. +--- + .github/workflows/install-rubygems.yml | 5 ---- + lib/rubygems.rb | 32 +++++++++++++------------- + test/rubygems/test_rubygems.rb | 23 ++++++++++++++++++ + 3 files changed, 39 insertions(+), 21 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. +--- + bundler/spec/commands/clean_spec.rb | 2 +- + bundler/spec/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 + From 08a1249d7f8f32051a2725204cd74e2c9f3e6d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 10 Jan 2022 11:55:34 +0100 Subject: [PATCH 018/141] Rebuilt for https://fedoraproject.org/wiki/Changes/LIBFFI34 --- ruby.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ruby.spec b/ruby.spec index dc2b5da..44319e7 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 155 +%global release 156 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -1461,6 +1461,9 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" %changelog +* Mon Jan 10 2022 Miro Hrončok - 3.0.3-156 +- Rebuilt for https://fedoraproject.org/wiki/Changes/LIBFFI34 + * Thu Dec 09 2021 Vít Ondruch - 3.0.3-155 - Fix loading of default gems. Resolves: rhbz#2027099 From b24ebf5ec1c6ad3a3ea5ac8858d34f3f75765390 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Tue, 11 Jan 2022 11:50:01 +0100 Subject: [PATCH 019/141] Remove the patch applied to pass the test/fiddle/test_import.rb on PPC. In Ruby 3.0.3, a new logic with the hard-coded "libc.so.6" to detect glibc works on PPC, both Power 8 and 9. See . Note the logic also fixes the following error on a Power 9 environment where the path is `/lib64/glibc-hwcaps/power9/libc-2.28.so`. ``` /builddir/build/BUILD/ruby-2.6.9/.ext/common/fiddle/import.rb:299:in `import_function': cannot find the function: strcpy() (Fiddle::DLError) from /builddir/build/BUILD/ruby-2.6.9/.ext/common/fiddle/import.rb:172:in `extern' from /builddir/build/BUILD/ruby-2.6.9/test/fiddle/test_import.rb:17:in `' from /builddir/build/BUILD/ruby-2.6.9/test/fiddle/test_import.rb:10:in `' from /builddir/build/BUILD/ruby-2.6.9/test/fiddle/test_import.rb:9:in `' from /builddir/build/BUILD/ruby-2.6.9/test/lib/test/unit.rb:958:in `require' from /builddir/build/BUILD/ruby-2.6.9/test/lib/test/unit.rb:958:in `block in non_options' from /builddir/build/BUILD/ruby-2.6.9/test/lib/test/unit.rb:952:in `each' from /builddir/build/BUILD/ruby-2.6.9/test/lib/test/unit.rb:952:in `non_options' from /builddir/build/BUILD/ruby-2.6.9/test/lib/test/unit.rb:64:in `process_args' from /builddir/build/BUILD/ruby-2.6.9/test/lib/test/unit.rb:130:in `process_args' from /builddir/build/BUILD/ruby-2.6.9/test/lib/test/unit.rb:1136:in `process_args' from /builddir/build/BUILD/ruby-2.6.9/test/lib/test/unit.rb:1141:in `run' from /builddir/build/BUILD/ruby-2.6.9/test/lib/test/unit.rb:1148:in `run' from ./test/runner.rb:33:in `
' ``` --- ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch | 30 -------------------- ruby.spec | 10 +++---- 2 files changed, 4 insertions(+), 36 deletions(-) delete mode 100644 ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch diff --git a/ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch b/ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch deleted file mode 100644 index 599a6e6..0000000 --- a/ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 346e147ba6480839b87046e9a9efab0bf6ed3660 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Wed, 10 Aug 2016 17:35:48 +0200 -Subject: [PATCH] Rely on ldd to detect glibc. - -This is just workaround, since we know we are quite sure this will be successful -on Red Hat platforms. - -This workaround rhbz#1361037 ---- - test/fiddle/helper.rb | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/test/fiddle/helper.rb b/test/fiddle/helper.rb -index 1da3d93..65148a1 100644 ---- a/test/fiddle/helper.rb -+++ b/test/fiddle/helper.rb -@@ -139,6 +139,9 @@ - libc_so = libm_so = "/usr/lib/libSystem.B.dylib" - end - -+# Just ignore the heuristic, because it is not reliable on all platforms. -+libc_so = libm_so = nil -+ - if !libc_so || !libm_so - ruby = EnvUtil.rubybin - # When the ruby binary is 32-bit and the host is 64-bit, --- -2.9.2 - diff --git a/ruby.spec b/ruby.spec index 44319e7..0f81795 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 156 +%global release 157 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -138,10 +138,6 @@ Patch5: ruby-1.9.3-mkmf-verbose.patch # https://lists.fedoraproject.org/archives/list/ruby-sig@lists.fedoraproject.org/message/LH6L6YJOYQT4Y5ZNOO4SLIPTUWZ5V45Q/ # For now, load the ABRT hook via this simple patch: Patch6: ruby-2.7.0-Initialize-ABRT-hook.patch -# Workaround "an invalid stdio handle" error on PPC, due to recently introduced -# hardening features of glibc (rhbz#1361037). -# https://bugs.ruby-lang.org/issues/12666 -Patch9: ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch # Fix DWARF5 support. # https://bugzilla.redhat.com/show_bug.cgi?id=1920533 # https://bugs.ruby-lang.org/issues/17585 @@ -674,7 +670,6 @@ rm -rf ext/fiddle/libffi* %patch4 -p1 %patch5 -p1 %patch6 -p1 -%patch9 -p1 %patch15 -p1 %patch16 -p1 %patch17 -p1 @@ -1461,6 +1456,9 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" %changelog +* Tue Jan 11 2022 Jun Aruga - 3.0.3-157 +- Remove the patch applied to pass the test/fiddle/test_import.rb on PPC. + * Mon Jan 10 2022 Miro Hrončok - 3.0.3-156 - Rebuilt for https://fedoraproject.org/wiki/Changes/LIBFFI34 From 46ee70614f22238e1ccb177e379fbcf53bdb36b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Fri, 17 Dec 2021 10:44:56 +0100 Subject: [PATCH 020/141] Remove colon from `load` call. This is not needed by RPM 4.17+ and might improve backwared compatibilty with RHEL 7, where the original LUA implementation of `load` macro was used. --- ruby.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby.spec b/ruby.spec index 0f81795..bbac027 100644 --- a/ruby.spec +++ b/ruby.spec @@ -109,8 +109,8 @@ 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}} +%{load %{SOURCE4}} +%{load %{SOURCE5}} # Fix ruby_version abuse. # https://bugs.ruby-lang.org/issues/11002 From b6d9b2acd19c1f6f98468e667ec9f5b829228a21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Mon, 17 Jan 2022 17:34:57 +0100 Subject: [PATCH 021/141] Disable some Fiddle test by libffi-3.4.2. --- ruby.spec | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ruby.spec b/ruby.spec index bbac027..978521c 100644 --- a/ruby.spec +++ b/ruby.spec @@ -979,6 +979,11 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestPKeyDH#test_derive_key/" DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestPKeyDH#test_key_exchange/" DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" +# Several test broken by libffi-3.4.2. There should be fix in libffi, once +# other components are fixed. +# https://bugzilla.redhat.com/show_bug.cgi?id=2040380 +mv test/fiddle/test_import.rb{,.disable} + # Give an option to increase the timeout in tests. # https://bugs.ruby-lang.org/issues/16921 %{?test_timeout_scale:RUBY_TEST_TIMEOUT_SCALE="%{test_timeout_scale}"} \ From a28556f68416aa9c42025bb481605ae2793227b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Thu, 20 Jan 2022 11:07:32 +0100 Subject: [PATCH 022/141] Fix segfault in `TestArray#test_sample` on s390x. ~~~ ... snip ... [ 3104/21226] TestArray#test_sample/builddir/build/BUILD/ruby-3.0.3/test/ruby/test_array.rb:2871: [BUG] Segmentation fault at 0x00000000c04fb000 ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [s390x-linux] -- Control frame information ----------------------------------------------- c:0031 p:---- s:0176 e:000175 CFUNC :srand c:0030 p:0011 s:0171 e:000170 METHOD /builddir/build/BUILD/ruby-3.0.3/test/ruby/test_array.rb:2871 c:0029 p:0052 s:0165 e:000164 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1283 c:0028 p:0065 s:0159 e:000158 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:1330 c:0027 p:0013 s:0150 e:000149 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit/testcase.rb:18 c:0026 p:0077 s:0145 e:000144 BLOCK /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:979 [FINISH] c:0025 p:---- s:0138 e:000137 CFUNC :map c:0024 p:0006 s:0134 E:0012c8 BLOCK /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:972 c:0023 p:0186 s:0130 E:000ba0 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:999 c:0022 p:0042 s:0118 E:000888 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1136 c:0021 p:0010 s:0111 E:0007a0 BLOCK /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:627 [FINISH] c:0020 p:---- s:0105 e:000104 CFUNC :each c:0019 p:0054 s:0101 E:001588 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:625 c:0018 p:0008 s:0094 E:001eb8 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:662 c:0017 p:0140 s:0087 E:0011a8 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:908 c:0016 p:0016 s:0074 E:001ca8 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1073 c:0015 p:0005 s:0069 E:000710 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:1147 c:0014 p:0006 s:0065 E:000438 BLOCK /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:1134 [FINISH] c:0013 p:---- s:0061 e:000060 CFUNC :each c:0012 p:0047 s:0057 E:0022b8 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:1133 c:0011 p:0013 s:0052 E:000288 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:1121 c:0010 p:0008 s:0047 E:000c70 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:847 c:0009 p:0008 s:0041 E:0008d0 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:695 c:0008 p:0015 s:0035 E:001f08 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:34 c:0007 p:0006 s:0030 E:0003c8 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1175 c:0006 p:0032 s:0025 E:000e80 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1245 c:0005 p:0009 s:0021 E:0018b8 METHOD /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1249 c:0004 p:0172 s:0016 E:0001b8 TOP /builddir/build/BUILD/ruby-3.0.3/tool/test/runner.rb:23 [FINISH] c:0003 p:---- s:0011 e:000010 CFUNC :require_relative c:0002 p:0092 s:0006 E:001bf0 EVAL ./test/runner.rb:11 [FINISH] c:0001 p:0000 s:0003 E:0004f0 (none) [FINISH] -- Ruby level backtrace information ---------------------------------------- ./test/runner.rb:11:in `
' ./test/runner.rb:11:in `require_relative' /builddir/build/BUILD/ruby-3.0.3/tool/test/runner.rb:23:in `' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1249:in `run' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1245:in `run' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1175:in `run' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:34:in `run' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:695:in `run' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:847:in `run' /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:1121:in `run' /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:1133:in `_run' /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:1133:in `each' /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:1134:in `block in _run' /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:1147:in `run_tests' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1073:in `_run_anything' /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:908:in `_run_anything' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:662:in `_run_suites' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:625:in `_run_suites' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:625:in `each' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:627:in `block in _run_suites' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1136:in `_run_suite' /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:999:in `_run_suite' /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:972:in `block in _run_suite' /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:972:in `map' /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:979:in `block (2 levels) in _run_suite' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit/testcase.rb:18:in `run' /builddir/build/BUILD/ruby-3.0.3/tool/lib/minitest/unit.rb:1330:in `run' /builddir/build/BUILD/ruby-3.0.3/tool/lib/test/unit.rb:1283:in `run_test' /builddir/build/BUILD/ruby-3.0.3/test/ruby/test_array.rb:2871:in `test_sample' /builddir/build/BUILD/ruby-3.0.3/test/ruby/test_array.rb:2871:in `srand' -- C level backtrace information ------------------------------------------- /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_print_backtrace+0x1c) [0x3ffab964c5c] vm_dump.c:758 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_vm_bugreport.constprop.0+0x4ba) [0x3ffab977f0a] vm_dump.c:998 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_bug_for_fatal_signal+0xb2) [0x3ffab7b2252] error.c:786 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(sigsegv+0x58) [0x3ffab8d2fb8] signal.c:963 [0x3ffabb7e490] /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_free_tmp_buffer+0x4) [0x3ffab7d1114] gc.c:11047 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rand_init+0x122) [0x3ffab896892] random.c:387 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_f_srand+0x6e) [0x3ffab8975fe] random.c:873 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_call_cfunc_with_frame+0x170) [0x3ffab9421f0] vm_insnhelper.c:2931 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_sendish+0x53a) [0x3ffab94659a] vm_insnhelper.c:4532 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_exec_core.lto_priv.0+0xe6) [0x3ffab947d16] insns.def:789 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_vm_exec+0x1ee) [0x3ffab96129e] vm.c:2172 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_yield+0xaa) [0x3ffab951a6a] vm.c:1398 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_ary_collect.lto_priv.0+0x6a) [0x3ffab742d6a] array.c:3635 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_call_cfunc_with_frame+0x170) [0x3ffab9421f0] vm_insnhelper.c:2931 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_sendish+0x53a) [0x3ffab94659a] vm_insnhelper.c:4532 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_exec_core.lto_priv.0+0x21c0) [0x3ffab949df0] insns.def:770 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_vm_exec+0x1ee) [0x3ffab96129e] vm.c:2172 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_yield+0xaa) [0x3ffab951a6a] vm.c:1398 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_ary_each+0x4c) [0x3ffab742aac] array.c:2523 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_call_cfunc_with_frame+0x170) [0x3ffab9421f0] vm_insnhelper.c:2931 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_call_method_each_type+0x530) [0x3ffab942d20] vm_insnhelper.c:3400 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_sendish+0x53a) [0x3ffab94659a] vm_insnhelper.c:4532 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_exec_core.lto_priv.0+0x21c0) [0x3ffab949df0] insns.def:770 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_vm_exec+0x1ee) [0x3ffab96129e] vm.c:2172 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_yield+0xaa) [0x3ffab951a6a] vm.c:1398 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_ary_each+0x4c) [0x3ffab742aac] array.c:2523 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_call_cfunc_with_frame+0x170) [0x3ffab9421f0] vm_insnhelper.c:2931 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_call_method_each_type+0x530) [0x3ffab942d20] vm_insnhelper.c:3400 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_sendish+0x53a) [0x3ffab94659a] vm_insnhelper.c:4532 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_exec_core.lto_priv.0+0x21c0) [0x3ffab949df0] insns.def:770 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_vm_exec+0x1ee) [0x3ffab96129e] vm.c:2172 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(require_internal.lto_priv.0+0xbc6) [0x3ffab809be6] load.c:1109 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_require_string+0x48) [0x3ffab809db8] load.c:1186 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_call_cfunc_with_frame+0x170) [0x3ffab9421f0] vm_insnhelper.c:2931 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_sendish+0x53a) [0x3ffab94659a] vm_insnhelper.c:4532 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(vm_exec_core.lto_priv.0+0xe6) [0x3ffab947d16] insns.def:789 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_vm_exec+0x1ee) [0x3ffab96129e] vm.c:2172 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(rb_ec_exec_node+0x10c) [0x3ffab7b71ac] eval.c:317 /builddir/build/BUILD/ruby-3.0.3/libruby.so.3.0.3(ruby_run_node+0x70) [0x3ffab7b72c0] eval.c:375 [0x2aa26e811f0] [0x3ffab4b3872] [0x3ffab4b3950] [0x2aa26e81250] ... snip ... ~~~ --- ruby-3.1.0-Fix-stack-buffer-overflow.patch | 70 ++++++++++++++++++++++ ruby.spec | 7 +++ 2 files changed, 77 insertions(+) create mode 100644 ruby-3.1.0-Fix-stack-buffer-overflow.patch diff --git a/ruby-3.1.0-Fix-stack-buffer-overflow.patch b/ruby-3.1.0-Fix-stack-buffer-overflow.patch new file mode 100644 index 0000000..4e842ff --- /dev/null +++ b/ruby-3.1.0-Fix-stack-buffer-overflow.patch @@ -0,0 +1,70 @@ +From cc44179cb8419b0e48ef9baa6f1722603643c1a0 Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Tue, 17 Aug 2021 22:01:57 +0900 +Subject: [PATCH] Fix stack buffer overflow + +https://hackerone.com/reports/1306859 +--- + include/ruby/internal/memory.h | 6 +++--- + random.c | 7 ++----- + 2 files changed, 5 insertions(+), 8 deletions(-) + +diff --git a/include/ruby/internal/memory.h b/include/ruby/internal/memory.h +index 7d24df4945..64f3101fc2 100644 +--- a/include/ruby/internal/memory.h ++++ b/include/ruby/internal/memory.h +@@ -110,18 +110,18 @@ extern void *alloca(); + ((var) = RBIMPL_CAST((type *)ruby_xrealloc2((void *)(var), (n), sizeof(type)))) + + #define ALLOCA_N(type,n) \ +- RBIMPL_CAST((type *)alloca(rbimpl_size_mul_or_raise(sizeof(type), (n)))) ++ RBIMPL_CAST((type *)(!(n) ? NULL : alloca(rbimpl_size_mul_or_raise(sizeof(type), (n))))) + + /* allocates _n_ bytes temporary buffer and stores VALUE including it + * in _v_. _n_ may be evaluated twice. */ + #define RB_ALLOCV(v, n) \ + ((n) < RUBY_ALLOCV_LIMIT ? \ +- ((v) = 0, alloca(n)) : \ ++ ((v) = 0, !(n) ? NULL : alloca(n)) : \ + rb_alloc_tmp_buffer(&(v), (n))) + #define RB_ALLOCV_N(type, v, n) \ + RBIMPL_CAST((type *) \ + (((size_t)(n) < RUBY_ALLOCV_LIMIT / sizeof(type)) ? \ +- ((v) = 0, alloca((n) * sizeof(type))) : \ ++ ((v) = 0, !(n) ? NULL : alloca((n) * sizeof(type))) : \ + rb_alloc_tmp_buffer2(&(v), (n), sizeof(type)))) + #define RB_ALLOCV_END(v) rb_free_tmp_buffer(&(v)) + +diff --git a/random.c b/random.c +index 7567d13dd7..4d70c17116 100644 +--- a/random.c ++++ b/random.c +@@ -369,15 +369,12 @@ rand_init(const rb_random_interface_t *rng, rb_random_t *rnd, VALUE seed) + int sign; + + len = rb_absint_numwords(seed, 32, NULL); ++ if (len == 0) len = 1; + buf = ALLOCV_N(uint32_t, buf0, len); + sign = rb_integer_pack(seed, buf, len, sizeof(uint32_t), 0, + INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER); + if (sign < 0) + sign = -sign; +- if (len == 0) { +- buf[0] = 0; +- len = 1; +- } + if (len > 1) { + if (sign != 2 && buf[len-1] == 1) /* remove leading-zero-guard */ + len--; +@@ -814,7 +811,7 @@ rand_mt_init(rb_random_t *rnd, const uint32_t *buf, size_t len) + { + struct MT *mt = &((rb_random_mt_t *)rnd)->mt; + if (len <= 1) { +- init_genrand(mt, buf[0]); ++ init_genrand(mt, len ? buf[0] : 0); + } + else { + init_by_array(mt, buf, (int)len); +-- +2.34.1 + diff --git a/ruby.spec b/ruby.spec index 978521c..136c36b 100644 --- a/ruby.spec +++ b/ruby.spec @@ -227,6 +227,9 @@ Patch52: ruby-3.1.0-Support-OpenSSL-3.0.patch # Fix `TestPumaControlCli#test_control_ssl` testcase in Puma. # https://github.com/ruby/openssl/pull/399#issuecomment-966239736 Patch53: ruby-3.1.0-SSL_read-EOF-handling.patch +# Fix segfault in `TestArray#test_sample` on s390x. +# https://github.com/ruby/ruby/pull/5239 +Patch54: ruby-3.1.0-Fix-stack-buffer-overflow.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -694,6 +697,7 @@ rm -rf ext/fiddle/libffi* %patch51 -p1 %patch52 -p1 %patch53 -p1 +%patch54 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -1461,6 +1465,9 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Thu Jan 20 2022 Vít Ondruch - 3.0.3-157 +- Fix segfault in `TestArray#test_sample` on s390x. + * Tue Jan 11 2022 Jun Aruga - 3.0.3-157 - Remove the patch applied to pass the test/fiddle/test_import.rb on PPC. From a0bcb33eaa666d3e1d08ca45e77161ca05611487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Thu, 20 Jan 2022 17:26:59 +0100 Subject: [PATCH 023/141] Disable package notes to prevent rubygem- build breakage. The embedded linker flags breaks build of rubygem- packages with binary extension: ~~~ gcc -shared -o nio4r_ext.so bytebuffer.o monitor.o nio4r_ext.o selector.o -L. -L/usr/lib64 -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -Wl,-dT,/builddir/build/BUILD/.package_note-rubygem-nio4r-2.5.2-6.fc36.x86_64.ld -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -Wl,-dT,/builddir/build/BUILD/.package_note-ruby-0.15.2-157.fc36.x86_64.ld -m64 -lruby -lm -lc /usr/bin/ld: cannot open linker script file /builddir/build/BUILD/.package_note-ruby-0.15.2-157.fc36.x86_64.ld: No such file or directory ~~~ --- ruby.spec | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ruby.spec b/ruby.spec index 136c36b..08d33a8 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 157 +%global release 158 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -80,6 +80,10 @@ %bcond_without hardening_test %endif +# The additional linker flags break binary rubygem- packages. +# https://bugzilla.redhat.com/show_bug.cgi?id=2043092 +%undefine _package_note_flags + Summary: An interpreter of object-oriented scripting language Name: ruby Version: %{ruby_version} @@ -1465,6 +1469,9 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Thu Jan 20 2022 Vít Ondruch - 3.0.3-158 +- Disable package notes to prevent rubygem- build breakage. + * Thu Jan 20 2022 Vít Ondruch - 3.0.3-157 - Fix segfault in `TestArray#test_sample` on s390x. From 2da7a540e7714777b93c430b4f252838b555b703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Tue, 25 Jan 2022 17:32:16 +0100 Subject: [PATCH 024/141] Update OpenSSL 3 compatibility patches. This replaces the parts of the original PR with official patches which landed in [ruby/openssl](https://github.com/ruby/openssl) repository and should reflect the state of OpenSSL 3 support in Ruby 3.1. --- ....1.0-Allocate-EVP_PKEY-on-initialize.patch | 630 ++++++++++ ...Key-set_-and-PKey-DH-EC-generate_key.patch | 719 +++++++++++ ...e-test_no_private_exp-on-OpenSSL-3.0.patch | 27 + ...he-low-level-HMAC-API-to-the-EVP-API.patch | 523 ++++++++ ...anges-for-OpenSSL-3.0-support-part-2.patch | 458 +++++++ ...eous-changes-for-OpenSSL-3.0-support.patch | 176 ++- ruby-3.1.0-Support-OpenSSL-3.0.patch | 1101 ----------------- ruby-3.1.0-Use-EVP-API-in-more-places.patch | 2 +- ...to-load-encrypted-PEM-on-OpenSSL-3.0.patch | 114 ++ ...face-to-generate-parameters-and-keys.patch | 2 +- ruby.spec | 71 +- ...ng_system-rb-customizations-too-late.patch | 11 +- ....1-Fix-compatibility-with-OpenSSL3.0.patch | 105 ++ 13 files changed, 2798 insertions(+), 1141 deletions(-) create mode 100644 ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.patch create mode 100644 ruby-3.1.0-Deprecate-PKey-set_-and-PKey-DH-EC-generate_key.patch create mode 100644 ruby-3.1.0-Disable-test_no_private_exp-on-OpenSSL-3.0.patch create mode 100644 ruby-3.1.0-Migrate-from-the-low-level-HMAC-API-to-the-EVP-API.patch create mode 100644 ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch delete mode 100644 ruby-3.1.0-Support-OpenSSL-3.0.patch create mode 100644 ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.patch create mode 100644 rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch 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-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-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 index f03f28a..a780108 100644 --- 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 @@ -1,7 +1,7 @@ From 8f948ed68a4ed6c05ff66d822711e3b70ae4bb3f Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Mon, 27 Sep 2021 13:32:03 +0900 -Subject: [PATCH 1/3] ext/openssl/ossl.h: add helper macros for +Subject: [PATCH 1/5] ext/openssl/ossl.h: add helper macros for OpenSSL/LibreSSL versions Add following convenient macros: @@ -17,7 +17,7 @@ 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 -@@ -43,6 +43,18 @@ +@@ -42,6 +42,18 @@ #include #include @@ -43,7 +43,7 @@ index c20f506bda..a0cef29d74 100644 From bbf235091e49807ece8f3a3df95bbfcc9d3ab43d Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Sat, 22 Feb 2020 05:37:01 +0900 -Subject: [PATCH 2/3] ts: use TS_VERIFY_CTX_set_certs instead of +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 @@ -58,7 +58,7 @@ 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 -@@ -166,7 +166,7 @@ def find_openssl_library +@@ -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") @@ -67,7 +67,7 @@ index 17d93443fc..09cae05b72 100644 have_func("TS_VERIFY_CTX_set_store") have_func("TS_VERIFY_CTX_add_flags") have_func("TS_RESP_CTX_set_time_cb") -@@ -175,6 +175,9 @@ def find_openssl_library +@@ -174,6 +174,9 @@ def find_openssl_library # added in 1.1.1 have_func("EVP_PKEY_check") @@ -81,7 +81,7 @@ 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 -@@ -242,4 +242,9 @@ IMPL_PKEY_GETTER(EC_KEY, ec) +@@ -236,4 +236,9 @@ IMPL_PKEY_GETTER(EC_KEY, ec) } while (0) #endif @@ -111,7 +111,7 @@ index 692c0d620f..f1da7c1947 100644 From 5fba3bc1df93ab6abc3ea53be3393480f36ea259 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Fri, 19 Mar 2021 19:18:25 +0900 -Subject: [PATCH 3/3] ssl: use SSL_get_rbio() to check if SSL is started or not +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. @@ -140,3 +140,165 @@ index 4b7efa39f5..ec430bfb0c 100644 -- 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-Support-OpenSSL-3.0.patch b/ruby-3.1.0-Support-OpenSSL-3.0.patch deleted file mode 100644 index e701ad0..0000000 --- a/ruby-3.1.0-Support-OpenSSL-3.0.patch +++ /dev/null @@ -1,1101 +0,0 @@ -From bc9cbef395fc8fc7f81c3911b92966abc693169a Mon Sep 17 00:00:00 2001 -From: Kazuki Yamaguchi -Date: Sun, 24 Oct 2021 17:50:18 +0900 -Subject: [PATCH 01/10] test/openssl/test_cipher: update test_ciphers - -Do not attempt to actually use all algorithms. Not all algorithms listed -in OpenSSL::Cipher.ciphers are always available; some may belong to the -legacy provider in OpenSSL 3.0. ---- - 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 178f5aba0e..395183b22d 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 --- -2.32.0 - - -From f73998da49d2cd273b38b542ddd49a4ceaf5bfa9 Mon Sep 17 00:00:00 2001 -From: Kazuki Yamaguchi -Date: Wed, 3 Nov 2021 23:31:29 +0900 -Subject: [PATCH 02/10] test/openssl/test_pkey_rsa: test concatenated PEM - parsing - -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 behavior 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 4548bdb2cf..327449ae03 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 --- -2.32.0 - - -From eb44c4c0eff7a63f9b0bc5d7a7a0df014f1c1b62 Mon Sep 17 00:00:00 2001 -From: Kazuki Yamaguchi -Date: Sat, 20 Mar 2021 23:16:16 +0900 -Subject: [PATCH 03/10] pkey: use OSSL_DECODER to load encrypted PEM on OpenSSL - 3.0 - -The routines to load pkeys (PEM_read_bio_* and d2i_* functions) have -been rewritten around the newly introduced OSSL_DECODER API in OpenSSL -3.0. They now first try to decrypt and parse a PEM block, and then check -the kind. Since we try to parse a given string using each of them in -turn, this means the password callback may now be called more than once. - -Let's use the OSSL_DECODER API directly on OpenSSL 3.0 to avoid this -from happening. ---- - 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 ba909c7632..4eab598942 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: --- -2.32.0 - - -From 588165c3235a23f0df58c8ec50ad6f46a05580f1 Mon Sep 17 00:00:00 2001 -From: Kazuki Yamaguchi -Date: Sat, 20 Mar 2021 23:16:41 +0900 -Subject: [PATCH 04/10] pkey: assume a pkey always has public key components on - OpenSSL 3.0 - -Do not check the key components in this way because they are not -necessarily accessible in this way. ---- - 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 4eab598942..a805b4dc99 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 * --- -2.32.0 - - -From 4c362a1fad72fd570985e4f401ba534456252cb3 Mon Sep 17 00:00:00 2001 -From: Kazuki Yamaguchi -Date: Mon, 12 Apr 2021 10:43:46 +0900 -Subject: [PATCH 05/10] 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 as a string rather than a 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 a805b4dc99..73a54eb2fb 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) { --- -2.32.0 - - -From 013c8552b845a8607f9a0639a07e1515fe067cd3 Mon Sep 17 00:00:00 2001 -From: Kazuki Yamaguchi -Date: Mon, 12 Apr 2021 13:55:10 +0900 -Subject: [PATCH 06/10] pkey: do not check NULL argument in ossl_pkey_new() - -Since the function takes the ownership, the caller is supposed to know -that the lifetime of the object - that is, it is never NULL. In fact, -it is properly checked by the caller in all code paths. ---- - 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 73a54eb2fb..5320d70a48 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 629c16ae1f..d57e9c0f15 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); --- -2.32.0 - - -From 2a9f958d71922303f223d4dcc15049d7dfa962a9 Mon Sep 17 00:00:00 2001 -From: Kazuki Yamaguchi -Date: Mon, 12 Apr 2021 18:32:40 +0900 -Subject: [PATCH 07/10] pkey: lazily initialize EVP_PKEY - -Allocate an EVP_PKEY when the content is ready: when #initialize -or #initialize_copy is called, rather than when OpenSSL::PKey::PKey is -allocated. - -This simplifies #initialize's and the upcoming generic #initialize_copy -implementation. ---- - ext/openssl/ossl_pkey.c | 15 ++---- - ext/openssl/ossl_pkey.h | 19 +++----- - ext/openssl/ossl_pkey_dh.c | 69 ++++++++++++++++++++-------- - ext/openssl/ossl_pkey_dsa.c | 87 +++++++++++++++++++++-------------- - ext/openssl/ossl_pkey_ec.c | 92 ++++++++++++++++++++----------------- - ext/openssl/ossl_pkey_rsa.c | 91 +++++++++++++++++++++--------------- - 6 files changed, 217 insertions(+), 156 deletions(-) - -diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c -index 5320d70a48..9ddfaafe7c 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; - } - -@@ -528,16 +528,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 d57e9c0f15..ac386717d7 100644 ---- a/ext/openssl/ossl_pkey.h -+++ b/ext/openssl/ossl_pkey.h -@@ -15,21 +15,14 @@ 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 GetPKey0(obj, pkey) \ -+ TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)) - #define GetPKey(obj, pkey) do {\ -- TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \ -+ GetPKey0((obj), (pkey)); \ - if (!(pkey)) { \ - rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\ - } \ -diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c -index ca782bbe59..7d8e0fa502 100644 ---- a/ext/openssl/ossl_pkey_dh.c -+++ b/ext/openssl/ossl_pkey_dh.c -@@ -76,7 +76,10 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) - BIO *in; - VALUE arg; - -- GetPKey(self, pkey); -+ GetPKey0(self, 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(); -@@ -84,22 +87,44 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) - ossl_raise(eDHError, "DH_new"); - } - 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); -- } -+ int type; -+ -+ arg = ossl_to_der_if_possible(arg); -+ in = ossl_obj2bio(&arg); -+ -+ /* First try DER-encoded parameters */ -+ dh = d2i_DHparams_bio(in, NULL); -+ OSSL_BIO_reset(in); -+ if (dh) { -+ BIO_free(in); -+ goto legacy; -+ } -+ -+ /* Use the generic routine - parses PEM-encoded parameters */ -+ 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)); -+ } -+ RTYPEDDATA_DATA(self) = pkey; -+ return self; - } -- if (!EVP_PKEY_assign_DH(pkey, dh)) { -- DH_free(dh); -- ossl_raise(eDHError, NULL); -+ -+ legacy: -+ if (dh) { -+ 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 +135,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"); -+ GetPKey0(self, 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 +157,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 7af00eebec..1bba6c54b7 100644 ---- a/ext/openssl/ossl_pkey_dsa.c -+++ b/ext/openssl/ossl_pkey_dsa.c -@@ -83,12 +83,16 @@ VALUE eDSAError; - static VALUE - ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) - { -- EVP_PKEY *pkey, *tmp; -- DSA *dsa = NULL; -+ EVP_PKEY *pkey; -+ DSA *dsa; - BIO *in; - VALUE arg, pass; -+ int type; -+ -+ GetPKey0(self, 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) { -@@ -97,36 +101,41 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) - ossl_raise(eDSAError, "DSA_new"); - } - 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); -+ pass = ossl_pem_passwd_value(pass); -+ arg = ossl_to_der_if_possible(arg); -+ in = ossl_obj2bio(&arg); -+ -+ dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey, -+ PEM_STRING_DSA_PUBLIC, -+ in, NULL, NULL, NULL); -+ OSSL_BIO_reset(in); -+ if (dsa) -+ goto legacy; -+ -+ 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)); - } -- 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); -+ RTYPEDDATA_DATA(self) = pkey; -+ return self; - } - -+ legacy: -+ if (dsa) { -+ 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"); -+ GetPKey0(self, 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 f52e67079d..bec9937bc6 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,55 @@ 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"); -+ GetPKey0(self, 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; -- -- 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; -+ ossl_raise(eECError, "EC_KEY_new"); -+ } -+ else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { -+ ec = ec_key_new_from_group(arg); -+ } -+ else { - 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); -+ arg = ossl_to_der_if_possible(arg); -+ in = ossl_obj2bio(&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; - } -- BIO_free(in); - -- if (!ec) { -- ossl_clear_error(); -- ec = ec_key_new_from_group(arg); -- } -+ 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; - } - -- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { -- EC_KEY_free(ec); -- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); -+ legacy: -+ if (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(self) = pkey; - return self; - } - -@@ -195,18 +202,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"); -+ GetPKey0(self, 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 8ebd3ec559..446150c8af 100644 ---- a/ext/openssl/ossl_pkey_rsa.c -+++ b/ext/openssl/ossl_pkey_rsa.c -@@ -76,12 +76,16 @@ VALUE eRSAError; - static VALUE - ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) - { -- EVP_PKEY *pkey, *tmp; -- RSA *rsa = NULL; -+ EVP_PKEY *pkey; -+ RSA *rsa; - BIO *in; - VALUE arg, pass; -+ int type; -+ -+ GetPKey0(self, 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) { -@@ -90,37 +94,45 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) - ossl_raise(eRSAError, "RSA_new"); - } - 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); -+ 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); -+ OSSL_BIO_reset(in); -+ if (rsa) -+ goto legacy; -+ rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); -+ OSSL_BIO_reset(in); -+ if (rsa) -+ goto legacy; -+ -+ /* 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)); - } -- 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"); -+ RTYPEDDATA_DATA(self) = pkey; -+ return self; - } - -+ legacy: -+ if (rsa) { -+ 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 +142,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"); -+ GetPKey0(self, 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; - } --- -2.32.0 - - -From 0ea28ac73e094bbb379b0915a67d44582e5e20da Mon Sep 17 00:00:00 2001 -From: Kazuki Yamaguchi -Date: Thu, 22 Apr 2021 18:29:30 +0900 -Subject: [PATCH 08/10] pkey: deprecate OpenSSL::PKey::{RSA,DSA,DH}#set_* - methods - -The underlying OpenSSL functions, {RSA,DSA,DH}_set_*() are removed in -OpenSSL 3.0. - -Since the plan is to make EVP_PKEY immutable, there will be no direct -replacement for them and we have no choice here. - -It is suggested for users to use OpenSSL::PKey.from_data instead, -which construct a pkey from all necessary parameters at once. ---- - ext/openssl/ossl_pkey.h | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h -index ac386717d7..f6ad961937 100644 ---- a/ext/openssl/ossl_pkey.h -+++ b/ext/openssl/ossl_pkey.h -@@ -130,6 +130,8 @@ static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALU - BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\ - BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\ - \ -+ rb_warning(#_keytype"#set_"#_group"= is incompatible with " \ -+ "OpenSSL 3.0; check OpenSSL::PKey.from_data"); \ - Get##_type(self, obj); \ - if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \ - (orig_bn2 && !(bn2 = BN_dup(orig_bn2))) || \ -@@ -160,6 +162,8 @@ static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \ - BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\ - BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\ - \ -+ rb_warning(#_keytype"#set_"#_group"= is incompatible with " \ -+ "OpenSSL 3.0; check OpenSSL::PKey.from_data"); \ - Get##_type(self, obj); \ - if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \ - (orig_bn2 && !(bn2 = BN_dup(orig_bn2)))) { \ --- -2.32.0 - - -From 6fda9b5c292fbaae2eb7d6c8e15f1ff53ae7e50c Mon Sep 17 00:00:00 2001 -From: Kazuki Yamaguchi -Date: Tue, 21 Sep 2021 18:29:59 +0900 -Subject: [PATCH 09/10] test/openssl/test_pkey_ec: update test_check_key for - OpenSSL 3.0 - -OpenSSL::PKey::EC#generate_key! or #private_key= will not work on -OpenSSL 3.0. ---- - test/openssl/test_pkey_ec.rb | 32 +++++++++++++++++++------------- - 1 file changed, 19 insertions(+), 13 deletions(-) - -diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb -index d62f1b5eb8..730ad28062 100644 ---- a/test/openssl/test_pkey_ec.rb -+++ b/test/openssl/test_pkey_ec.rb -@@ -60,22 +60,28 @@ 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) -+ EnvUtil.suppress_warning do -+ key2.private_key += 1 -+ assert_raise(OpenSSL::PKey::ECError) { key2.check_key } -+ end -+ end - end - - def test_sign_verify --- -2.32.0 - - -From b63c0cb012981613463bdf4d80dcaedfa494a0d0 Mon Sep 17 00:00:00 2001 -From: Kazuki Yamaguchi -Date: Fri, 22 Oct 2021 16:24:07 +0900 -Subject: [PATCH 10/10] pkey/dh: deprecate OpenSSL::PKey::DH#generate_key! - -OpenSSL 3.0.0 has made keys immutable, so PKey::DH#generate_key! can't -work on it anymore. - -It's advised to use OpenSSL::PKey.generate_key instead. ---- - ext/openssl/lib/openssl/pkey.rb | 26 ++++++++++++++++++++++---- - test/openssl/test_pkey_dh.rb | 33 ++++++++++++++++++--------------- - 2 files changed, 40 insertions(+), 19 deletions(-) - -diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb -index f6bf5892b0..cad376855d 100644 ---- a/ext/openssl/lib/openssl/pkey.rb -+++ b/ext/openssl/lib/openssl/pkey.rb -@@ -61,14 +61,32 @@ 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! -+ msg = "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \ -+ "use OpenSSL::PKey.generate_key instead" -+ if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000 -+ raise DHError, msg -+ else -+ warn "#{caller(1, 1)[0]}: warning: #{msg}" -+ end -+ - unless priv_key - tmp = OpenSSL::PKey.generate_key(self) - set_key(tmp.pub_key, tmp.priv_key) -diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb -index 757704caf6..248f4ebb42 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,17 @@ def test_public_key - end - - def test_generate_key -- dh = Fixtures.pkey("dh1024").public_key # creates a copy -- assert_no_key(dh) -- dh.generate_key! -- assert_key(dh) -- end -- -- def test_key_exchange -- dh = Fixtures.pkey("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 -+ EnvUtil.suppress_warning { # 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) -+ -+ dh2 = dh.public_key -+ dh2.generate_key! -+ assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key)) -+ } -+ end if !openssl?(3, 0, 0) - - def test_params_ok? - dh0 = Fixtures.pkey("dh1024") --- -2.32.0 - 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 index 4938949..f9c4580 100644 --- a/ruby-3.1.0-Use-EVP-API-in-more-places.patch +++ b/ruby-3.1.0-Use-EVP-API-in-more-places.patch @@ -698,7 +698,7 @@ 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 -@@ -173,6 +173,9 @@ def find_openssl_library +@@ -172,6 +172,9 @@ def find_openssl_library have_func("EVP_PBE_scrypt") have_func("SSL_CTX_set_post_handshake_auth") 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 index acb706e..d02ce45 100644 --- 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 @@ -974,7 +974,7 @@ index 693e55cd97..b3c6647faf 100644 -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("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 diff --git a/ruby.spec b/ruby.spec index 08d33a8..a1273d1 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 158 +%global release 159 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -173,6 +173,9 @@ Patch21: ruby-3.1.0-Properly-exclude-test-cases.patch # https://bugzilla.redhat.com/show_bug.cgi?id=2027099 # https://github.com/rubygems/rubygems/pull/5154 Patch22: rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch +# Fix segfault in `TestArray#test_sample` on s390x. +# https://github.com/ruby/ruby/pull/5239 +Patch23: ruby-3.1.0-Fix-stack-buffer-overflow.patch # OpenSSL 3.0 compatibility patches @@ -193,47 +196,63 @@ Patch40: ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch # Implement more 'generic' operations using the EVP API. # https://github.com/ruby/openssl/pull/329 Patch41: ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch +# Migrate from the low-level HMAC API to the EVP API. +# https://github.com/ruby/openssl/pull/371 +Patch42: ruby-3.1.0-Migrate-from-the-low-level-HMAC-API-to-the-EVP-API.patch # Allow setting algorithm-specific options in #sign and #verify. # https://github.com/ruby/openssl/pull/374 -Patch42: ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch +Patch43: ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch # Use high level EVP interface to generate parameters and keys. # https://github.com/ruby/openssl/pull/397 -Patch43: ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch +Patch44: ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch # Use EVP API in more places. # https://github.com/ruby/openssl/pull/436 -Patch44: ruby-3.1.0-Use-EVP-API-in-more-places.patch +Patch45: ruby-3.1.0-Use-EVP-API-in-more-places.patch # Implement PKey#{encrypt,decrypt,sign_raw,verify_{raw,verify_recover}}. # https://github.com/ruby/openssl/pull/382 -Patch45: ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch +Patch46: ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch # Fix `OpenSSL::TestSSL#test_dup` test failure. # https://github.com/ruby/openssl/commit/7b66eaa2dbabb6570dbbbdfac24c4dcdcc6793d7 -Patch46: ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch +Patch47: ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch # Fix `OpenSSL::TestDigest#test_digest_constants` test case. # https://github.com/ruby/openssl/commit/a3e59f4c2e200c76ef1d93945ff8737a05715e17 -Patch47: ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch +Patch48: ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch # Fix `OpenSSL::TestSSL#test_connect_certificate_verify_failed_exception_message` # test case. # https://github.com/ruby/openssl/commit/b5a0a198505452c7457b192da2e5cd5dda04f23d -Patch48: ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch +Patch49: ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch # Fix `OpenSSL::TestPKCS12#test_{new_with_no_keys,new_with_one_key_and_one_cert}` # test failures. # https://github.com/ruby/openssl/commit/998406d18f2acf73090e9fd9d92a7b4227ac593b -Patch49: ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch +Patch50: ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch # Fix `OpenSSL::TestPKey#test_s_generate_key` test case. # https://github.com/ruby/openssl/commit/c732387ee5aaa8c5a9717e8b3ffebb3d7430e99a -Patch50: ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch +Patch51: ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch # Miscellaneous changes for OpenSSL 3.0 support. # https://github.com/ruby/openssl/pull/468 -Patch51: ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch -# Support OpenSSL 3.0. -# https://github.com/ruby/openssl/pull/399 -Patch52: ruby-3.1.0-Support-OpenSSL-3.0.patch +Patch52: ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch +# Use OSSL_DECODER to load encrypted PEM. +# https://github.com/ruby/openssl/pull/479 +Patch53: ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.patch +# Allocate EVP_PKEY on #initialize. +# https://github.com/ruby/openssl/pull/478 +Patch54: ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.patch +# Disable `OpenSSL::TestPKeyRSA#test_no_private_exp` test case which is not +# compatible with OpenSSL 3.0. +# https://github.com/ruby/ruby/commit/47975ece4096cdab16b3f200f93ea2377dfb41ac +Patch55: ruby-3.1.0-Disable-test_no_private_exp-on-OpenSSL-3.0.patch +# Deprecate PKey::*#set_* and PKey::{DH,EC}#generate_key! +# https://github.com/ruby/openssl/pull/480 +Patch56: ruby-3.1.0-Deprecate-PKey-set_-and-PKey-DH-EC-generate_key.patch +# Fix `OpenSSL::PKey::PKeyError: pkeys are immutable on OpenSSL 3.0` errors. +# https://github.com/rubygems/rubygems/pull/5196 +Patch57: rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch +# Miscellaneous changes for OpenSSL 3.0 support. +# https://github.com/ruby/openssl/pull/481 +Patch58: ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch # Fix `TestPumaControlCli#test_control_ssl` testcase in Puma. # https://github.com/ruby/openssl/pull/399#issuecomment-966239736 -Patch53: ruby-3.1.0-SSL_read-EOF-handling.patch -# Fix segfault in `TestArray#test_sample` on s390x. -# https://github.com/ruby/ruby/pull/5239 -Patch54: ruby-3.1.0-Fix-stack-buffer-overflow.patch +Patch59: ruby-3.1.0-SSL_read-EOF-handling.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -685,6 +704,7 @@ rm -rf ext/fiddle/libffi* %patch20 -p1 %patch21 -p1 %patch22 -p1 +%patch23 -p1 %patch30 -p1 -R %patch31 -p1 %patch40 -p1 @@ -702,6 +722,11 @@ rm -rf ext/fiddle/libffi* %patch52 -p1 %patch53 -p1 %patch54 -p1 +%patch55 -p1 +%patch56 -p1 +%patch57 -p1 +%patch58 -p1 +%patch59 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -980,13 +1005,6 @@ MSPECOPTS="" # Avoid `hostname' dependency. %{!?with_hostname:MSPECOPTS="-P 'Socket.gethostname returns the host name'"} -# Some tests are failing upstream due to OpenSSL 3.x compatibility. -# https://github.com/ruby/openssl/pull/399/checks?check_run_id=3716152870 -DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestEC#test_check_key/" -DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestPKeyDH#test_derive_key/" -DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestPKeyDH#test_key_exchange/" -DISABLE_TESTS="$DISABLE_TESTS -n !/OpenSSL::TestCipher#test_ciphers/" - # Several test broken by libffi-3.4.2. There should be fix in libffi, once # other components are fixed. # https://bugzilla.redhat.com/show_bug.cgi?id=2040380 @@ -1469,6 +1487,9 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Tue Jan 25 2022 Vít Ondruch - 3.0.3-158 +- Update OpenSSL 3 compatibility patches. + * Thu Jan 20 2022 Vít Ondruch - 3.0.3-158 - Disable package notes to prevent rubygem- build breakage. 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 index d61020d..d5a0673 100644 --- 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 @@ -92,10 +92,9 @@ 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. --- - .github/workflows/install-rubygems.yml | 5 ---- - lib/rubygems.rb | 32 +++++++++++++------------- - test/rubygems/test_rubygems.rb | 23 ++++++++++++++++++ - 3 files changed, 39 insertions(+), 21 deletions(-) + 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 @@ -189,8 +188,8 @@ 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. --- - bundler/spec/commands/clean_spec.rb | 2 +- - bundler/spec/install/gems/standalone_spec.rb | 2 +- + 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 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) From a51a61214c0c78df737f4badba1af8b7a429cc78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Tue, 25 Jan 2022 17:35:49 +0100 Subject: [PATCH 025/141] Drop Puma workaround. This is considered as Puma issue which should be addressed in latest release: https://github.com/puma/puma/issues/2753 --- ruby-3.1.0-SSL_read-EOF-handling.patch | 16 ---------------- ruby.spec | 4 ---- 2 files changed, 20 deletions(-) delete mode 100644 ruby-3.1.0-SSL_read-EOF-handling.patch diff --git a/ruby-3.1.0-SSL_read-EOF-handling.patch b/ruby-3.1.0-SSL_read-EOF-handling.patch deleted file mode 100644 index 1c5660f..0000000 --- a/ruby-3.1.0-SSL_read-EOF-handling.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c -index 3b425ca..40e748c 100644 ---- a/ext/openssl/ossl_ssl.c -+++ b/ext/openssl/ossl_ssl.c -@@ -1870,6 +1870,11 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) - return str; - - GetSSL(self, ssl); -+ -+#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF -+ SSL_set_options(ssl, SSL_OP_IGNORE_UNEXPECTED_EOF); -+#endif -+ - io = rb_attr_get(self, id_i_io); - GetOpenFile(io, fptr); - if (ssl_started(ssl)) { diff --git a/ruby.spec b/ruby.spec index a1273d1..f92b10d 100644 --- a/ruby.spec +++ b/ruby.spec @@ -250,9 +250,6 @@ Patch57: rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch # Miscellaneous changes for OpenSSL 3.0 support. # https://github.com/ruby/openssl/pull/481 Patch58: ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch -# Fix `TestPumaControlCli#test_control_ssl` testcase in Puma. -# https://github.com/ruby/openssl/pull/399#issuecomment-966239736 -Patch59: ruby-3.1.0-SSL_read-EOF-handling.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -726,7 +723,6 @@ rm -rf ext/fiddle/libffi* %patch56 -p1 %patch57 -p1 %patch58 -p1 -%patch59 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . From b0ce095f6d6e74a40b571143eba52c14ce04c074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Fri, 14 Jan 2022 19:20:05 +0100 Subject: [PATCH 026/141] Upgrade to Ruby 3.1.0. For details of the evolution please check `private-ruby-3.1` branch. --- ruby-1.9.3-mkmf-verbose.patch | 4 +- ...0-Enable-configuration-of-archlibdir.patch | 2 +- ...ed-paths-when-empty-version-string-i.patch | 4 +- ruby-2.1.0-always-use-i386.patch | 2 +- ruby-2.1.0-custom-rubygems-location.patch | 8 +- ruby-2.3.0-ruby_version.patch | 49 +- ruby-2.7.0-Initialize-ABRT-hook.patch | 4 +- ..._bug_reporter_add-witout-raising-err.patch | 2 +- ...onf.rb-require-OpenSSL-version-1.0.1.patch | 84 - ...-more-support-for-generic-pkey-types.patch | 1004 ------------ ....1.0-Allocate-EVP_PKEY-on-initialize.patch | 630 ------- ...-specific-options-in-sign-and-verify.patch | 358 ---- ...Key-set_-and-PKey-DH-EC-generate_key.patch | 719 -------- ...e-test_no_private_exp-on-OpenSSL-3.0.patch | 27 - ruby-3.1.0-Fix-stack-buffer-overflow.patch | 70 - ...et-rid-of-type-punning-pointer-casts.patch | 186 --- ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch | 58 - ...gn_raw-verify_raw-and-verify_recover.patch | 1319 --------------- ...he-low-level-HMAC-API-to-the-EVP-API.patch | 523 ------ ...anges-for-OpenSSL-3.0-support-part-2.patch | 458 ------ ...eous-changes-for-OpenSSL-3.0-support.patch | 304 ---- ruby-3.1.0-Properly-exclude-test-cases.patch | 93 -- ...-Refactor-PEM-DER-serialization-code.patch | 1450 ----------------- ruby-3.1.0-Support-GCCs-DWARF-5.patch | 229 --- ruby-3.1.0-Use-EVP-API-in-more-places.patch | 831 ---------- ...to-load-encrypted-PEM-on-OpenSSL-3.0.patch | 114 -- ...face-to-generate-parameters-and-keys.patch | 1113 ------------- ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch | 29 - ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch | 27 - ...t_digest-do-not-test-constants-for-l.patch | 29 - ...t_pkcs12-fix-test-failures-with-Open.patch | 439 ----- ...t_pkey-use-EC-keys-for-PKey.generate.patch | 67 - ...t_ssl-relax-regex-to-match-OpenSSL-s.patch | 31 - ...tils-remove-dup_public-helper-method.patch | 265 --- ruby.rpmlintrc | 66 +- ruby.spec | 447 +++-- ...ished-name-which-will-be-correctly-p.patch | 44 - ...ng_system-rb-customizations-too-late.patch | 261 --- ....1-Fix-compatibility-with-OpenSSL3.0.patch | 105 -- sources | 2 +- 40 files changed, 289 insertions(+), 11168 deletions(-) delete mode 100644 ruby-3.0.3-ext-openssl-extconf.rb-require-OpenSSL-version-1.0.1.patch delete mode 100644 ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch delete mode 100644 ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.patch delete mode 100644 ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch delete mode 100644 ruby-3.1.0-Deprecate-PKey-set_-and-PKey-DH-EC-generate_key.patch delete mode 100644 ruby-3.1.0-Disable-test_no_private_exp-on-OpenSSL-3.0.patch delete mode 100644 ruby-3.1.0-Fix-stack-buffer-overflow.patch delete mode 100644 ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch delete mode 100644 ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch delete mode 100644 ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch delete mode 100644 ruby-3.1.0-Migrate-from-the-low-level-HMAC-API-to-the-EVP-API.patch delete mode 100644 ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch delete mode 100644 ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch delete mode 100644 ruby-3.1.0-Properly-exclude-test-cases.patch delete mode 100644 ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch delete mode 100644 ruby-3.1.0-Support-GCCs-DWARF-5.patch delete mode 100644 ruby-3.1.0-Use-EVP-API-in-more-places.patch delete mode 100644 ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.patch delete mode 100644 ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch delete mode 100644 ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch delete mode 100644 ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch delete mode 100644 ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch delete mode 100644 ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch delete mode 100644 ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch delete mode 100644 ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch delete mode 100644 ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch delete mode 100644 rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch delete mode 100644 rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch delete mode 100644 rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch diff --git a/ruby-1.9.3-mkmf-verbose.patch b/ruby-1.9.3-mkmf-verbose.patch index b9c2c6f..2113bea 100644 --- a/ruby-1.9.3-mkmf-verbose.patch +++ b/ruby-1.9.3-mkmf-verbose.patch @@ -11,15 +11,15 @@ diff --git a/lib/mkmf.rb b/lib/mkmf.rb index 682eb46..e6b1445 100644 --- a/lib/mkmf.rb +++ b/lib/mkmf.rb -@@ -1930,7 +1930,7 @@ def configuration(srcdir) +@@ -1974,7 +1974,7 @@ def configuration(srcdir) SHELL = /bin/sh # V=0 quiet, V=1 verbose. other values don't work. -V = 0 +V = 1 + V0 = $(V:0=) Q1 = $(V:1=) Q = $(Q1:0=@) - ECHO1 = $(V:1=@ #{CONFIG['NULLCMD']}) -- 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 index 32806da..f82660f 100644 --- a/ruby-2.1.0-Enable-configuration-of-archlibdir.patch +++ b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch @@ -11,7 +11,7 @@ diff --git a/configure.ac b/configure.ac index d261ea57b5..3c13076b82 100644 --- a/configure.ac +++ b/configure.ac -@@ -3240,6 +3240,11 @@ AS_IF([test ${multiarch+set}], [ +@@ -3368,6 +3368,11 @@ AS_IF([test ${multiarch+set}], [ ]) archlibdir='${libdir}/${arch}' 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 index 118203c..041f475 100644 --- 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 @@ -14,7 +14,7 @@ diff --git a/configure.ac b/configure.ac index c42436c23d..d261ea57b5 100644 --- a/configure.ac +++ b/configure.ac -@@ -3881,7 +3881,8 @@ AS_CASE(["$ruby_version_dir_name"], +@@ -4026,7 +4026,8 @@ AS_CASE(["$ruby_version_dir_name"], ruby_version_dir=/'${ruby_version_dir_name}' if test -z "${ruby_version_dir_name}"; then @@ -66,7 +66,7 @@ diff --git a/tool/mkconfig.rb b/tool/mkconfig.rb index 07076d4..35e6c3c 100755 --- a/tool/mkconfig.rb +++ b/tool/mkconfig.rb -@@ -114,7 +114,7 @@ +@@ -115,7 +115,7 @@ val = val.gsub(/\$(?:\$|\{?(\w+)\}?)/) {$1 ? "$(#{$1})" : $&}.dump case name when /^prefix$/ diff --git a/ruby-2.1.0-always-use-i386.patch b/ruby-2.1.0-always-use-i386.patch index de58295..dffeb91 100644 --- a/ruby-2.1.0-always-use-i386.patch +++ b/ruby-2.1.0-always-use-i386.patch @@ -11,7 +11,7 @@ diff --git a/configure.ac b/configure.ac index 3c13076b82..93af30321d 100644 --- a/configure.ac +++ b/configure.ac -@@ -3945,6 +3945,8 @@ AC_SUBST(vendorarchdir)dnl +@@ -4090,6 +4090,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 diff --git a/ruby-2.1.0-custom-rubygems-location.patch b/ruby-2.1.0-custom-rubygems-location.patch index f7862fa..fdf0dfe 100644 --- a/ruby-2.1.0-custom-rubygems-location.patch +++ b/ruby-2.1.0-custom-rubygems-location.patch @@ -15,7 +15,7 @@ diff --git a/configure.ac b/configure.ac index 93af30321d..bc13397e0e 100644 --- a/configure.ac +++ b/configure.ac -@@ -3917,6 +3917,10 @@ AC_ARG_WITH(vendorarchdir, +@@ -4062,6 +4062,10 @@ AC_ARG_WITH(vendorarchdir, [vendorarchdir=$withval], [vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby'${ruby_version_dir}}${multiarch-'${vendorlibdir}/${sitearch}'}]) @@ -26,7 +26,7 @@ index 93af30321d..bc13397e0e 100644 AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) RUBY_EXEC_PREFIX='' -@@ -3941,6 +3945,7 @@ AC_SUBST(sitearchdir)dnl +@@ -4086,6 +4090,7 @@ AC_SUBST(sitearchdir)dnl AC_SUBST(vendordir)dnl AC_SUBST(vendorlibdir)dnl AC_SUBST(vendorarchdir)dnl @@ -67,7 +67,7 @@ diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb index e9110a17ca..76a1f0a315 100755 --- a/tool/rbinstall.rb +++ b/tool/rbinstall.rb -@@ -349,6 +349,7 @@ def CONFIG.[](name, mandatory = false) +@@ -359,6 +359,7 @@ def CONFIG.[](name, mandatory = false) vendorlibdir = CONFIG["vendorlibdir"] vendorarchlibdir = CONFIG["vendorarchdir"] end @@ -75,7 +75,7 @@ index e9110a17ca..76a1f0a315 100755 mandir = CONFIG["mandir", true] docdir = CONFIG["docdir", true] enable_shared = CONFIG["ENABLE_SHARED"] == 'yes' -@@ -581,7 +582,16 @@ def stub +@@ -590,7 +591,16 @@ def stub install?(:local, :comm, :lib) do prepare "library scripts", rubylibdir noinst = %w[*.txt *.rdoc *.gemspec] diff --git a/ruby-2.3.0-ruby_version.patch b/ruby-2.3.0-ruby_version.patch index b0a73a9..1f42472 100644 --- a/ruby-2.3.0-ruby_version.patch +++ b/ruby-2.3.0-ruby_version.patch @@ -20,7 +20,7 @@ diff --git a/configure.ac b/configure.ac index 80b137e380..63cd3b4f8b 100644 --- a/configure.ac +++ b/configure.ac -@@ -3832,9 +3832,6 @@ AS_CASE(["$target_os"], +@@ -3977,9 +3977,6 @@ AS_CASE(["$target_os"], rubyw_install_name='$(RUBYW_INSTALL_NAME)' ]) @@ -30,7 +30,7 @@ index 80b137e380..63cd3b4f8b 100644 rubyarchprefix=${multiarch+'${archlibdir}/${RUBY_BASE_NAME}'}${multiarch-'${rubylibprefix}/${arch}'} AC_ARG_WITH(rubyarchprefix, AS_HELP_STRING([--with-rubyarchprefix=DIR], -@@ -3857,56 +3854,62 @@ AC_ARG_WITH(ridir, +@@ -4002,56 +3999,62 @@ AC_ARG_WITH(ridir, AC_SUBST(ridir) AC_SUBST(RI_BASE_NAME) @@ -120,7 +120,7 @@ index 80b137e380..63cd3b4f8b 100644 AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) -@@ -3923,6 +3926,7 @@ AC_SUBST(sitearchincludedir)dnl +@@ -4068,6 +4071,7 @@ AC_SUBST(sitearchincludedir)dnl AC_SUBST(arch)dnl AC_SUBST(sitearch)dnl AC_SUBST(ruby_version)dnl @@ -132,14 +132,14 @@ 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@ +@@ -2,6 +2,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@ + arch=@arch@ -- 2.1.0 @@ -171,7 +171,7 @@ diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb index d4c110e..d39c9a6 100755 --- a/tool/rbinstall.rb +++ b/tool/rbinstall.rb -@@ -439,7 +439,7 @@ def CONFIG.[](name, mandatory = false) +@@ -448,7 +448,7 @@ def CONFIG.[](name, mandatory = false) install?(:doc, :rdoc) do if $rdocdir @@ -190,31 +190,24 @@ Date: Tue, 31 Mar 2015 16:37:44 +0200 Subject: [PATCH 3/4] Add ruby_version_dir_name support for RubyGems. --- - lib/rubygems/defaults.rb | 9 +++++---- + lib/rubygems/defaults.rb | 7 ++++--- test/rubygems/test_gem.rb | 5 +++-- - 2 files changed, 8 insertions(+), 6 deletions(-) + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb index d4ff4a262c..3f9a5bf590 100644 --- a/lib/rubygems/defaults.rb +++ b/lib/rubygems/defaults.rb -@@ -38,13 +38,13 @@ def self.default_dir - [ - File.dirname(RbConfig::CONFIG['sitedir']), - 'Gems', -- RbConfig::CONFIG['ruby_version'], -+ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] - ] - else - [ - RbConfig::CONFIG['rubylibprefix'], - 'gems', -- RbConfig::CONFIG['ruby_version'], -+ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] - ] - end +@@ -34,7 +34,7 @@ def self.default_spec_cache_dir + # specified in the environment -@@ -117,7 +117,8 @@ def self.user_dir + def self.default_dir +- @default_dir ||= File.join(RbConfig::CONFIG['rubylibprefix'], 'gems', RbConfig::CONFIG['ruby_version']) ++ @default_dir ||= File.join(RbConfig::CONFIG['rubylibprefix'], 'gems', RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version']) + end + + ## +@@ -103,7 +103,8 @@ def self.user_dir gem_dir = File.join(Gem.user_home, ".gem") gem_dir = File.join(Gem.data_home, "gem") unless File.exist?(gem_dir) parts = [gem_dir, ruby_engine] @@ -224,7 +217,7 @@ index d4ff4a262c..3f9a5bf590 100644 File.join parts end -@@ -252,7 +253,7 @@ def self.vendor_dir # :nodoc: +@@ -234,7 +235,7 @@ def self.vendor_dir # :nodoc: return nil unless RbConfig::CONFIG.key? 'vendordir' File.join RbConfig::CONFIG['vendordir'], 'gems', @@ -237,7 +230,7 @@ diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index b25068405d..e9fef4a311 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb -@@ -1440,7 +1440,8 @@ def test_self_use_paths +@@ -1410,7 +1410,8 @@ def test_self_use_paths def test_self_user_dir parts = [@userhome, '.gem', Gem.ruby_engine] @@ -247,7 +240,7 @@ index b25068405d..e9fef4a311 100644 FileUtils.mkdir_p File.join(parts) -@@ -1516,7 +1517,7 @@ def test_self_vendor_dir +@@ -1486,7 +1487,7 @@ def test_self_vendor_dir vendordir(File.join(@tempdir, 'vendor')) do expected = File.join RbConfig::CONFIG['vendordir'], 'gems', @@ -274,7 +267,7 @@ diff --git a/configure.ac b/configure.ac index a00f2b6776..999e2d6d5d 100644 --- a/configure.ac +++ b/configure.ac -@@ -107,7 +107,7 @@ RUBY_BASE_NAME=`echo ruby | sed "$program_transform_name"` +@@ -108,7 +108,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) diff --git a/ruby-2.7.0-Initialize-ABRT-hook.patch b/ruby-2.7.0-Initialize-ABRT-hook.patch index 2b90d9e..fc2bd08 100644 --- a/ruby-2.7.0-Initialize-ABRT-hook.patch +++ b/ruby-2.7.0-Initialize-ABRT-hook.patch @@ -43,7 +43,7 @@ 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 +@@ -82,7 +82,8 @@ ENC_MK = enc.mk MAKE_ENC = -f $(ENC_MK) V="$(V)" UNICODE_HDR_DIR="$(UNICODE_HDR_DIR)" \ RUBY="$(MINIRUBY)" MINIRUBY="$(MINIRUBY)" $(mflags) @@ -57,7 +57,7 @@ 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) +@@ -1611,10 +1611,14 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt) void Init_builtin_features(void); 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 index 64e2114..5c7afe8 100644 --- 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 @@ -20,7 +20,7 @@ diff --git a/test/-ext-/bug_reporter/test_bug_reporter.rb b/test/-ext-/bug_repor 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 +@@ -22,7 +22,7 @@ def test_bug_reporter_add args = ["--disable-gems", "-r-test-/bug_reporter", "-C", tmpdir] stdin = "register_sample_bug_reporter(12345); Process.kill :SEGV, $$" 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 deleted file mode 100644 index 4b8e9ab..0000000 --- a/ruby-3.0.3-ext-openssl-extconf.rb-require-OpenSSL-version-1.0.1.patch +++ /dev/null @@ -1,84 +0,0 @@ -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.1.0-Add-more-support-for-generic-pkey-types.patch b/ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch deleted file mode 100644 index cede1aa..0000000 --- a/ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch +++ /dev/null @@ -1,1004 +0,0 @@ -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 deleted file mode 100644 index 33789b4..0000000 --- a/ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.patch +++ /dev/null @@ -1,630 +0,0 @@ -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 deleted file mode 100644 index 679411a..0000000 --- a/ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch +++ /dev/null @@ -1,358 +0,0 @@ -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 deleted file mode 100644 index d8f936e..0000000 --- a/ruby-3.1.0-Deprecate-PKey-set_-and-PKey-DH-EC-generate_key.patch +++ /dev/null @@ -1,719 +0,0 @@ -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 deleted file mode 100644 index 2b640ea..0000000 --- a/ruby-3.1.0-Disable-test_no_private_exp-on-OpenSSL-3.0.patch +++ /dev/null @@ -1,27 +0,0 @@ -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-Fix-stack-buffer-overflow.patch b/ruby-3.1.0-Fix-stack-buffer-overflow.patch deleted file mode 100644 index 4e842ff..0000000 --- a/ruby-3.1.0-Fix-stack-buffer-overflow.patch +++ /dev/null @@ -1,70 +0,0 @@ -From cc44179cb8419b0e48ef9baa6f1722603643c1a0 Mon Sep 17 00:00:00 2001 -From: Nobuyoshi Nakada -Date: Tue, 17 Aug 2021 22:01:57 +0900 -Subject: [PATCH] Fix stack buffer overflow - -https://hackerone.com/reports/1306859 ---- - include/ruby/internal/memory.h | 6 +++--- - random.c | 7 ++----- - 2 files changed, 5 insertions(+), 8 deletions(-) - -diff --git a/include/ruby/internal/memory.h b/include/ruby/internal/memory.h -index 7d24df4945..64f3101fc2 100644 ---- a/include/ruby/internal/memory.h -+++ b/include/ruby/internal/memory.h -@@ -110,18 +110,18 @@ extern void *alloca(); - ((var) = RBIMPL_CAST((type *)ruby_xrealloc2((void *)(var), (n), sizeof(type)))) - - #define ALLOCA_N(type,n) \ -- RBIMPL_CAST((type *)alloca(rbimpl_size_mul_or_raise(sizeof(type), (n)))) -+ RBIMPL_CAST((type *)(!(n) ? NULL : alloca(rbimpl_size_mul_or_raise(sizeof(type), (n))))) - - /* allocates _n_ bytes temporary buffer and stores VALUE including it - * in _v_. _n_ may be evaluated twice. */ - #define RB_ALLOCV(v, n) \ - ((n) < RUBY_ALLOCV_LIMIT ? \ -- ((v) = 0, alloca(n)) : \ -+ ((v) = 0, !(n) ? NULL : alloca(n)) : \ - rb_alloc_tmp_buffer(&(v), (n))) - #define RB_ALLOCV_N(type, v, n) \ - RBIMPL_CAST((type *) \ - (((size_t)(n) < RUBY_ALLOCV_LIMIT / sizeof(type)) ? \ -- ((v) = 0, alloca((n) * sizeof(type))) : \ -+ ((v) = 0, !(n) ? NULL : alloca((n) * sizeof(type))) : \ - rb_alloc_tmp_buffer2(&(v), (n), sizeof(type)))) - #define RB_ALLOCV_END(v) rb_free_tmp_buffer(&(v)) - -diff --git a/random.c b/random.c -index 7567d13dd7..4d70c17116 100644 ---- a/random.c -+++ b/random.c -@@ -369,15 +369,12 @@ rand_init(const rb_random_interface_t *rng, rb_random_t *rnd, VALUE seed) - int sign; - - len = rb_absint_numwords(seed, 32, NULL); -+ if (len == 0) len = 1; - buf = ALLOCV_N(uint32_t, buf0, len); - sign = rb_integer_pack(seed, buf, len, sizeof(uint32_t), 0, - INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER); - if (sign < 0) - sign = -sign; -- if (len == 0) { -- buf[0] = 0; -- len = 1; -- } - if (len > 1) { - if (sign != 2 && buf[len-1] == 1) /* remove leading-zero-guard */ - len--; -@@ -814,7 +811,7 @@ rand_mt_init(rb_random_t *rnd, const uint32_t *buf, size_t len) - { - struct MT *mt = &((rb_random_mt_t *)rnd)->mt; - if (len <= 1) { -- init_genrand(mt, buf[0]); -+ init_genrand(mt, len ? buf[0] : 0); - } - else { - init_by_array(mt, buf, (int)len); --- -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 deleted file mode 100644 index ae8f722..0000000 --- a/ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch +++ /dev/null @@ -1,186 +0,0 @@ -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 deleted file mode 100644 index 86f534d..0000000 --- a/ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch +++ /dev/null @@ -1,58 +0,0 @@ -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 deleted file mode 100644 index a558cec..0000000 --- a/ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch +++ /dev/null @@ -1,1319 +0,0 @@ -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 deleted file mode 100644 index d25cae9..0000000 --- a/ruby-3.1.0-Migrate-from-the-low-level-HMAC-API-to-the-EVP-API.patch +++ /dev/null @@ -1,523 +0,0 @@ -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 deleted file mode 100644 index b906c19..0000000 --- a/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch +++ /dev/null @@ -1,458 +0,0 @@ -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 deleted file mode 100644 index a780108..0000000 --- a/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch +++ /dev/null @@ -1,304 +0,0 @@ -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 deleted file mode 100644 index ca2cd9b..0000000 --- a/ruby-3.1.0-Properly-exclude-test-cases.patch +++ /dev/null @@ -1,93 +0,0 @@ -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 deleted file mode 100644 index d1de216..0000000 --- a/ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch +++ /dev/null @@ -1,1450 +0,0 @@ -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 deleted file mode 100644 index d9b434a..0000000 --- a/ruby-3.1.0-Support-GCCs-DWARF-5.patch +++ /dev/null @@ -1,229 +0,0 @@ -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 deleted file mode 100644 index f9c4580..0000000 --- a/ruby-3.1.0-Use-EVP-API-in-more-places.patch +++ /dev/null @@ -1,831 +0,0 @@ -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 deleted file mode 100644 index dfdd690..0000000 --- a/ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.patch +++ /dev/null @@ -1,114 +0,0 @@ -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 deleted file mode 100644 index d02ce45..0000000 --- a/ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch +++ /dev/null @@ -1,1113 +0,0 @@ -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-addr2line-DW_FORM_ref_addr.patch b/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch deleted file mode 100644 index b8f727d..0000000 --- a/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch +++ /dev/null @@ -1,29 +0,0 @@ -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-autoconf-2.70-add-ac-prog-cc.patch b/ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch deleted file mode 100644 index 1bd20bd..0000000 --- a/ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 912a8dcfc5369d840dcd6bf0f88ee0bac7d902d6 Mon Sep 17 00:00:00 2001 -From: Nobuyoshi Nakada -Date: Thu, 30 Sep 2021 18:24:37 +0900 -Subject: [PATCH] Needs `AC_PROG_CC` - -Although `AC_PROG_CC_C99` has been obsolete, `AC_PROG_CC` is not -and the latter is necessary not to make C++ compiler mandatory. ---- - configure.ac | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index b24a8f59b0..c7059ee1ec 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -203,7 +203,7 @@ rb_test_CXXFLAGS=${CXXFLAGS+yes} - # BSD's ports and MacPorts prefix GNU binutils with 'g' - - dnl Seems necessarily in order to add -std=gnu99 option for gcc 4.9. --m4_version_prereq([2.70], [], [AC_PROG_CC_C99]) -+m4_version_prereq([2.70], [AC_PROG_CC], [AC_PROG_CC_C99]) - - AC_PROG_CXX - AC_PROG_CPP --- -2.31.1 - 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 deleted file mode 100644 index 5f3445e..0000000 --- a/ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch +++ /dev/null @@ -1,29 +0,0 @@ -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 deleted file mode 100644 index 80b73d2..0000000 --- a/ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch +++ /dev/null @@ -1,439 +0,0 @@ -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 deleted file mode 100644 index ac45842..0000000 --- a/ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch +++ /dev/null @@ -1,67 +0,0 @@ -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 deleted file mode 100644 index c9421bc..0000000 --- a/ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch +++ /dev/null @@ -1,31 +0,0 @@ -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 deleted file mode 100644 index 2019380..0000000 --- a/ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch +++ /dev/null @@ -1,265 +0,0 @@ -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.rpmlintrc b/ruby.rpmlintrc index bc72c06..8a4dde6 100644 --- a/ruby.rpmlintrc +++ b/ruby.rpmlintrc @@ -15,42 +15,38 @@ addFilter(r'^rubygem-bundler\.noarch: E: non-executable-script /usr/share/gems/g # 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 ') +# https://github.com/rubygems/rubygems/issues/5255 +# https://github.com/ruby/debug/pull/481 +# https://github.com/ruby/net-ftp/pull/12 +# https://github.com/ruby/net-imap/pull/53 +# https://github.com/ruby/net-pop/pull/7 +# https://github.com/ruby/prime/pull/16 +addFilter(r'^.*: E: non-executable-script /usr/share/gems/gems/(debug|net-(ftp|imap|pop)|prime)-[\d\.]+/bin/\w+ 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/.]+$') +# Ruby provides API to set the cipher list. +addFilter(r'^ruby-libs\.\w+: W: crypto-policy-non-compliance-openssl /usr/lib(64)?/ruby/openssl.so SSL_CTX_set_cipher_list$') + +# `gethostbyname` is part of deprecated Ruby API. There is also request to drop the API altogether: +# https://bugs.ruby-lang.org/issues/13097 +# https://bugs.ruby-lang.org/issues/17944 +addFilter(r'^ruby-libs\.\w+: W: binary-or-shlib-calls-gethostbyname /usr/lib(64)?/ruby/socket.so$') # 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$') +addFilter(r'^ruby-libs\.\w+: E: shared-library-without-dependency-information /usr/lib(64)?/ruby/enc/gb2312.so$') + +# These are Ruby plugins, where Ruby always load glibc prior the library. +addFilter(r'^ruby-libs\.\w+: W: library-not-linked-against-libc /usr/lib(64)?/ruby/.*.so$') + +# Rake ships some examples. +addFilter(r'^rubygem-rake.noarch: W: devel-file-in-non-devel-package /usr/share/gems/gems/rake-[\d\.]+/doc/example/\w+.c$') + +# Some executables don't have their manual pages. Is it worth of use help2man? +addFilter(r'^.+: W: no-manual-page-for-binary (bundler|gem|rbs|rdbg|rdoc|ruby-mri|typeprof)$') + +# Default gems does not come with any documentation. +addFilter(r'^rubygem-(bigdecimal|io-console|json|psych)\.\w+: W: no-documentation$') + +# rubygems-devel ships only RPM macros and generators. Their placement is given +# by RPM and can't be modified. +addFilter(r'rubygems-devel.noarch: W: only-non-binary-in-usr-lib$') diff --git a/ruby.spec b/ruby.spec index f92b10d..01cb7bb 100644 --- a/ruby.spec +++ b/ruby.spec @@ -1,6 +1,6 @@ %global major_version 3 -%global minor_version 0 -%global teeny_version 3 +%global minor_version 1 +%global teeny_version 0 %global major_minor_version %{major_version}.%{minor_version} %global ruby_version %{major_minor_version}.%{teeny_version} @@ -10,7 +10,7 @@ #%%global milestone rc1 # Keep the revision enabled for pre-releases from GIT. -#%%global revision 684649ea05 +#%%global revision fb4df44d16 %global ruby_archive %{name}-%{ruby_version} @@ -22,7 +22,7 @@ %endif -%global release 159 +%global release 160 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -30,39 +30,49 @@ %global rubygems_dir %{_datadir}/rubygems # Bundled libraries versions -%global rubygems_version 3.2.32 +%global rubygems_version 3.3.3 %global rubygems_molinillo_version 0.7.0 # Default gems. -%global bundler_version 2.2.32 +%global bundler_version 2.3.3 %global bundler_connection_pool_version 2.3.0 %global bundler_fileutils_version 1.4.1 %global bundler_molinillo_version 0.7.0 %global bundler_net_http_persistent_version 4.0.0 %global bundler_thor_version 1.1.0 %global bundler_tmpdir_version 0.1.0 -%global bundler_uri_version 0.10.0 +# TODO: Check the version if/when available in library. +%global bundler_tsort_version 0.1.1 +%global bundler_uri_version 0.10.1 -%global bigdecimal_version 3.0.0 -%global did_you_mean_version 1.5.0 -%global erb_version 2.2.0 -%global io_console_version 0.5.7 -%global irb_version 1.3.5 -%global json_version 2.5.1 -%global openssl_version 2.2.1 -%global psych_version 3.3.2 -%global racc_version 1.5.2 -%global rdoc_version 6.3.3 +%global bigdecimal_version 3.1.1 +%global did_you_mean_version 1.6.1 +%global erb_version 2.2.3 +%global io_console_version 0.5.10 +%global irb_version 1.4.1 +%global json_version 2.6.1 +%global openssl_version 3.0.0 +%global psych_version 4.0.3 +%global racc_version 1.6.0 +%global rdoc_version 6.4.0 +%global stringio_version 3.0.1 # Bundled gems. -%global minitest_version 5.14.2 -%global power_assert_version 1.2.0 -%global rake_version 13.0.3 -%global rbs_version 1.4.0 -%global test_unit_version 3.3.7 +%global minitest_version 5.15.0 +%global power_assert_version 2.0.1 +%global rake_version 13.0.6 +%global test_unit_version 3.5.3 %global rexml_version 3.2.5 %global rss_version 0.2.9 -%global typeprof_version 0.15.2 +%global net_ftp_version 0.1.3 +%global net_imap_version 0.2.2 +%global net_pop_version 0.1.1 +%global net_smtp_version 0.3.1 +%global matrix_version 0.4.2 +%global prime_version 0.1.2 +%global rbs_version 2.0.0 +%global typeprof_version 0.21.1 +%global debug_version 1.4.0 %global tapset_libdir %(echo %{_libdir} | sed 's/64//')* @@ -142,114 +152,9 @@ Patch5: ruby-1.9.3-mkmf-verbose.patch # https://lists.fedoraproject.org/archives/list/ruby-sig@lists.fedoraproject.org/message/LH6L6YJOYQT4Y5ZNOO4SLIPTUWZ5V45Q/ # For now, load the ABRT hook via this simple patch: Patch6: ruby-2.7.0-Initialize-ABRT-hook.patch -# Fix DWARF5 support. -# https://bugzilla.redhat.com/show_bug.cgi?id=1920533 -# https://bugs.ruby-lang.org/issues/17585 -# https://github.com/ruby/ruby/pull/4240 -Patch15: ruby-3.1.0-Support-GCCs-DWARF-5.patch -# Fix segfaults with enabled LTO. -# https://bugs.ruby-lang.org/issues/18062 -# https://github.com/ruby/ruby/pull/4716 -Patch16: ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch -# DWARF5/LTO fixes for SIGSEV handler. -# https://bugs.ruby-lang.org/issues/17052 -# https://github.com/ruby/ruby/commit/72317b333b85eed483ad00bcd4f40944019a7c13 -Patch17: ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch -# https://bugs.ruby-lang.org/issues/17052#note-9 -# https://bugs.ruby-lang.org/attachments/download/8974/ruby-addr2line-DW_FORM_ref_addr.patch -# https://github.com/ruby/ruby/commit/a9977ba2f9863e3fb1b2346589ebbca67d80536c -Patch18: ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch # Avoid possible timeout errors in TestBugReporter#test_bug_reporter_add. # https://bugs.ruby-lang.org/issues/16492 Patch19: ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch -# Add AC_PROG_CC to make C++ compiler dependency optional on autoconf >= 2.70. -# https://github.com/ruby/ruby/commit/912a8dcfc5369d840dcd6bf0f88ee0bac7d902d6 -Patch20: ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch -# Allow to exclude test with fully qualified name. -# https://bugs.ruby-lang.org/issues/16936 -# https://github.com/ruby/ruby/pull/5026 -Patch21: ruby-3.1.0-Properly-exclude-test-cases.patch -# Fix loading of default gems. -# https://bugzilla.redhat.com/show_bug.cgi?id=2027099 -# https://github.com/rubygems/rubygems/pull/5154 -Patch22: rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch -# Fix segfault in `TestArray#test_sample` on s390x. -# https://github.com/ruby/ruby/pull/5239 -Patch23: ruby-3.1.0-Fix-stack-buffer-overflow.patch - - -# OpenSSL 3.0 compatibility patches - -# Revert OpenSSL < 3.x enforcement. -# https://github.com/ruby/openssl/commit/202ff1372a40a8adf9aac74bfe8a39141b0c57e5 -Patch30: ruby-3.0.3-ext-openssl-extconf.rb-require-OpenSSL-version-1.0.1.patch - -# Fix test broken by wrongly formatted distinguished name submitted to -# `OpenSSL::X509::Name.parse`. -# https://github.com/ruby/openssl/issues/470 -# https://github.com/rubygems/rubygems/pull/5030 -Patch31: rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch - -# Refactor PEM/DER serialization code. -# https://github.com/ruby/openssl/pull/328 -Patch40: ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch -# Implement more 'generic' operations using the EVP API. -# https://github.com/ruby/openssl/pull/329 -Patch41: ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch -# Migrate from the low-level HMAC API to the EVP API. -# https://github.com/ruby/openssl/pull/371 -Patch42: ruby-3.1.0-Migrate-from-the-low-level-HMAC-API-to-the-EVP-API.patch -# Allow setting algorithm-specific options in #sign and #verify. -# https://github.com/ruby/openssl/pull/374 -Patch43: ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch -# Use high level EVP interface to generate parameters and keys. -# https://github.com/ruby/openssl/pull/397 -Patch44: ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch -# Use EVP API in more places. -# https://github.com/ruby/openssl/pull/436 -Patch45: ruby-3.1.0-Use-EVP-API-in-more-places.patch -# Implement PKey#{encrypt,decrypt,sign_raw,verify_{raw,verify_recover}}. -# https://github.com/ruby/openssl/pull/382 -Patch46: ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch -# Fix `OpenSSL::TestSSL#test_dup` test failure. -# https://github.com/ruby/openssl/commit/7b66eaa2dbabb6570dbbbdfac24c4dcdcc6793d7 -Patch47: ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch -# Fix `OpenSSL::TestDigest#test_digest_constants` test case. -# https://github.com/ruby/openssl/commit/a3e59f4c2e200c76ef1d93945ff8737a05715e17 -Patch48: ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch -# Fix `OpenSSL::TestSSL#test_connect_certificate_verify_failed_exception_message` -# test case. -# https://github.com/ruby/openssl/commit/b5a0a198505452c7457b192da2e5cd5dda04f23d -Patch49: ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch -# Fix `OpenSSL::TestPKCS12#test_{new_with_no_keys,new_with_one_key_and_one_cert}` -# test failures. -# https://github.com/ruby/openssl/commit/998406d18f2acf73090e9fd9d92a7b4227ac593b -Patch50: ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch -# Fix `OpenSSL::TestPKey#test_s_generate_key` test case. -# https://github.com/ruby/openssl/commit/c732387ee5aaa8c5a9717e8b3ffebb3d7430e99a -Patch51: ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch -# Miscellaneous changes for OpenSSL 3.0 support. -# https://github.com/ruby/openssl/pull/468 -Patch52: ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch -# Use OSSL_DECODER to load encrypted PEM. -# https://github.com/ruby/openssl/pull/479 -Patch53: ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.patch -# Allocate EVP_PKEY on #initialize. -# https://github.com/ruby/openssl/pull/478 -Patch54: ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.patch -# Disable `OpenSSL::TestPKeyRSA#test_no_private_exp` test case which is not -# compatible with OpenSSL 3.0. -# https://github.com/ruby/ruby/commit/47975ece4096cdab16b3f200f93ea2377dfb41ac -Patch55: ruby-3.1.0-Disable-test_no_private_exp-on-OpenSSL-3.0.patch -# Deprecate PKey::*#set_* and PKey::{DH,EC}#generate_key! -# https://github.com/ruby/openssl/pull/480 -Patch56: ruby-3.1.0-Deprecate-PKey-set_-and-PKey-DH-EC-generate_key.patch -# Fix `OpenSSL::PKey::PKeyError: pkeys are immutable on OpenSSL 3.0` errors. -# https://github.com/rubygems/rubygems/pull/5196 -Patch57: rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch -# Miscellaneous changes for OpenSSL 3.0 support. -# https://github.com/ruby/openssl/pull/481 -Patch58: ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -257,7 +162,6 @@ Recommends: ruby(rubygems) >= %{rubygems_version} Recommends: rubygem(bigdecimal) >= %{bigdecimal_version} BuildRequires: autoconf -BuildRequires: gdbm-devel %{?with_gmp:BuildRequires: gmp-devel} BuildRequires: libffi-devel BuildRequires: openssl-devel @@ -385,6 +289,7 @@ Obsoletes: rubygem-racc < 1.4.16-130 # Obsoleted by Ruby 3.0 in F34 timeframe. Obsoletes: rubygem-openssl < 2.2.0-145 Provides: rubygem(openssl) = %{openssl_version}-%{release} +Provides: rubygem(stringio) = %{stringio_version} BuildArch: noarch %description default-gems @@ -422,6 +327,7 @@ Requires: ruby(release) Requires: ruby(rubygems) >= %{rubygems_version} Requires: rubygem(io-console) >= %{io_console_version} Requires: rubygem(json) >= %{json_version} +Requires: rubygem(psych) >= %{psych_version} Provides: rdoc = %{version}-%{release} Provides: ri = %{version}-%{release} Provides: rubygem(rdoc) = %{version}-%{release} @@ -497,6 +403,7 @@ Version: %{psych_version} License: MIT Requires: ruby(release) Requires: ruby(rubygems) >= %{rubygems_version} +Requires: rubygem(stringio) >= %{stringio_version} Provides: rubygem(psych) = %{version}-%{release} %description -n rubygem-psych @@ -534,6 +441,22 @@ many machines, systematically and repeatably. # These are regular packages, which might be installed just optionally. Users # should list them among their dependencies (in Gemfile). +%package bundled-gems +Summary: Bundled gems which are part of Ruby StdLib +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(net-ftp) = %{net_ftp_version} +Provides: rubygem(net-imap) = %{net_imap_version} +Provides: rubygem(net-pop) = %{net_pop_version} +Provides: rubygem(net-smtp) = %{net_smtp_version} +Provides: rubygem(matrix) = %{matrix_version} +Provides: rubygem(prime) = %{prime_version} +Provides: rubygem(debug) = %{debug_version} + +%description bundled-gems +Bundled gems which are part of Ruby StdLib. While being part of Ruby, these +needs to be listed in Gemfile to be used by Bundler. + + %package -n rubygem-minitest Summary: Minitest provides a complete suite of testing facilities Version: %{minitest_version} @@ -595,7 +518,6 @@ License: Ruby or BSD Requires: ruby(release) Requires: ruby(rubygems) >= %{rubygems_version} Provides: rubygem(rbs) = %{version}-%{release} -BuildArch: noarch %description -n rubygem-rbs RBS is the language for type signatures for Ruby and standard library @@ -693,36 +615,7 @@ rm -rf ext/fiddle/libffi* %patch4 -p1 %patch5 -p1 %patch6 -p1 -%patch15 -p1 -%patch16 -p1 -%patch17 -p1 -%patch18 -p1 %patch19 -p1 -%patch20 -p1 -%patch21 -p1 -%patch22 -p1 -%patch23 -p1 -%patch30 -p1 -R -%patch31 -p1 -%patch40 -p1 -%patch41 -p1 -%patch42 -p1 -%patch43 -p1 -%patch44 -p1 -%patch45 -p1 -%patch46 -p1 -%patch47 -p1 -%patch48 -p1 -%patch49 -p1 -%patch50 -p1 -%patch51 -p1 -%patch52 -p1 -%patch53 -p1 -%patch54 -p1 -%patch55 -p1 -%patch56 -p1 -%patch57 -p1 -%patch58 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -756,6 +649,14 @@ autoconf %install rm -rf %{buildroot} + +# Workaround binary extensions installation issues. +# https://bugs.ruby-lang.org/issues/18373 +find .bundle -name extconf.rb -exec \ + sed -i \ + -e '/create_makefile/i \$arch_hdrdir = "$(hdrdir)/../.ext/include/$(arch)"' \ + -e '/create_makefile/i \$DLDFLAGS << " -L#{$top_srcdir}"' {} \; + %make_install # TODO: Regenerate RBS parser in lib/rbs/parser.rb @@ -878,10 +779,16 @@ ln -s %{_libdir}/gems/%{name}/psych-%{psych_version}/psych.so %{buildroot}%{ruby # Move the binary extensions into proper place (if no gem has binary extension, # the extensions directory might be empty). +# TODO: Get information about extension form .gemspec files. find %{buildroot}%{gem_dir}/extensions/*-%{_target_os}/%{ruby_version}/* -maxdepth 0 \ + -exec rm '{}/gem_make.out' \; \ -exec mv '{}' %{buildroot}%{_libdir}/gems/%{name}/ \; \ || echo "No gem binary extensions to move." +# Remove the extension sources and library copies from `lib` dir. +find %{buildroot}%{gem_dir}/gems/*/ext -maxdepth 0 -exec rm -rf '{}' + +find %{buildroot}%{gem_dir}/gems/*/lib -name \*.so -delete + # Move man pages into proper location mkdir -p %{buildroot}%{_mandir}/man{1,5} mv %{buildroot}%{gem_dir}/gems/rake-%{rake_version}/doc/rake.1 %{buildroot}%{_mandir}/man1 @@ -957,7 +864,10 @@ checksec --file=libruby.so.%{ruby_version} | \ == '%{bundler_molinillo_version}' ] # Net::HTTP::Persistent. -[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ +# Require `rubygems` to workaround the `': uninitialized +# constant Gem (NameError) issue. +# https://github.com/rubygems/rubygems/issues/5119 +[ "`make runruby TESTRUN_SCRIPT=\"-rrubygems -e \\\" \ module Bundler; module Persistent; module Net; module HTTP; \ end; end; end; end; \ require 'bundler/vendor/net-http-persistent/lib/net/http/persistent'; \ @@ -1001,6 +911,16 @@ MSPECOPTS="" # Avoid `hostname' dependency. %{!?with_hostname:MSPECOPTS="-P 'Socket.gethostname returns the host name'"} +# https://bugs.ruby-lang.org/issues/18380 +DISABLE_TESTS="$DISABLE_TESTS -n !/TestAddressResolve#test_socket_getnameinfo_domain_blocking/" + +%ifarch armv7hl +# TestReadline#test_interrupt_in_other_thread fails on 32 bit arches according +# to upstream, but the test is disabled just on Travis, not in test suite. +# https://bugs.ruby-lang.org/issues/18393 +DISABLE_TESTS="$DISABLE_TESTS -n !/TestReadline#test_interrupt_in_other_thread/" +%endif + # Several test broken by libffi-3.4.2. There should be fix in libffi, once # other components are fixed. # https://bugzilla.redhat.com/show_bug.cgi?id=2040380 @@ -1063,28 +983,26 @@ mv test/fiddle/test_import.rb{,.disable} %{ruby_libdir}/coverage.rb %{ruby_libdir}/csv* %{ruby_libdir}/date.rb -%{ruby_libdir}/debug.rb %{ruby_libdir}/delegate* %{ruby_libdir}/digest* %{ruby_libdir}/drb* %{ruby_libdir}/English.rb -%{ruby_libdir}/erb.rb +%{ruby_libdir}/erb* +%{ruby_libdir}/error_highlight* %{ruby_libdir}/expect.rb %{ruby_libdir}/fiddle* %{ruby_libdir}/fileutils.rb %{ruby_libdir}/find.rb %{ruby_libdir}/forwardable* %{ruby_libdir}/getoptlong* -%{ruby_libdir}/io %{ruby_libdir}/ipaddr.rb %{ruby_libdir}/kconv.rb %{ruby_libdir}/logger* -%{ruby_libdir}/matrix* %{ruby_libdir}/mkmf.rb %{ruby_libdir}/monitor.rb %{ruby_libdir}/mutex_m.rb %{ruby_libdir}/net -%{ruby_libdir}/objspace.rb +%{ruby_libdir}/objspace* %{ruby_libdir}/observer* %{ruby_libdir}/open-uri.rb %{ruby_libdir}/open3* @@ -1094,8 +1012,8 @@ mv test/fiddle/test_import.rb{,.disable} %{ruby_libdir}/pathname.rb %{ruby_libdir}/pp.rb %{ruby_libdir}/prettyprint.rb -%{ruby_libdir}/prime.rb %{ruby_libdir}/pstore* +%{ruby_libdir}/random %{ruby_libdir}/readline.rb %{ruby_libdir}/reline* %{ruby_libdir}/resolv.rb @@ -1112,7 +1030,6 @@ mv test/fiddle/test_import.rb{,.disable} %{ruby_libdir}/timeout* %{ruby_libdir}/time.rb %{ruby_libdir}/tmpdir.rb -%{ruby_libdir}/tracer* %{ruby_libdir}/tsort.rb %{ruby_libdir}/unicode_normalize %{ruby_libdir}/un.rb @@ -1121,14 +1038,13 @@ mv test/fiddle/test_import.rb{,.disable} %{ruby_libdir}/yaml* # Platform specific libraries. -%{_libdir}/libruby.so.* +%{_libdir}/libruby.so.{%{major_minor_version},%{ruby_version}} %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 @@ -1201,9 +1117,7 @@ mv test/fiddle/test_import.rb{,.disable} %{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 @@ -1264,77 +1178,69 @@ mv test/fiddle/test_import.rb{,.disable} %files default-gems %{gem_dir}/specifications/default/abbrev-0.1.0.gemspec -%{gem_dir}/specifications/default/base64-0.1.0.gemspec -%{gem_dir}/specifications/default/benchmark-0.1.1.gemspec -%{gem_dir}/specifications/default/cgi-0.2.1.gemspec -%{gem_dir}/specifications/default/csv-3.1.9.gemspec -%{gem_dir}/specifications/default/date-3.1.3.gemspec -%{gem_dir}/specifications/default/dbm-1.1.0.gemspec -%{gem_dir}/specifications/default/debug-0.2.1.gemspec +%{gem_dir}/specifications/default/base64-0.1.1.gemspec +%{gem_dir}/specifications/default/benchmark-0.2.0.gemspec +%{gem_dir}/specifications/default/cgi-0.3.1.gemspec +%{gem_dir}/specifications/default/csv-3.2.2.gemspec +%{gem_dir}/specifications/default/date-3.2.2.gemspec %{gem_dir}/specifications/default/delegate-0.2.0.gemspec %{gem_dir}/specifications/default/did_you_mean-%{did_you_mean_version}.gemspec -%{gem_dir}/specifications/default/digest-3.0.0.gemspec -%{gem_dir}/specifications/default/drb-2.0.5.gemspec +%{gem_dir}/specifications/default/digest-3.1.0.gemspec +%{gem_dir}/specifications/default/drb-2.1.0.gemspec %{gem_dir}/specifications/default/english-0.7.1.gemspec %{gem_dir}/specifications/default/erb-%{erb_version}.gemspec +%{gem_dir}/specifications/default/error_highlight-0.3.0.gemspec %{gem_dir}/specifications/default/etc-1.3.0.gemspec %{gem_dir}/specifications/default/fcntl-1.0.1.gemspec -%{gem_dir}/specifications/default/fiddle-1.0.8.gemspec -%{gem_dir}/specifications/default/fileutils-1.5.0.gemspec -%{gem_dir}/specifications/default/find-0.1.0.gemspec +%{gem_dir}/specifications/default/fiddle-1.1.0.gemspec +%{gem_dir}/specifications/default/fileutils-1.6.0.gemspec +%{gem_dir}/specifications/default/find-0.1.1.gemspec %{gem_dir}/specifications/default/forwardable-1.3.2.gemspec -%{gem_dir}/specifications/default/gdbm-2.1.0.gemspec %{gem_dir}/specifications/default/getoptlong-0.1.1.gemspec %{gem_dir}/specifications/default/io-nonblock-0.1.0.gemspec -%{gem_dir}/specifications/default/io-wait-0.2.0.gemspec -%{gem_dir}/specifications/default/ipaddr-1.2.2.gemspec -%{gem_dir}/specifications/default/logger-1.4.3.gemspec -%{gem_dir}/specifications/default/matrix-0.3.1.gemspec +%{gem_dir}/specifications/default/io-wait-0.2.1.gemspec +%{gem_dir}/specifications/default/ipaddr-1.2.3.gemspec +%{gem_dir}/specifications/default/logger-1.5.0.gemspec %{gem_dir}/specifications/default/mutex_m-0.1.1.gemspec -%{gem_dir}/specifications/default/net-ftp-0.1.2.gemspec -%{gem_dir}/specifications/default/net-http-0.1.1.gemspec -%{gem_dir}/specifications/default/net-imap-0.1.1.gemspec -%{gem_dir}/specifications/default/net-pop-0.1.1.gemspec -%{gem_dir}/specifications/default/net-protocol-0.1.1.gemspec -%{gem_dir}/specifications/default/net-smtp-0.2.1.gemspec -%{gem_dir}/specifications/default/nkf-0.1.0.gemspec +%{gem_dir}/specifications/default/net-http-0.2.0.gemspec +%{gem_dir}/specifications/default/net-protocol-0.1.2.gemspec +%{gem_dir}/specifications/default/nkf-0.1.1.gemspec %{gem_dir}/specifications/default/observer-0.1.1.gemspec %{gem_dir}/specifications/default/open3-0.1.1.gemspec -%{gem_dir}/specifications/default/open-uri-0.1.0.gemspec -%{gem_dir}/specifications/default/optparse-0.1.1.gemspec +%{gem_dir}/specifications/default/open-uri-0.2.0.gemspec +%{gem_dir}/specifications/default/optparse-0.2.0.gemspec %{gem_dir}/specifications/default/openssl-%{openssl_version}.gemspec -%{gem_dir}/specifications/default/ostruct-0.3.1.gemspec -%{gem_dir}/specifications/default/pathname-0.1.0.gemspec -%{gem_dir}/specifications/default/pp-0.2.1.gemspec +%{gem_dir}/specifications/default/ostruct-0.5.2.gemspec +%{gem_dir}/specifications/default/pathname-0.2.0.gemspec +%{gem_dir}/specifications/default/pp-0.3.0.gemspec %{gem_dir}/specifications/default/prettyprint-0.1.1.gemspec -%{gem_dir}/specifications/default/prime-0.1.2.gemspec %{gem_dir}/specifications/default/pstore-0.1.1.gemspec %{gem_dir}/specifications/default/racc-%{racc_version}.gemspec -%{gem_dir}/specifications/default/readline-0.0.2.gemspec -%{gem_dir}/specifications/default/readline-ext-0.1.1.gemspec -%{gem_dir}/specifications/default/reline-0.2.5.gemspec +%{gem_dir}/specifications/default/readline-0.0.3.gemspec +%{gem_dir}/specifications/default/readline-ext-0.1.4.gemspec +%{gem_dir}/specifications/default/reline-0.3.0.gemspec %{gem_dir}/specifications/default/resolv-0.2.1.gemspec %{gem_dir}/specifications/default/resolv-replace-0.1.0.gemspec %{gem_dir}/specifications/default/rinda-0.1.1.gemspec -%{gem_dir}/specifications/default/securerandom-0.1.0.gemspec -%{gem_dir}/specifications/default/set-1.0.1.gemspec +%{gem_dir}/specifications/default/ruby2_keywords-0.0.5.gemspec +%{gem_dir}/specifications/default/securerandom-0.1.1.gemspec +%{gem_dir}/specifications/default/set-1.0.2.gemspec %{gem_dir}/specifications/default/shellwords-0.1.0.gemspec %{gem_dir}/specifications/default/singleton-0.1.1.gemspec -%{gem_dir}/specifications/default/stringio-3.0.1.gemspec +%{gem_dir}/specifications/default/stringio-%{stringio_version}.gemspec %{gem_dir}/specifications/default/strscan-3.0.1.gemspec %{gem_dir}/specifications/default/syslog-0.1.0.gemspec -%{gem_dir}/specifications/default/tempfile-0.1.1.gemspec -%{gem_dir}/specifications/default/time-0.1.0.gemspec -%{gem_dir}/specifications/default/timeout-0.1.1.gemspec +%{gem_dir}/specifications/default/tempfile-0.1.2.gemspec +%{gem_dir}/specifications/default/time-0.2.0.gemspec +%{gem_dir}/specifications/default/timeout-0.2.0.gemspec %{gem_dir}/specifications/default/tmpdir-0.1.2.gemspec %{gem_dir}/specifications/default/tsort-0.1.0.gemspec -%{gem_dir}/specifications/default/tracer-0.1.1.gemspec -%{gem_dir}/specifications/default/un-0.1.0.gemspec -%{gem_dir}/specifications/default/uri-0.10.1.gemspec +%{gem_dir}/specifications/default/un-0.2.0.gemspec +%{gem_dir}/specifications/default/uri-0.11.0.gemspec %{gem_dir}/specifications/default/weakref-0.1.1.gemspec #%%{gem_dir}/specifications/default/win32ole-1.8.8.gemspec -%{gem_dir}/specifications/default/yaml-0.1.1.gemspec -%{gem_dir}/specifications/default/zlib-2.0.0.gemspec +%{gem_dir}/specifications/default/yaml-0.2.0.gemspec +%{gem_dir}/specifications/default/zlib-2.1.1.gemspec %{gem_dir}/gems/erb-%{erb_version} # Use standalone rubygem-racc if Racc binary is required. Shipping this @@ -1390,7 +1296,8 @@ mv test/fiddle/test_import.rb{,.disable} %{ruby_libdir}/psych.rb %{ruby_libarchdir}/psych.so %{_libdir}/gems/%{name}/psych-%{psych_version} -%{gem_dir}/gems/psych-%{psych_version} +%dir %{gem_dir}/gems/psych-%{psych_version} +%{gem_dir}/gems/psych-%{psych_version}/lib %{gem_dir}/specifications/psych-%{psych_version}.gemspec %files -n rubygem-bundler @@ -1401,15 +1308,95 @@ mv test/fiddle/test_import.rb{,.disable} %{_mandir}/man1/bundle*.1* %{_mandir}/man5/gemfile.5* +%files bundled-gems +%{_bindir}/rdbg +%dir %{_libdir}/gems/%{name}/debug-%{debug_version} +%{_libdir}/gems/%{name}/debug-%{debug_version}/gem.build_complete +%dir %{_libdir}/gems/%{name}/debug-%{debug_version}/debug +%{_libdir}/gems/%{name}/debug-%{debug_version}/debug/debug.so +%dir %{gem_dir}/gems/debug-%{debug_version} +%exclude %{gem_dir}/gems/debug-%{debug_version}/.* +%doc %{gem_dir}/gems/debug-%{debug_version}/CONTRIBUTING.md +%{gem_dir}/gems/debug-%{debug_version}/Gemfile +%license %{gem_dir}/gems/debug-%{debug_version}/LICENSE.txt +%doc %{gem_dir}/gems/debug-%{debug_version}/README.md +%{gem_dir}/gems/debug-%{debug_version}/Rakefile +%doc %{gem_dir}/gems/debug-%{debug_version}/TODO.md +%{gem_dir}/gems/debug-%{debug_version}/bin +%{gem_dir}/gems/debug-%{debug_version}/exe +%{gem_dir}/gems/debug-%{debug_version}/lib +%{gem_dir}/gems/debug-%{debug_version}/misc +%{gem_dir}/specifications/debug-%{debug_version}.gemspec + +%dir %{gem_dir}/gems/net-ftp-%{net_ftp_version} +%{gem_dir}/gems/net-ftp-%{net_ftp_version}/Gemfile +%license %{gem_dir}/gems/net-ftp-%{net_ftp_version}/LICENSE.txt +%doc %{gem_dir}/gems/net-ftp-%{net_ftp_version}/README.md +%{gem_dir}/gems/net-ftp-%{net_ftp_version}/Rakefile +%{gem_dir}/gems/net-ftp-%{net_ftp_version}/bin +%{gem_dir}/gems/net-ftp-%{net_ftp_version}/lib +%{gem_dir}/specifications/net-ftp-%{net_ftp_version}.gemspec + +%dir %{gem_dir}/gems/net-imap-%{net_imap_version} +%{gem_dir}/gems/net-imap-%{net_imap_version}/Gemfile +%license %{gem_dir}/gems/net-imap-%{net_imap_version}/LICENSE.txt +%doc %{gem_dir}/gems/net-imap-%{net_imap_version}/README.md +%{gem_dir}/gems/net-imap-%{net_imap_version}/Rakefile +%{gem_dir}/gems/net-imap-%{net_imap_version}/bin +%{gem_dir}/gems/net-imap-%{net_imap_version}/lib +%{gem_dir}/specifications/net-imap-%{net_imap_version}.gemspec + +%dir %{gem_dir}/gems/net-pop-%{net_pop_version} +%{gem_dir}/gems/net-pop-%{net_pop_version}/Gemfile +%license %{gem_dir}/gems/net-pop-%{net_pop_version}/LICENSE.txt +%doc %{gem_dir}/gems/net-pop-%{net_pop_version}/README.md +%{gem_dir}/gems/net-pop-%{net_pop_version}/Rakefile +%{gem_dir}/gems/net-pop-%{net_pop_version}/bin +%{gem_dir}/gems/net-pop-%{net_pop_version}/lib +%{gem_dir}/specifications/net-pop-%{net_pop_version}.gemspec + +%dir %{gem_dir}/gems/net-smtp-%{net_smtp_version} +%license %{gem_dir}/gems/net-smtp-%{net_smtp_version}/LICENSE.txt +%{gem_dir}/gems/net-smtp-%{net_smtp_version}/lib +%{gem_dir}/specifications/net-smtp-%{net_smtp_version}.gemspec + +%dir %{gem_dir}/gems/matrix-%{matrix_version} +%license %{gem_dir}/gems/matrix-%{matrix_version}/LICENSE.txt +%{gem_dir}/gems/matrix-%{matrix_version}/lib +%{gem_dir}/specifications/matrix-%{matrix_version}.gemspec + +%dir %{gem_dir}/gems/prime-%{prime_version} +%{gem_dir}/gems/prime-%{prime_version}/Gemfile +%license %{gem_dir}/gems/prime-%{prime_version}/LICENSE.txt +%doc %{gem_dir}/gems/prime-%{prime_version}/README.md +%{gem_dir}/gems/prime-%{prime_version}/Rakefile +%{gem_dir}/gems/prime-%{prime_version}/bin +%{gem_dir}/gems/prime-%{prime_version}/lib +%{gem_dir}/specifications/prime-%{prime_version}.gemspec + %files -n rubygem-minitest -%{gem_dir}/gems/minitest-%{minitest_version} +%dir %{gem_dir}/gems/minitest-%{minitest_version} %exclude %{gem_dir}/gems/minitest-%{minitest_version}/.* +%{gem_dir}/gems/minitest-%{minitest_version}/Manifest.txt +%{gem_dir}/gems/minitest-%{minitest_version}/design_rationale.rb +%{gem_dir}/gems/minitest-%{minitest_version}/lib %{gem_dir}/specifications/minitest-%{minitest_version}.gemspec +%doc %{gem_dir}/gems/minitest-%{minitest_version}/History.rdoc +%doc %{gem_dir}/gems/minitest-%{minitest_version}/README.rdoc +%{gem_dir}/gems/minitest-%{minitest_version}/Rakefile +%{gem_dir}/gems/minitest-%{minitest_version}/test %files -n rubygem-power_assert -%{gem_dir}/gems/power_assert-%{power_assert_version} +%dir %{gem_dir}/gems/power_assert-%{power_assert_version} %exclude %{gem_dir}/gems/power_assert-%{power_assert_version}/.* +%license %{gem_dir}/gems/power_assert-%{power_assert_version}/BSDL +%license %{gem_dir}/gems/power_assert-%{power_assert_version}/COPYING +%license %{gem_dir}/gems/power_assert-%{power_assert_version}/LEGAL +%{gem_dir}/gems/power_assert-%{power_assert_version}/lib %{gem_dir}/specifications/power_assert-%{power_assert_version}.gemspec +%{gem_dir}/gems/power_assert-%{power_assert_version}/Gemfile +%doc %{gem_dir}/gems/power_assert-%{power_assert_version}/README.md +%{gem_dir}/gems/power_assert-%{power_assert_version}/Rakefile %files -n rubygem-rake %{_bindir}/rake @@ -1419,6 +1406,9 @@ mv test/fiddle/test_import.rb{,.disable} %files -n rubygem-rbs %{_bindir}/rbs +%dir %{_libdir}/gems/%{name}/rbs-%{rbs_version} +%{_libdir}/gems/%{name}/rbs-%{rbs_version}/gem.build_complete +%{_libdir}/gems/%{name}/rbs-%{rbs_version}/rbs_extension.so %dir %{gem_dir}/gems/rbs-%{rbs_version} %exclude %{gem_dir}/gems/rbs-%{rbs_version}/.* %license %{gem_dir}/gems/rbs-%{rbs_version}/BSDL @@ -1440,8 +1430,16 @@ mv test/fiddle/test_import.rb{,.disable} %{gem_dir}/specifications/rbs-%{rbs_version}.gemspec %files -n rubygem-test-unit -%{gem_dir}/gems/test-unit-%{test_unit_version} +%dir %{gem_dir}/gems/test-unit-%{test_unit_version} +%license %{gem_dir}/gems/test-unit-%{test_unit_version}/BSDL +%license %{gem_dir}/gems/test-unit-%{test_unit_version}/COPYING +%license %{gem_dir}/gems/test-unit-%{test_unit_version}/PSFL +%{gem_dir}/gems/test-unit-%{test_unit_version}/lib +%{gem_dir}/gems/test-unit-%{test_unit_version}/sample %{gem_dir}/specifications/test-unit-%{test_unit_version}.gemspec +%doc %{gem_dir}/gems/test-unit-%{test_unit_version}/README.md +%{gem_dir}/gems/test-unit-%{test_unit_version}/Rakefile +%doc %{gem_dir}/gems/test-unit-%{test_unit_version}/doc %files -n rubygem-rexml %dir %{gem_dir}/gems/rexml-%{rexml_version} @@ -1471,19 +1469,20 @@ mv test/fiddle/test_import.rb{,.disable} %license %{gem_dir}/gems/typeprof-%{typeprof_version}/LICENSE %{gem_dir}/gems/typeprof-%{typeprof_version}/exe %{gem_dir}/gems/typeprof-%{typeprof_version}/lib -%doc %{gem_dir}/gems/typeprof-%{typeprof_version}/smoke %doc %{gem_dir}/gems/typeprof-%{typeprof_version}/tools +%exclude %{gem_dir}/gems/typeprof-%{typeprof_version}/typeprof-lsp +%exclude %{gem_dir}/gems/typeprof-%{typeprof_version}/vscode %{gem_dir}/specifications/typeprof-%{typeprof_version}.gemspec %doc %{gem_dir}/gems/typeprof-%{typeprof_version}/Gemfile* %doc %{gem_dir}/gems/typeprof-%{typeprof_version}/README.md %doc %{gem_dir}/gems/typeprof-%{typeprof_version}/Rakefile -%doc %{gem_dir}/gems/typeprof-%{typeprof_version}/doc -%lang(ja) %doc %{gem_dir}/gems/typeprof-%{typeprof_version}/doc/doc.ja.md -%doc %{gem_dir}/gems/typeprof-%{typeprof_version}/testbed %changelog -* Tue Jan 25 2022 Vít Ondruch - 3.0.3-158 +* Wed Jan 26 2022 Vít Ondruch - 3.1.0-160 +- Upgrade to Ruby 3.1.0. + +* Tue Jan 25 2022 Vít Ondruch - 3.0.3-159 - Update OpenSSL 3 compatibility patches. * Thu Jan 20 2022 Vít Ondruch - 3.0.3-158 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 deleted file mode 100644 index 433d03e..0000000 --- a/rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch +++ /dev/null @@ -1,44 +0,0 @@ -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 deleted file mode 100644 index d5a0673..0000000 --- a/rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch +++ /dev/null @@ -1,261 +0,0 @@ -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 deleted file mode 100644 index b405b5f..0000000 --- a/rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch +++ /dev/null @@ -1,105 +0,0 @@ -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/sources b/sources index 2b40f22..31675a3 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (ruby-3.0.3.tar.xz) = bb9ea426278d5a7ac46595296f03b82d43df8b7db41045cdf85611e05e26c703c53f700494cd7cf5d4c27fa953bdc5c144317d7720812db0a6e3b6f4bc4d2e00 +SHA512 (ruby-3.1.0.tar.xz) = a2bb6b5e62d5fa06dd9c30cf84ddcb2c27cb87fbaaffd2309a44391a6b110e1dde6b7b0d8c659b56387ee3c9b4264003f3532d5a374123a7c187ebba9293f320 From 1ff09bed2b1d1ea893d595ad1689f8b1132a0321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Tue, 18 Jan 2022 12:55:59 +0100 Subject: [PATCH 027/141] Temporary bump rubygem-json release. This allow to rebuild independent rubygem-json package, which would have otherwise higher release and caused issues with build of other packages. --- ruby.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/ruby.spec b/ruby.spec index 01cb7bb..5cfbca6 100644 --- a/ruby.spec +++ b/ruby.spec @@ -384,6 +384,7 @@ 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} +Release: 201~1%{dist} # UCD: ext/json/generator/generator.c License: (Ruby or GPLv2) and UCD Requires: ruby(release) From 8157cd4820ed4e2775fbd1f1a2a5d67a3becdfbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Wed, 26 Jan 2022 15:33:43 +0100 Subject: [PATCH 028/141] Revert "Temporary bump rubygem-json release." This reverts commit 1ff09bed2b1d1ea893d595ad1689f8b1132a0321. --- ruby.spec | 1 - 1 file changed, 1 deletion(-) diff --git a/ruby.spec b/ruby.spec index 5cfbca6..01cb7bb 100644 --- a/ruby.spec +++ b/ruby.spec @@ -384,7 +384,6 @@ 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} -Release: 201~1%{dist} # UCD: ext/json/generator/generator.c License: (Ruby or GPLv2) and UCD Requires: ruby(release) From 204bab4f7f31ad5cdc8f6b5d747be6eb06a85123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Thu, 10 Feb 2022 14:12:41 +0100 Subject: [PATCH 029/141] Prevent segfaults running with SystemTap. --- ...ery-RubyVM-FrozenCore-for-class-path.patch | 43 +++++++++++++++++++ ruby.spec | 12 +++++- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 ruby-3.1.0-Don-t-query-RubyVM-FrozenCore-for-class-path.patch 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..973fe72 --- /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 +@@ -479,7 +479,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.spec b/ruby.spec index 01cb7bb..c831fa5 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 160 +%global release 161 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -152,6 +152,12 @@ Patch5: ruby-1.9.3-mkmf-verbose.patch # https://lists.fedoraproject.org/archives/list/ruby-sig@lists.fedoraproject.org/message/LH6L6YJOYQT4Y5ZNOO4SLIPTUWZ5V45Q/ # For now, load the ABRT hook via this simple patch: Patch6: ruby-2.7.0-Initialize-ABRT-hook.patch +# Prevent segfaults running with SystemTap due to `RubyVM::FrozenCore` being +# corrupted by GC. +# https://bugzilla.redhat.com/show_bug.cgi?id=2015441 +# https://bugzilla.redhat.com/show_bug.cgi?id=1986206 +# https://bugs.ruby-lang.org/issues/18257 +Patch7: ruby-3.1.0-Don-t-query-RubyVM-FrozenCore-for-class-path.patch # Avoid possible timeout errors in TestBugReporter#test_bug_reporter_add. # https://bugs.ruby-lang.org/issues/16492 Patch19: ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch @@ -615,6 +621,7 @@ rm -rf ext/fiddle/libffi* %patch4 -p1 %patch5 -p1 %patch6 -p1 +%patch7 -p1 %patch19 -p1 # Provide an example of usage of the tapset: @@ -1479,6 +1486,9 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Thu Feb 10 2022 Vít Ondruch - 3.1.0-161 +- Prevent segfaults running with SystemTap. + * Wed Jan 26 2022 Vít Ondruch - 3.1.0-160 - Upgrade to Ruby 3.1.0. From 67d5a7b3c6d1146bcb1a1e8cb5a6e5b2f35be339 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Mon, 14 Mar 2022 11:27:34 +0100 Subject: [PATCH 030/141] Revert "Remove colon from `load` call." This is for a compatibility of Zuul CI still using RPM 4.16 on F34. This reverts commit 46ee70614f22238e1ccb177e379fbcf53bdb36b6. --- ruby.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby.spec b/ruby.spec index c831fa5..fd9899e 100644 --- a/ruby.spec +++ b/ruby.spec @@ -123,8 +123,8 @@ 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}} +%{load:%{SOURCE4}} +%{load:%{SOURCE5}} # Fix ruby_version abuse. # https://bugs.ruby-lang.org/issues/11002 From 74983bcd567f31b3ae1774b08f9f2094fdd2640b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Tue, 15 Mar 2022 13:25:19 +0100 Subject: [PATCH 031/141] Upgrade to Ruby 3.1.1. --- ruby.spec | 26 ++++++++++++++------------ sources | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/ruby.spec b/ruby.spec index fd9899e..b44669b 100644 --- a/ruby.spec +++ b/ruby.spec @@ -1,6 +1,6 @@ %global major_version 3 %global minor_version 1 -%global teeny_version 0 +%global teeny_version 1 %global major_minor_version %{major_version}.%{minor_version} %global ruby_version %{major_minor_version}.%{teeny_version} @@ -22,7 +22,7 @@ %endif -%global release 161 +%global release 162 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -30,16 +30,16 @@ %global rubygems_dir %{_datadir}/rubygems # Bundled libraries versions -%global rubygems_version 3.3.3 +%global rubygems_version 3.3.7 %global rubygems_molinillo_version 0.7.0 # Default gems. -%global bundler_version 2.3.3 +%global bundler_version 2.3.7 %global bundler_connection_pool_version 2.3.0 %global bundler_fileutils_version 1.4.1 %global bundler_molinillo_version 0.7.0 %global bundler_net_http_persistent_version 4.0.0 -%global bundler_thor_version 1.1.0 +%global bundler_thor_version 1.2.1 %global bundler_tmpdir_version 0.1.0 # TODO: Check the version if/when available in library. %global bundler_tsort_version 0.1.1 @@ -48,7 +48,7 @@ %global bigdecimal_version 3.1.1 %global did_you_mean_version 1.6.1 %global erb_version 2.2.3 -%global io_console_version 0.5.10 +%global io_console_version 0.5.11 %global irb_version 1.4.1 %global json_version 2.6.1 %global openssl_version 3.0.0 @@ -65,13 +65,13 @@ %global rexml_version 3.2.5 %global rss_version 0.2.9 %global net_ftp_version 0.1.3 -%global net_imap_version 0.2.2 +%global net_imap_version 0.2.3 %global net_pop_version 0.1.1 %global net_smtp_version 0.3.1 %global matrix_version 0.4.2 %global prime_version 0.1.2 -%global rbs_version 2.0.0 -%global typeprof_version 0.21.1 +%global rbs_version 2.1.0 +%global typeprof_version 0.21.2 %global debug_version 1.4.0 %global tapset_libdir %(echo %{_libdir} | sed 's/64//')* @@ -787,7 +787,7 @@ ln -s %{_libdir}/gems/%{name}/psych-%{psych_version}/psych.so %{buildroot}%{ruby # Move the binary extensions into proper place (if no gem has binary extension, # the extensions directory might be empty). # TODO: Get information about extension form .gemspec files. -find %{buildroot}%{gem_dir}/extensions/*-%{_target_os}/%{ruby_version}/* -maxdepth 0 \ +find %{buildroot}%{gem_dir}/extensions/*-%{_target_os}/%{major_minor_version}.*/* -maxdepth 0 \ -exec rm '{}/gem_make.out' \; \ -exec mv '{}' %{buildroot}%{_libdir}/gems/%{name}/ \; \ || echo "No gem binary extensions to move." @@ -1206,7 +1206,7 @@ mv test/fiddle/test_import.rb{,.disable} %{gem_dir}/specifications/default/getoptlong-0.1.1.gemspec %{gem_dir}/specifications/default/io-nonblock-0.1.0.gemspec %{gem_dir}/specifications/default/io-wait-0.2.1.gemspec -%{gem_dir}/specifications/default/ipaddr-1.2.3.gemspec +%{gem_dir}/specifications/default/ipaddr-1.2.4.gemspec %{gem_dir}/specifications/default/logger-1.5.0.gemspec %{gem_dir}/specifications/default/mutex_m-0.1.1.gemspec %{gem_dir}/specifications/default/net-http-0.2.0.gemspec @@ -1349,7 +1349,6 @@ mv test/fiddle/test_import.rb{,.disable} %license %{gem_dir}/gems/net-imap-%{net_imap_version}/LICENSE.txt %doc %{gem_dir}/gems/net-imap-%{net_imap_version}/README.md %{gem_dir}/gems/net-imap-%{net_imap_version}/Rakefile -%{gem_dir}/gems/net-imap-%{net_imap_version}/bin %{gem_dir}/gems/net-imap-%{net_imap_version}/lib %{gem_dir}/specifications/net-imap-%{net_imap_version}.gemspec @@ -1486,6 +1485,9 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Mon Mar 14 2022 Vít Ondruch - 3.1.1-162 +- Upgrade to Ruby 3.1.1. + * Thu Feb 10 2022 Vít Ondruch - 3.1.0-161 - Prevent segfaults running with SystemTap. diff --git a/sources b/sources index 31675a3..b5357ad 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (ruby-3.1.0.tar.xz) = a2bb6b5e62d5fa06dd9c30cf84ddcb2c27cb87fbaaffd2309a44391a6b110e1dde6b7b0d8c659b56387ee3c9b4264003f3532d5a374123a7c187ebba9293f320 +SHA512 (ruby-3.1.1.tar.xz) = 8877fa9a458964a59a11529cd10b3d25b5f6238cd4678b6dcea0bd4b750499cf8ff39d8824053b4ab26c5cd0cfb604a57807ce61580175857fcf00b2cff3e55f From 9e774fba706a3a1031ca95840e254a64a9eeebbb Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Mon, 14 Mar 2022 18:06:54 +0100 Subject: [PATCH 032/141] ruby.rpmlintrc: Ignore zero-length error for gem.build_complete file. This error is gone as false positive in rpmlint 2.0+. However the rpmlint version on Zuul CI running on the Fedora 34 container is still 1.11. After Zuul CI is upgraded to Fedora 35+ container, and uses the rpmlint 2, we can notice this filter is not used by "E: unused-rpmlintrc-filter" error, and remove it. --- ruby.rpmlintrc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ruby.rpmlintrc b/ruby.rpmlintrc index 8a4dde6..d59d364 100644 --- a/ruby.rpmlintrc +++ b/ruby.rpmlintrc @@ -50,3 +50,7 @@ addFilter(r'^rubygem-(bigdecimal|io-console|json|psych)\.\w+: W: no-documentatio # rubygems-devel ships only RPM macros and generators. Their placement is given # by RPM and can't be modified. addFilter(r'rubygems-devel.noarch: W: only-non-binary-in-usr-lib$') + +# The empty gem.build_complete file is false positive. This error is gone in rpmlint 2.0+. +# https://github.com/rpm-software-management/rpmlint/commit/e34ce874f27d733628f51c9884ac951af072bed2 +addFilter(r'^ruby(gem)?-(bigdecimal|bundled-gems|io-console|json|psych|rbs)\.\w+: E: zero-length /usr/lib(64)?/gems/ruby/.*/gem.build_complete') From df8cc89df48ecabd4af7cf490301d0795fa3708c Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Mon, 14 Mar 2022 19:47:41 +0100 Subject: [PATCH 033/141] ruby.rpmlintrc: Recover the filter to ignore a false positive missing-call-to-chdir-with-chroot error. The filter was deleted at the b0ce095f6d6e74a40b571143eba52c14ce04c074 . But it is still needed to pass Zuul CI. --- ruby.rpmlintrc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ruby.rpmlintrc b/ruby.rpmlintrc index d59d364..85d91b9 100644 --- a/ruby.rpmlintrc +++ b/ruby.rpmlintrc @@ -38,6 +38,17 @@ addFilter(r'^ruby-libs\.\w+: E: shared-library-without-dependency-information /u # These are Ruby plugins, where Ruby always load glibc prior the library. addFilter(r'^ruby-libs\.\w+: W: library-not-linked-against-libc /usr/lib(64)?/ruby/.*.so$') +# 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.N.N.N +# 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/.]+$') + # Rake ships some examples. addFilter(r'^rubygem-rake.noarch: W: devel-file-in-non-devel-package /usr/share/gems/gems/rake-[\d\.]+/doc/example/\w+.c$') From aee17a21802d113ed3c065540ddd1eab7592a42b Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Mon, 14 Mar 2022 19:55:01 +0100 Subject: [PATCH 034/141] ruby.rpmlintrc: Add a filter for "E: shared-lib-without-dependency-information". Add a filter for "E: shared-lib-without-dependency-information" for rpmlint 1.11 compatibility in Zuul CI. --- ruby.rpmlintrc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruby.rpmlintrc b/ruby.rpmlintrc index 85d91b9..0c2b585 100644 --- a/ruby.rpmlintrc +++ b/ruby.rpmlintrc @@ -34,6 +34,8 @@ addFilter(r'^ruby-libs\.\w+: W: binary-or-shlib-calls-gethostbyname /usr/lib(64) # 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-library-without-dependency-information /usr/lib(64)?/ruby/enc/gb2312.so$') +# Compatibility for rpmlint 1.11. +addFilter(r'^ruby-libs\.\w+: E: shared-lib-without-dependency-information /usr/lib(64)?/ruby/enc/gb2312.so$') # These are Ruby plugins, where Ruby always load glibc prior the library. addFilter(r'^ruby-libs\.\w+: W: library-not-linked-against-libc /usr/lib(64)?/ruby/.*.so$') From 796a198176b693f1cd3245546b3aa8f984daf639 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Fri, 4 Mar 2022 13:50:28 +0100 Subject: [PATCH 035/141] Add Bundler tests. * Add `make test-bundler-parallel` executed on the upstream CI. See . * The tests are disabled as a default, as it requires the internet. Run the Bundler tests as follows. ``` $ mock --with bundler_tests ruby-3.1.0-161.fc37.src.rpm ``` * Fix a test for `bin/bundle update --bundler` in `make test-bundler`. --- ...0-bundle-update-bundler-test-in-ruby.patch | 31 +++++++++++++++++++ ruby.spec | 11 +++++++ 2 files changed, 42 insertions(+) create mode 100644 ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch diff --git a/ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch b/ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch new file mode 100644 index 0000000..b208537 --- /dev/null +++ b/ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch @@ -0,0 +1,31 @@ +From bfa2f72cfa3bfde34049d26dcb24976316074ad7 Mon Sep 17 00:00:00 2001 +From: Jun Aruga +Date: Mon, 21 Mar 2022 15:36:51 +0100 +Subject: [PATCH] Fix a test for `bin/bundle update --bundler` to pass on + ruby/ruby. + +Consider the case that the latest Bundler version on RubyGems is higher than +the `system_bundler_version` (= `Bundler::VERSION`) in `make test-bundler` on +ruby/ruby. + +See . +--- + spec/bundler/commands/binstubs_spec.rb | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/spec/bundler/commands/binstubs_spec.rb b/spec/bundler/commands/binstubs_spec.rb +index 198226207bc..2634f43417c 100644 +--- a/spec/bundler/commands/binstubs_spec.rb ++++ b/spec/bundler/commands/binstubs_spec.rb +@@ -226,7 +226,10 @@ + + it "calls through to the latest bundler version" do + sys_exec "bin/bundle update --bundler", :env => { "DEBUG" => "1" } +- expect(out).to include %(Using bundler #{system_bundler_version}\n) ++ using_bundler_line = /Using bundler ([\w\.]+)\n/.match(out) ++ expect(using_bundler_line).to_not be_nil ++ latest_version = using_bundler_line[1] ++ expect(Gem::Version.new(latest_version)).to be >= Gem::Version.new(system_bundler_version) + end + + it "calls through to the explicit bundler version" do diff --git a/ruby.spec b/ruby.spec index b44669b..7e37172 100644 --- a/ruby.spec +++ b/ruby.spec @@ -85,6 +85,8 @@ %bcond_without gmp %bcond_without hostname %bcond_without systemtap +# Enable test when building on local. +%bcond_with bundler_tests %if 0%{?fedora} %bcond_without hardening_test @@ -161,6 +163,10 @@ Patch7: ruby-3.1.0-Don-t-query-RubyVM-FrozenCore-for-class-path.patch # Avoid possible timeout errors in TestBugReporter#test_bug_reporter_add. # https://bugs.ruby-lang.org/issues/16492 Patch19: ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch +# Fix a test for `bin/bundle update --bundler` in `make test-bundler`. +# https://bugs.ruby-lang.org/issues/18643 +# https://github.com/rubygems/rubygems/commit/bfa2f72cfa3bfde34049d26dcb24976316074ad7 +Patch20: ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -186,6 +192,8 @@ BuildRequires: multilib-rpm-config BuildRequires: gcc BuildRequires: make BuildRequires: zlib-devel +# The bundler/spec/runtime/setup_spec.rb requires the command `man`. +%{?with_bundler_tests:BuildRequires: %{_bindir}/man} # This package provides %%{_bindir}/ruby-mri therefore it is marked by this # virtual provide. It can be installed as dependency of rubypick. @@ -623,6 +631,7 @@ rm -rf ext/fiddle/libffi* %patch6 -p1 %patch7 -p1 %patch19 -p1 +%patch20 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -938,6 +947,8 @@ mv test/fiddle/test_import.rb{,.disable} %{?test_timeout_scale:RUBY_TEST_TIMEOUT_SCALE="%{test_timeout_scale}"} \ make check TESTS="-v $DISABLE_TESTS" MSPECOPT="-fs $MSPECOPTS" +%{?with_bundler_tests:make test-bundler-parallel} + %files %license BSDL %license COPYING From 22d91a091076f5aabd70c345381e44755235ca91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Mon, 4 Apr 2022 12:10:29 +0200 Subject: [PATCH 036/141] Properly build binary gem extensions. Because the gem extensions were built in `%{buildroot}` they referred `BUILDROOT` directory, which would be under normal circumstances reported by RPM, but there was a bug in RPM due to changes in grep: https://github.com/rpm-software-management/rpm/issues/1968 --- ...Properly-build-binary-gem-extensions.patch | 231 ++++++++++++++++++ ruby.spec | 18 +- 2 files changed, 240 insertions(+), 9 deletions(-) create mode 100644 ruby-3.1.1-Properly-build-binary-gem-extensions.patch diff --git a/ruby-3.1.1-Properly-build-binary-gem-extensions.patch b/ruby-3.1.1-Properly-build-binary-gem-extensions.patch new file mode 100644 index 0000000..17cb836 --- /dev/null +++ b/ruby-3.1.1-Properly-build-binary-gem-extensions.patch @@ -0,0 +1,231 @@ +From 0da0152986f7d1e666aeb1317d18746250423575 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Thu, 31 Mar 2022 19:12:24 +0200 +Subject: [PATCH 1/4] Properly install expanded gem extensions. + +The expanded gem location changed from 'gem' to '.bundled/gems' +directory in commit:git|55bf0ef1aa7c936b564b883196de1ace4be4cc7e / + #2922, leaving behind binary extension installation. This should fix +the issues, so the gem binary extensions are buildable as part of Ruby +build process again. +--- + ext/extmk.rb | 13 ++++++------- + template/exts.mk.tmpl | 4 ++-- + tool/rbinstall.rb | 4 ++-- + 3 files changed, 10 insertions(+), 11 deletions(-) + +diff --git a/ext/extmk.rb b/ext/extmk.rb +index 4a087f294ac9..bc0e4f135d8e 100755 +--- a/ext/extmk.rb ++++ b/ext/extmk.rb +@@ -146,7 +146,7 @@ def extmake(target, basedir = 'ext', maybestatic = true) + top_srcdir = $top_srcdir + topdir = $topdir + hdrdir = $hdrdir +- prefix = "../" * (target.count("/")+1) ++ prefix = "../" * (target.count("/") + basedir.count("/")) + $top_srcdir = relative_from(top_srcdir, prefix) + $hdrdir = relative_from(hdrdir, prefix) + $topdir = prefix + $topdir +@@ -461,15 +461,15 @@ def $mflags.defined?(var) + + @gemname = nil + if ARGV[0] +- ext_prefix, exts = ARGV.shift.split('/', 2) ++ ext_prefix, exts = File.split(ARGV.shift) + $extension = [exts] if exts +- if ext_prefix == 'gems' ++ if ext_prefix == '.bundle/gems' + @gemname = exts + elsif exts + $static_ext.delete_if {|t, *| !File.fnmatch(t, exts)} + end + end +-ext_prefix = "#{$top_srcdir}/#{ext_prefix || 'ext'}" ++ext_prefix = "#{$top_srcdir}/#{ext_prefix || './ext'}" + exts = $static_ext.sort_by {|t, i| i}.collect {|t, i| t} + default_exclude_exts = + case +@@ -515,7 +515,6 @@ def $mflags.defined?(var) + exts.delete_if {|d| File.fnmatch?("-*", d)} + end + end +-ext_prefix = File.basename(ext_prefix) + + extend Module.new { + def timestamp_file(name, target_prefix = nil) +@@ -534,7 +533,7 @@ def create_makefile(*args, &block) + super(*args) do |conf| + conf.find do |s| + s.sub!(/^(TARGET_SO_DIR *= *)\$\(RUBYARCHDIR\)/) { +- "TARGET_GEM_DIR = $(extout)/gems/$(arch)/#{@gemname}\n"\ ++ "TARGET_GEM_DIR = $(extout)/.bundle/gems/$(arch)/#{@gemname}\n"\ + "#{$1}$(TARGET_GEM_DIR)$(target_prefix)" + } + end +@@ -634,7 +633,7 @@ def initialize(src) + end + } + +-Dir.chdir ".." ++Dir.chdir dir + unless $destdir.to_s.empty? + $mflags.defined?("DESTDIR") or $mflags << "DESTDIR=#{$destdir}" + end +diff --git a/template/exts.mk.tmpl b/template/exts.mk.tmpl +index 2f37f4480ac5..401ea9a497f3 100644 +--- a/template/exts.mk.tmpl ++++ b/template/exts.mk.tmpl +@@ -19,13 +19,13 @@ opt = OptionParser.new do |o| + o.on('--configure-exts=FILE') {|v| confexts = v} + o.order!(ARGV) + end +-confexts &&= File.read(confexts).scan(/^exts: (.*\.mk)/).flatten rescue nil ++confexts &&= File.read(confexts).scan(/^(exts|gems): (.*\.mk)/).collect {|i| i.last } rescue nil + confexts ||= [] + macros["old_extensions"] = [] + + contpat = /(?>(?>[^\\\n]|\\.)*\\\n)*(?>[^\\\n]|\\.)*/ + Dir.glob("{ext,.bundle/gems}/*/exts.mk") do |e| +- gem = /\Agems(?=\/)/ =~ e ++ gem = /\A.bundle\/gems(?=\/)/ =~ e + s = File.read(e) + s.scan(/^(extensions|SUBMAKEOPTS|EXT[A-Z]+|MFLAGS|NOTE_[A-Z]+)[ \t]*=[ \t]*(#{contpat})$/o) do |n, v| + v.gsub!(/\\\n[ \t]*/, ' ') +diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb +index 9d9b672be472..8c8a14193ec9 100755 +--- a/tool/rbinstall.rb ++++ b/tool/rbinstall.rb +@@ -1047,7 +1047,7 @@ def install_default_gem(dir, srcdir, bindir) + :wrappers => true, + :format_executable => true, + } +- gem_ext_dir = "#$extout/gems/#{CONFIG['arch']}" ++ gem_ext_dir = "#$extout/.bundle/gems/#{CONFIG['arch']}" + extensions_dir = with_destdir(Gem::StubSpecification.gemspec_stub("", gem_dir, gem_dir).extensions_dir) + + File.foreach("#{srcdir}/gems/bundled_gems") do |name| +@@ -1080,7 +1080,7 @@ def install_default_gem(dir, srcdir, bindir) + File.chmod($data_mode, File.join(install_dir, "specifications", "#{spec.full_name}.gemspec")) + end + unless spec.extensions.empty? +- install_recursive(ext, spec.extension_dir) ++ install_recursive(ext, without_destdir(spec.extension_dir)) + end + installed_gems[spec.full_name] = true + end + +From 8c57deb09dbd9005ebc872c3c9147d6c2924e208 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Thu, 31 Mar 2022 19:22:15 +0200 +Subject: [PATCH 2/4] Re-enable building gem extensions. + +This reverts commit bac6e8ca5d8f6bc45984d12ddad55d3d876d4324. +--- + template/configure-ext.mk.tmpl | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/template/configure-ext.mk.tmpl b/template/configure-ext.mk.tmpl +index 6636a7759c54..8ba6b963e3ec 100644 +--- a/template/configure-ext.mk.tmpl ++++ b/template/configure-ext.mk.tmpl +@@ -27,7 +27,7 @@ SCRIPT_ARGS = <%=script_args.gsub("#", "\\#")%> + EXTMK_ARGS = $(SCRIPT_ARGS) --gnumake=$(gnumake) --extflags="$(EXTLDFLAGS)" \ + --make-flags="MINIRUBY='$(MINIRUBY)'" + +-all: exts # gems ++all: exts gems + exts: + gems: + + +From ee6a16eed10c3ab6e4cc8285ca137e83964e0f5c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Fri, 1 Apr 2022 16:26:04 +0200 +Subject: [PATCH 3/4] Trust that .gemspec correctly declare their extensions. + +Do not judge the extension availability by the available extension +build. This is already assumed on other places anyway: + +https://github.com/ruby/ruby/blob/d1d48cb690fdad855da94b2a2d11721428bc06ba/tool/rbinstall.rb#L1062 +--- + tool/rbinstall.rb | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb +index 8c8a14193ec9..259792ad878c 100755 +--- a/tool/rbinstall.rb ++++ b/tool/rbinstall.rb +@@ -1069,9 +1069,6 @@ def install_default_gem(dir, srcdir, bindir) + next + end + spec.extension_dir = "#{extensions_dir}/#{spec.full_name}" +- if File.directory?(ext = "#{gem_ext_dir}/#{spec.full_name}") +- spec.extensions[0] ||= "-" +- end + package = RbInstall::DirPackage.new spec + ins = RbInstall::UnpackedInstaller.new(package, options) + puts "#{INDENT}#{spec.name} #{spec.version}" +@@ -1080,6 +1077,7 @@ def install_default_gem(dir, srcdir, bindir) + File.chmod($data_mode, File.join(install_dir, "specifications", "#{spec.full_name}.gemspec")) + end + unless spec.extensions.empty? ++ ext = "#{gem_ext_dir}/#{spec.full_name}" + install_recursive(ext, without_destdir(spec.extension_dir)) + end + installed_gems[spec.full_name] = true + +From d11bc592494529f8732a4a40defaf18f600c261d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Mon, 4 Apr 2022 11:18:51 +0200 +Subject: [PATCH 4/4] Install the previously build gem extensions. + +Install the pre-build gem binary extensions and attempt to build them +during `gem install` phase only when they are not available for whatever +reason. +--- + tool/rbinstall.rb | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb +index 259792ad878c..4e42133bc1ce 100755 +--- a/tool/rbinstall.rb ++++ b/tool/rbinstall.rb +@@ -901,6 +901,18 @@ def write_default_spec + super unless $dryrun + $installed_list.puts(without_destdir(default_spec_file)) if $installed_list + end ++ ++ def build_extensions ++ return if spec.extensions.empty? ++ ++ ext = "#$extout/.bundle/gems/#{CONFIG['arch']}/#{spec.full_name}" ++ ++ # Call `install_recursive` with global binding, so it correctly use ++ # the global `install` ++ Object.__send__ :install_recursive, ext, without_destdir(spec.extension_dir) ++ ++ super unless File.exist? spec.gem_build_complete_path ++ end + end + + class GemInstaller +@@ -1047,7 +1059,6 @@ def install_default_gem(dir, srcdir, bindir) + :wrappers => true, + :format_executable => true, + } +- gem_ext_dir = "#$extout/.bundle/gems/#{CONFIG['arch']}" + extensions_dir = with_destdir(Gem::StubSpecification.gemspec_stub("", gem_dir, gem_dir).extensions_dir) + + File.foreach("#{srcdir}/gems/bundled_gems") do |name| +@@ -1076,10 +1087,6 @@ def install_default_gem(dir, srcdir, bindir) + unless $dryrun + File.chmod($data_mode, File.join(install_dir, "specifications", "#{spec.full_name}.gemspec")) + end +- unless spec.extensions.empty? +- ext = "#{gem_ext_dir}/#{spec.full_name}" +- install_recursive(ext, without_destdir(spec.extension_dir)) +- end + installed_gems[spec.full_name] = true + end + installed_gems, gems = Dir.glob(srcdir+'/gems/*.gem').partition {|gem| installed_gems.key?(File.basename(gem, '.gem'))} diff --git a/ruby.spec b/ruby.spec index 7e37172..c0aac4d 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 162 +%global release 163 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -167,6 +167,10 @@ Patch19: ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch # https://bugs.ruby-lang.org/issues/18643 # https://github.com/rubygems/rubygems/commit/bfa2f72cfa3bfde34049d26dcb24976316074ad7 Patch20: ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch +# Workaround gem binary extensions build and installation issues. +# https://bugs.ruby-lang.org/issues/18373 +# https://github.com/ruby/ruby/pull/5743 +Patch21: ruby-3.1.1-Properly-build-binary-gem-extensions.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -632,6 +636,7 @@ rm -rf ext/fiddle/libffi* %patch7 -p1 %patch19 -p1 %patch20 -p1 +%patch21 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -666,13 +671,6 @@ autoconf %install rm -rf %{buildroot} -# Workaround binary extensions installation issues. -# https://bugs.ruby-lang.org/issues/18373 -find .bundle -name extconf.rb -exec \ - sed -i \ - -e '/create_makefile/i \$arch_hdrdir = "$(hdrdir)/../.ext/include/$(arch)"' \ - -e '/create_makefile/i \$DLDFLAGS << " -L#{$top_srcdir}"' {} \; - %make_install # TODO: Regenerate RBS parser in lib/rbs/parser.rb @@ -797,7 +795,6 @@ ln -s %{_libdir}/gems/%{name}/psych-%{psych_version}/psych.so %{buildroot}%{ruby # the extensions directory might be empty). # TODO: Get information about extension form .gemspec files. find %{buildroot}%{gem_dir}/extensions/*-%{_target_os}/%{major_minor_version}.*/* -maxdepth 0 \ - -exec rm '{}/gem_make.out' \; \ -exec mv '{}' %{buildroot}%{_libdir}/gems/%{name}/ \; \ || echo "No gem binary extensions to move." @@ -1496,6 +1493,9 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Mon Apr 04 2022 Vít Ondruch - 3.1.1-163 +- Properly build binary gem extensions. + * Mon Mar 14 2022 Vít Ondruch - 3.1.1-162 - Upgrade to Ruby 3.1.1. From 09d0e79c2bb0d3198c556ac250bc4b82f68cb0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Thu, 14 Apr 2022 13:37:12 +0200 Subject: [PATCH 037/141] Upgrade to Ruby 3.1.2. --- ruby.spec | 7 +++++-- sources | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ruby.spec b/ruby.spec index c0aac4d..fa01783 100644 --- a/ruby.spec +++ b/ruby.spec @@ -1,6 +1,6 @@ %global major_version 3 %global minor_version 1 -%global teeny_version 1 +%global teeny_version 2 %global major_minor_version %{major_version}.%{minor_version} %global ruby_version %{major_minor_version}.%{teeny_version} @@ -22,7 +22,7 @@ %endif -%global release 163 +%global release 164 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -1493,6 +1493,9 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Thu Apr 14 2022 Vít Ondruch - 3.1.2-164 +- Upgrade to Ruby 3.1.2. + * Mon Apr 04 2022 Vít Ondruch - 3.1.1-163 - Properly build binary gem extensions. diff --git a/sources b/sources index b5357ad..9cefc8d 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (ruby-3.1.1.tar.xz) = 8877fa9a458964a59a11529cd10b3d25b5f6238cd4678b6dcea0bd4b750499cf8ff39d8824053b4ab26c5cd0cfb604a57807ce61580175857fcf00b2cff3e55f +SHA512 (ruby-3.1.2.tar.xz) = 4a74e9efc6ea4b3eff4fec7534eb1fff4794d021531defc2e9937e53c6668db8ecdc0fff2bc23d5e6602d0df344a2caa85b31c5414309541e3d5313ec82b6e21 From c2061af620c2a52c936f73c7df97694106d72cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Thu, 14 Apr 2022 11:56:21 +0200 Subject: [PATCH 038/141] Use upstream patch for correct build of gem extensions. --- ...Properly-build-binary-gem-extensions.patch | 231 ------------ ...-extension-libraries-in-bundled-gems.patch | 338 ++++++++++++++++++ ruby.spec | 11 +- 3 files changed, 347 insertions(+), 233 deletions(-) delete mode 100644 ruby-3.1.1-Properly-build-binary-gem-extensions.patch create mode 100644 ruby-3.2.0-Build-extension-libraries-in-bundled-gems.patch diff --git a/ruby-3.1.1-Properly-build-binary-gem-extensions.patch b/ruby-3.1.1-Properly-build-binary-gem-extensions.patch deleted file mode 100644 index 17cb836..0000000 --- a/ruby-3.1.1-Properly-build-binary-gem-extensions.patch +++ /dev/null @@ -1,231 +0,0 @@ -From 0da0152986f7d1e666aeb1317d18746250423575 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Thu, 31 Mar 2022 19:12:24 +0200 -Subject: [PATCH 1/4] Properly install expanded gem extensions. - -The expanded gem location changed from 'gem' to '.bundled/gems' -directory in commit:git|55bf0ef1aa7c936b564b883196de1ace4be4cc7e / - #2922, leaving behind binary extension installation. This should fix -the issues, so the gem binary extensions are buildable as part of Ruby -build process again. ---- - ext/extmk.rb | 13 ++++++------- - template/exts.mk.tmpl | 4 ++-- - tool/rbinstall.rb | 4 ++-- - 3 files changed, 10 insertions(+), 11 deletions(-) - -diff --git a/ext/extmk.rb b/ext/extmk.rb -index 4a087f294ac9..bc0e4f135d8e 100755 ---- a/ext/extmk.rb -+++ b/ext/extmk.rb -@@ -146,7 +146,7 @@ def extmake(target, basedir = 'ext', maybestatic = true) - top_srcdir = $top_srcdir - topdir = $topdir - hdrdir = $hdrdir -- prefix = "../" * (target.count("/")+1) -+ prefix = "../" * (target.count("/") + basedir.count("/")) - $top_srcdir = relative_from(top_srcdir, prefix) - $hdrdir = relative_from(hdrdir, prefix) - $topdir = prefix + $topdir -@@ -461,15 +461,15 @@ def $mflags.defined?(var) - - @gemname = nil - if ARGV[0] -- ext_prefix, exts = ARGV.shift.split('/', 2) -+ ext_prefix, exts = File.split(ARGV.shift) - $extension = [exts] if exts -- if ext_prefix == 'gems' -+ if ext_prefix == '.bundle/gems' - @gemname = exts - elsif exts - $static_ext.delete_if {|t, *| !File.fnmatch(t, exts)} - end - end --ext_prefix = "#{$top_srcdir}/#{ext_prefix || 'ext'}" -+ext_prefix = "#{$top_srcdir}/#{ext_prefix || './ext'}" - exts = $static_ext.sort_by {|t, i| i}.collect {|t, i| t} - default_exclude_exts = - case -@@ -515,7 +515,6 @@ def $mflags.defined?(var) - exts.delete_if {|d| File.fnmatch?("-*", d)} - end - end --ext_prefix = File.basename(ext_prefix) - - extend Module.new { - def timestamp_file(name, target_prefix = nil) -@@ -534,7 +533,7 @@ def create_makefile(*args, &block) - super(*args) do |conf| - conf.find do |s| - s.sub!(/^(TARGET_SO_DIR *= *)\$\(RUBYARCHDIR\)/) { -- "TARGET_GEM_DIR = $(extout)/gems/$(arch)/#{@gemname}\n"\ -+ "TARGET_GEM_DIR = $(extout)/.bundle/gems/$(arch)/#{@gemname}\n"\ - "#{$1}$(TARGET_GEM_DIR)$(target_prefix)" - } - end -@@ -634,7 +633,7 @@ def initialize(src) - end - } - --Dir.chdir ".." -+Dir.chdir dir - unless $destdir.to_s.empty? - $mflags.defined?("DESTDIR") or $mflags << "DESTDIR=#{$destdir}" - end -diff --git a/template/exts.mk.tmpl b/template/exts.mk.tmpl -index 2f37f4480ac5..401ea9a497f3 100644 ---- a/template/exts.mk.tmpl -+++ b/template/exts.mk.tmpl -@@ -19,13 +19,13 @@ opt = OptionParser.new do |o| - o.on('--configure-exts=FILE') {|v| confexts = v} - o.order!(ARGV) - end --confexts &&= File.read(confexts).scan(/^exts: (.*\.mk)/).flatten rescue nil -+confexts &&= File.read(confexts).scan(/^(exts|gems): (.*\.mk)/).collect {|i| i.last } rescue nil - confexts ||= [] - macros["old_extensions"] = [] - - contpat = /(?>(?>[^\\\n]|\\.)*\\\n)*(?>[^\\\n]|\\.)*/ - Dir.glob("{ext,.bundle/gems}/*/exts.mk") do |e| -- gem = /\Agems(?=\/)/ =~ e -+ gem = /\A.bundle\/gems(?=\/)/ =~ e - s = File.read(e) - s.scan(/^(extensions|SUBMAKEOPTS|EXT[A-Z]+|MFLAGS|NOTE_[A-Z]+)[ \t]*=[ \t]*(#{contpat})$/o) do |n, v| - v.gsub!(/\\\n[ \t]*/, ' ') -diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb -index 9d9b672be472..8c8a14193ec9 100755 ---- a/tool/rbinstall.rb -+++ b/tool/rbinstall.rb -@@ -1047,7 +1047,7 @@ def install_default_gem(dir, srcdir, bindir) - :wrappers => true, - :format_executable => true, - } -- gem_ext_dir = "#$extout/gems/#{CONFIG['arch']}" -+ gem_ext_dir = "#$extout/.bundle/gems/#{CONFIG['arch']}" - extensions_dir = with_destdir(Gem::StubSpecification.gemspec_stub("", gem_dir, gem_dir).extensions_dir) - - File.foreach("#{srcdir}/gems/bundled_gems") do |name| -@@ -1080,7 +1080,7 @@ def install_default_gem(dir, srcdir, bindir) - File.chmod($data_mode, File.join(install_dir, "specifications", "#{spec.full_name}.gemspec")) - end - unless spec.extensions.empty? -- install_recursive(ext, spec.extension_dir) -+ install_recursive(ext, without_destdir(spec.extension_dir)) - end - installed_gems[spec.full_name] = true - end - -From 8c57deb09dbd9005ebc872c3c9147d6c2924e208 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Thu, 31 Mar 2022 19:22:15 +0200 -Subject: [PATCH 2/4] Re-enable building gem extensions. - -This reverts commit bac6e8ca5d8f6bc45984d12ddad55d3d876d4324. ---- - template/configure-ext.mk.tmpl | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/template/configure-ext.mk.tmpl b/template/configure-ext.mk.tmpl -index 6636a7759c54..8ba6b963e3ec 100644 ---- a/template/configure-ext.mk.tmpl -+++ b/template/configure-ext.mk.tmpl -@@ -27,7 +27,7 @@ SCRIPT_ARGS = <%=script_args.gsub("#", "\\#")%> - EXTMK_ARGS = $(SCRIPT_ARGS) --gnumake=$(gnumake) --extflags="$(EXTLDFLAGS)" \ - --make-flags="MINIRUBY='$(MINIRUBY)'" - --all: exts # gems -+all: exts gems - exts: - gems: - - -From ee6a16eed10c3ab6e4cc8285ca137e83964e0f5c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Fri, 1 Apr 2022 16:26:04 +0200 -Subject: [PATCH 3/4] Trust that .gemspec correctly declare their extensions. - -Do not judge the extension availability by the available extension -build. This is already assumed on other places anyway: - -https://github.com/ruby/ruby/blob/d1d48cb690fdad855da94b2a2d11721428bc06ba/tool/rbinstall.rb#L1062 ---- - tool/rbinstall.rb | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb -index 8c8a14193ec9..259792ad878c 100755 ---- a/tool/rbinstall.rb -+++ b/tool/rbinstall.rb -@@ -1069,9 +1069,6 @@ def install_default_gem(dir, srcdir, bindir) - next - end - spec.extension_dir = "#{extensions_dir}/#{spec.full_name}" -- if File.directory?(ext = "#{gem_ext_dir}/#{spec.full_name}") -- spec.extensions[0] ||= "-" -- end - package = RbInstall::DirPackage.new spec - ins = RbInstall::UnpackedInstaller.new(package, options) - puts "#{INDENT}#{spec.name} #{spec.version}" -@@ -1080,6 +1077,7 @@ def install_default_gem(dir, srcdir, bindir) - File.chmod($data_mode, File.join(install_dir, "specifications", "#{spec.full_name}.gemspec")) - end - unless spec.extensions.empty? -+ ext = "#{gem_ext_dir}/#{spec.full_name}" - install_recursive(ext, without_destdir(spec.extension_dir)) - end - installed_gems[spec.full_name] = true - -From d11bc592494529f8732a4a40defaf18f600c261d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Mon, 4 Apr 2022 11:18:51 +0200 -Subject: [PATCH 4/4] Install the previously build gem extensions. - -Install the pre-build gem binary extensions and attempt to build them -during `gem install` phase only when they are not available for whatever -reason. ---- - tool/rbinstall.rb | 17 ++++++++++++----- - 1 file changed, 12 insertions(+), 5 deletions(-) - -diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb -index 259792ad878c..4e42133bc1ce 100755 ---- a/tool/rbinstall.rb -+++ b/tool/rbinstall.rb -@@ -901,6 +901,18 @@ def write_default_spec - super unless $dryrun - $installed_list.puts(without_destdir(default_spec_file)) if $installed_list - end -+ -+ def build_extensions -+ return if spec.extensions.empty? -+ -+ ext = "#$extout/.bundle/gems/#{CONFIG['arch']}/#{spec.full_name}" -+ -+ # Call `install_recursive` with global binding, so it correctly use -+ # the global `install` -+ Object.__send__ :install_recursive, ext, without_destdir(spec.extension_dir) -+ -+ super unless File.exist? spec.gem_build_complete_path -+ end - end - - class GemInstaller -@@ -1047,7 +1059,6 @@ def install_default_gem(dir, srcdir, bindir) - :wrappers => true, - :format_executable => true, - } -- gem_ext_dir = "#$extout/.bundle/gems/#{CONFIG['arch']}" - extensions_dir = with_destdir(Gem::StubSpecification.gemspec_stub("", gem_dir, gem_dir).extensions_dir) - - File.foreach("#{srcdir}/gems/bundled_gems") do |name| -@@ -1076,10 +1087,6 @@ def install_default_gem(dir, srcdir, bindir) - unless $dryrun - File.chmod($data_mode, File.join(install_dir, "specifications", "#{spec.full_name}.gemspec")) - end -- unless spec.extensions.empty? -- ext = "#{gem_ext_dir}/#{spec.full_name}" -- install_recursive(ext, without_destdir(spec.extension_dir)) -- end - installed_gems[spec.full_name] = true - end - installed_gems, gems = Dir.glob(srcdir+'/gems/*.gem').partition {|gem| installed_gems.key?(File.basename(gem, '.gem'))} diff --git a/ruby-3.2.0-Build-extension-libraries-in-bundled-gems.patch b/ruby-3.2.0-Build-extension-libraries-in-bundled-gems.patch new file mode 100644 index 0000000..de8d4d3 --- /dev/null +++ b/ruby-3.2.0-Build-extension-libraries-in-bundled-gems.patch @@ -0,0 +1,338 @@ +From 111f8422427d78becc9183ae149b2105a16bf327 Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Tue, 5 Apr 2022 23:24:00 +0900 +Subject: [PATCH 1/5] Bundled gems are expanded under `.bundle/gems` now + +--- + ext/extmk.rb | 13 +++++++------ + template/exts.mk.tmpl | 2 +- + 2 files changed, 8 insertions(+), 7 deletions(-) + +diff --git a/ext/extmk.rb b/ext/extmk.rb +index 4a087f294ac9..1da9e2704521 100755 +--- a/ext/extmk.rb ++++ b/ext/extmk.rb +@@ -146,7 +146,7 @@ def extmake(target, basedir = 'ext', maybestatic = true) + top_srcdir = $top_srcdir + topdir = $topdir + hdrdir = $hdrdir +- prefix = "../" * (target.count("/")+1) ++ prefix = "../" * (basedir.count("/")+target.count("/")+1) + $top_srcdir = relative_from(top_srcdir, prefix) + $hdrdir = relative_from(hdrdir, prefix) + $topdir = prefix + $topdir +@@ -460,10 +460,11 @@ def $mflags.defined?(var) + end unless $extstatic + + @gemname = nil +-if ARGV[0] +- ext_prefix, exts = ARGV.shift.split('/', 2) ++if exts = ARGV.shift ++ ext_prefix = exts[%r[\A(?>\.bundle/)?[^/]+(?:/(?=(.+)?)|\z)]] ++ exts = $1 + $extension = [exts] if exts +- if ext_prefix == 'gems' ++ if ext_prefix.start_with?('.') + @gemname = exts + elsif exts + $static_ext.delete_if {|t, *| !File.fnmatch(t, exts)} +@@ -515,7 +516,7 @@ def $mflags.defined?(var) + exts.delete_if {|d| File.fnmatch?("-*", d)} + end + end +-ext_prefix = File.basename(ext_prefix) ++ext_prefix = ext_prefix[$top_srcdir.size+1..-2] + + extend Module.new { + def timestamp_file(name, target_prefix = nil) +@@ -634,7 +635,7 @@ def initialize(src) + end + } + +-Dir.chdir ".." ++Dir.chdir dir + unless $destdir.to_s.empty? + $mflags.defined?("DESTDIR") or $mflags << "DESTDIR=#{$destdir}" + end +diff --git a/template/exts.mk.tmpl b/template/exts.mk.tmpl +index 2f37f4480ac5..964939e365a1 100644 +--- a/template/exts.mk.tmpl ++++ b/template/exts.mk.tmpl +@@ -25,7 +25,7 @@ macros["old_extensions"] = [] + + contpat = /(?>(?>[^\\\n]|\\.)*\\\n)*(?>[^\\\n]|\\.)*/ + Dir.glob("{ext,.bundle/gems}/*/exts.mk") do |e| +- gem = /\Agems(?=\/)/ =~ e ++ gem = e.start_with?(".bundle/gems/") + s = File.read(e) + s.scan(/^(extensions|SUBMAKEOPTS|EXT[A-Z]+|MFLAGS|NOTE_[A-Z]+)[ \t]*=[ \t]*(#{contpat})$/o) do |n, v| + v.gsub!(/\\\n[ \t]*/, ' ') + +From 6ea34cac22131d28a9cc50e7875e854aed9bdb88 Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Wed, 6 Apr 2022 20:25:53 +0900 +Subject: [PATCH 2/5] Retrieve configured gems info + +--- + template/configure-ext.mk.tmpl | 2 +- + template/exts.mk.tmpl | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/template/configure-ext.mk.tmpl b/template/configure-ext.mk.tmpl +index 6636a7759c54..8ba6b963e3ec 100644 +--- a/template/configure-ext.mk.tmpl ++++ b/template/configure-ext.mk.tmpl +@@ -27,7 +27,7 @@ SCRIPT_ARGS = <%=script_args.gsub("#", "\\#")%> + EXTMK_ARGS = $(SCRIPT_ARGS) --gnumake=$(gnumake) --extflags="$(EXTLDFLAGS)" \ + --make-flags="MINIRUBY='$(MINIRUBY)'" + +-all: exts # gems ++all: exts gems + exts: + gems: + +diff --git a/template/exts.mk.tmpl b/template/exts.mk.tmpl +index 964939e365a1..e544c4c88bd7 100644 +--- a/template/exts.mk.tmpl ++++ b/template/exts.mk.tmpl +@@ -19,7 +19,7 @@ opt = OptionParser.new do |o| + o.on('--configure-exts=FILE') {|v| confexts = v} + o.order!(ARGV) + end +-confexts &&= File.read(confexts).scan(/^exts: (.*\.mk)/).flatten rescue nil ++confexts &&= File.read(confexts).scan(/^(?:ext|gem)s: (.*\.mk)/).flatten rescue nil + confexts ||= [] + macros["old_extensions"] = [] + +@@ -30,7 +30,7 @@ Dir.glob("{ext,.bundle/gems}/*/exts.mk") do |e| + s.scan(/^(extensions|SUBMAKEOPTS|EXT[A-Z]+|MFLAGS|NOTE_[A-Z]+)[ \t]*=[ \t]*(#{contpat})$/o) do |n, v| + v.gsub!(/\\\n[ \t]*/, ' ') + next if v.empty? +- next if gem and n != "extensions" ++ next if n != "extensions" + n = "old_extensions" if n == "extensions" and !confexts.include?(e) + v = v.split + m = macros[n] ||= [] + +From be9d00ee7c72766551ba8c3530f1538034498a6a Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Wed, 6 Apr 2022 20:28:00 +0900 +Subject: [PATCH 3/5] Move the target directory of bundled gems like as + rubygems + +--- + ext/extmk.rb | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/ext/extmk.rb b/ext/extmk.rb +index 1da9e2704521..a440af27fc5d 100755 +--- a/ext/extmk.rb ++++ b/ext/extmk.rb +@@ -2,6 +2,9 @@ + # -*- mode: ruby; coding: us-ascii -*- + # frozen_string_literal: false + ++module Gem; end # only needs Gem::Platform ++require 'rubygems/platform' ++ + # :stopdoc: + $extension = nil + $extstatic = nil +@@ -535,11 +538,12 @@ def create_makefile(*args, &block) + super(*args) do |conf| + conf.find do |s| + s.sub!(/^(TARGET_SO_DIR *= *)\$\(RUBYARCHDIR\)/) { +- "TARGET_GEM_DIR = $(extout)/gems/$(arch)/#{@gemname}\n"\ ++ "TARGET_GEM_DIR = $(topdir)/.bundle/extensions/$(gem_platform)/$(ruby_version)/#{@gemname}\n"\ + "#{$1}$(TARGET_GEM_DIR)$(target_prefix)" + } + end + conf.any? {|s| /^TARGET *= *\S/ =~ s} and conf << %{ ++gem_platform = #{Gem::Platform.local} + + # default target + all: + +From c4daf8e445925695c34bab8bf5135dcd1e8575a3 Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Wed, 6 Apr 2022 22:57:01 +0900 +Subject: [PATCH 4/5] Obey spec file locations to rubygems + +--- + common.mk | 3 ++- + defs/gmake.mk | 2 +- + tool/gem-unpack.rb | 5 +++-- + 3 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/common.mk b/common.mk +index 7c552cba1e04..b4adb2729c0e 100644 +--- a/common.mk ++++ b/common.mk +@@ -1359,10 +1359,11 @@ extract-gems$(gnumake:yes=-nongnumake): PHONY + $(Q) $(RUNRUBY) -C "$(srcdir)" \ + -Itool -rgem-unpack -answ \ + -e 'BEGIN {FileUtils.mkdir_p(d = ".bundle/gems")}' \ ++ -e 'BEGIN {FileUtils.mkdir_p(s = ".bundle/specifications")}' \ + -e 'gem, ver = *$$F' \ + -e 'next if !ver or /^#/=~gem' \ + -e 'g = "#{gem}-#{ver}"' \ +- -e 'File.directory?("#{d}/#{g}") or Gem.unpack("gems/#{g}.gem", d)' \ ++ -e 'File.directory?("#{d}/#{g}") or Gem.unpack("gems/#{g}.gem", d, s)' \ + gems/bundled_gems + + update-bundled_gems: PHONY +diff --git a/defs/gmake.mk b/defs/gmake.mk +index a625379a6804..27e3e21cc4d6 100644 +--- a/defs/gmake.mk ++++ b/defs/gmake.mk +@@ -290,7 +290,7 @@ extract-gems: | $(patsubst %,.bundle/gems/%,$(bundled-gems)) + $(ECHO) Extracting bundle gem $*... + $(Q) $(BASERUBY) -C "$(srcdir)" \ + -Itool -rgem-unpack \ +- -e 'Gem.unpack("gems/$(@F).gem", ".bundle/gems")' ++ -e 'Gem.unpack("gems/$(@F).gem", ".bundle/gems", ".bundle/specifications")' + + $(srcdir)/.bundle/gems: + $(MAKEDIRS) $@ +diff --git a/tool/gem-unpack.rb b/tool/gem-unpack.rb +index cb05719463f2..fe10b0e420fa 100644 +--- a/tool/gem-unpack.rb ++++ b/tool/gem-unpack.rb +@@ -5,13 +5,14 @@ + # This library is used by "make extract-gems" to + # unpack bundled gem files. + +-def Gem.unpack(file, dir = nil) ++def Gem.unpack(file, dir = nil, spec_dir = nil) + pkg = Gem::Package.new(file) + spec = pkg.spec + target = spec.full_name + target = File.join(dir, target) if dir + pkg.extract_files target +- spec_file = File.join(target, "#{spec.name}-#{spec.version}.gemspec") ++ FileUtils.mkdir_p(spec_dir ||= target) ++ spec_file = File.join(spec_dir, "#{spec.name}-#{spec.version}.gemspec") + open(spec_file, 'wb') do |f| + f.print spec.to_ruby + end + +From 3de652d8198be9cd2998c095903889a80e738275 Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Thu, 7 Apr 2022 01:44:43 +0900 +Subject: [PATCH 5/5] Install built gem extension binaries + +--- + tool/rbinstall.rb | 56 ++++++++++++++--------------------------------- + 1 file changed, 16 insertions(+), 40 deletions(-) + +diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb +index 9d9b672be472..624961b4eee6 100755 +--- a/tool/rbinstall.rb ++++ b/tool/rbinstall.rb +@@ -858,6 +858,9 @@ class UnpackedInstaller < GemInstaller + def write_cache_file + end + ++ def build_extensions ++ end ++ + def shebang(bin_file_name) + path = File.join(gem_dir, spec.bindir, bin_file_name) + first_line = File.open(path, "rb") {|file| file.gets} +@@ -940,13 +943,12 @@ def ensure_writable_dir(dir) + install_default_gem('ext', srcdir, bindir) + end + +-def load_gemspec(file, expanded = false) ++def load_gemspec(file, base = nil) + file = File.realpath(file) + code = File.read(file, encoding: "utf-8:-") + code.gsub!(/(?:`git[^\`]*`|%x\[git[^\]]*\])\.split\([^\)]*\)/m) do + files = [] +- if expanded +- base = File.dirname(file) ++ if base + Dir.glob("**/*", File::FNM_DOTMATCH, base: base) do |n| + case File.basename(n); when ".", ".."; next; end + next if File.directory?(File.join(base, n)) +@@ -959,7 +961,7 @@ def load_gemspec(file, expanded = false) + unless Gem::Specification === spec + raise TypeError, "[#{file}] isn't a Gem::Specification (#{spec.class} instead)." + end +- spec.loaded_from = file ++ spec.loaded_from = base ? File.join(base, File.basename(file)) : file + spec.files.reject! {|n| n.end_with?(".gemspec") or n.start_with?(".git")} + + spec +@@ -1014,20 +1016,6 @@ def install_default_gem(dir, srcdir, bindir) + end + + install?(:ext, :comm, :gem, :'bundled-gems') do +- if CONFIG['CROSS_COMPILING'] == 'yes' +- # The following hacky steps set "$ruby = BASERUBY" in tool/fake.rb +- $hdrdir = '' +- $extmk = nil +- $ruby = nil # ... +- ruby_path = $ruby + " -I#{Dir.pwd}" # $baseruby + " -I#{Dir.pwd}" +- else +- # ruby_path = File.expand_path(with_destdir(File.join(bindir, ruby_install_name))) +- ENV['RUBYLIB'] = nil +- ENV['RUBYOPT'] = nil +- ruby_path = File.expand_path(with_destdir(File.join(bindir, ruby_install_name))) + " --disable=gems -I#{with_destdir(archlibdir)}" +- end +- Gem.instance_variable_set(:@ruby, ruby_path) if Gem.ruby != ruby_path +- + gem_dir = Gem.default_dir + install_dir = with_destdir(gem_dir) + prepare "bundled gems", gem_dir +@@ -1047,40 +1035,28 @@ def install_default_gem(dir, srcdir, bindir) + :wrappers => true, + :format_executable => true, + } +- gem_ext_dir = "#$extout/gems/#{CONFIG['arch']}" +- extensions_dir = with_destdir(Gem::StubSpecification.gemspec_stub("", gem_dir, gem_dir).extensions_dir) ++ ++ extensions_dir = Gem::StubSpecification.gemspec_stub("", gem_dir, gem_dir).extensions_dir ++ specifications_dir = File.join(gem_dir, "specifications") ++ build_dir = Gem::StubSpecification.gemspec_stub("", ".bundle", ".bundle").extensions_dir + + File.foreach("#{srcdir}/gems/bundled_gems") do |name| + next if /^\s*(?:#|$)/ =~ name + next unless /^(\S+)\s+(\S+).*/ =~ name + gem_name = "#$1-#$2" +- path = "#{srcdir}/.bundle/gems/#{gem_name}/#{gem_name}.gemspec" +- if File.exist?(path) +- spec = load_gemspec(path) +- else +- path = "#{srcdir}/.bundle/gems/#{gem_name}/#$1.gemspec" +- next unless File.exist?(path) +- spec = load_gemspec(path, true) +- end ++ path = "#{srcdir}/.bundle/specifications/#{gem_name}.gemspec" ++ next unless File.exist?(path) ++ spec = load_gemspec(path, "#{srcdir}/.bundle/gems/#{gem_name}") + next unless spec.platform == Gem::Platform::RUBY + next unless spec.full_name == gem_name +- if !spec.extensions.empty? && CONFIG["EXTSTATIC"] == "static" +- puts "skip installation of #{spec.name} #{spec.version}; bundled gem with an extension library is not supported on --with-static-linked-ext" +- next +- end + spec.extension_dir = "#{extensions_dir}/#{spec.full_name}" +- if File.directory?(ext = "#{gem_ext_dir}/#{spec.full_name}") +- spec.extensions[0] ||= "-" +- end + package = RbInstall::DirPackage.new spec + ins = RbInstall::UnpackedInstaller.new(package, options) + puts "#{INDENT}#{spec.name} #{spec.version}" + ins.install +- unless $dryrun +- File.chmod($data_mode, File.join(install_dir, "specifications", "#{spec.full_name}.gemspec")) +- end +- unless spec.extensions.empty? +- install_recursive(ext, spec.extension_dir) ++ install_recursive("#{build_dir}/#{gem_name}", "#{extensions_dir}/#{gem_name}") do |src, dest| ++ # puts "#{INDENT} #{dest[extensions_dir.size+gem_name.size+2..-1]}" ++ install src, dest, :mode => (File.executable?(src) ? $prog_mode : $data_mode) + end + installed_gems[spec.full_name] = true + end diff --git a/ruby.spec b/ruby.spec index fa01783..f5d028d 100644 --- a/ruby.spec +++ b/ruby.spec @@ -169,8 +169,8 @@ Patch19: ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch Patch20: ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch # Workaround gem binary extensions build and installation issues. # https://bugs.ruby-lang.org/issues/18373 -# https://github.com/ruby/ruby/pull/5743 -Patch21: ruby-3.1.1-Properly-build-binary-gem-extensions.patch +# https://github.com/ruby/ruby/pull/5774 +Patch21: ruby-3.2.0-Build-extension-libraries-in-bundled-gems.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -636,6 +636,12 @@ rm -rf ext/fiddle/libffi* %patch7 -p1 %patch19 -p1 %patch20 -p1 + +# Once the upstream tarball contains the files on the right place, this code +# won't be necessary. This should happen at the same moment when the patch21 +# is not needed anymore. +mkdir .bundle/specifications +find .bundle/gems -name '*-[0-9]*.gemspec' -exec cp -t .bundle/specifications/ {} + %patch21 -p1 # Provide an example of usage of the tapset: @@ -1495,6 +1501,7 @@ mv test/fiddle/test_import.rb{,.disable} %changelog * Thu Apr 14 2022 Vít Ondruch - 3.1.2-164 - Upgrade to Ruby 3.1.2. +- Use upstream patch for correct build of gem extensions. * Mon Apr 04 2022 Vít Ondruch - 3.1.1-163 - Properly build binary gem extensions. From 03e8cec9fef6cb11dbfb52bfb4fd422c9018830b Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Thu, 21 Apr 2022 16:52:48 +0200 Subject: [PATCH 039/141] Drop `Q=` in make options. Because the `%make_build` macro includes the `V=1`. Note there is no actual difference of build.log between before and after this commit. ``` $ rpm --eval %make_build /usr/bin/make -O -j8 V=1 VERBOSE=1 ``` --- ruby.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby.spec b/ruby.spec index f5d028d..a194ec2 100644 --- a/ruby.spec +++ b/ruby.spec @@ -672,7 +672,7 @@ autoconf # Q= makes the build output more verbose and allows to check Fedora # compiler options. -%make_build COPY="cp -p" Q= +%make_build COPY="cp -p" %install rm -rf %{buildroot} From 2c91b113bbd0b56707181223e0a5db8eaf0f9578 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Wed, 4 May 2022 20:09:28 +0200 Subject: [PATCH 040/141] Update a comment about `make` verbose option, dropping `Q=` explanation. According to the , the `Q=` is not recommended. The `V=1` is recommended to output for the verbose mode. The `make V=1` suppresses some logs that `make` without `V=1` outputs rather than just adding verbose logs. While the `V=1 ECHO0=echo` is more equivalent with `Q=`, the `make V=1 ECHO0=echo` doesn't really output meaningful logs additionally. So, the `make V=1` is the best option for us to check the compiler flags. --- ruby.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby.spec b/ruby.spec index a194ec2..a92223c 100644 --- a/ruby.spec +++ b/ruby.spec @@ -670,8 +670,8 @@ autoconf --with-ruby-version='' \ --enable-multiarch \ -# Q= makes the build output more verbose and allows to check Fedora -# compiler options. +# V=1 in %%make_build outputs the compiler options more verbosely. +# https://bugs.ruby-lang.org/issues/18756 %make_build COPY="cp -p" %install From b7b547379654b3a337010d15914139e158e59acb Mon Sep 17 00:00:00 2001 From: Jarek Prokop Date: Thu, 26 May 2022 12:37:01 +0200 Subject: [PATCH 041/141] Define compaction methods as rb_f_notimplement on unsupported platforms. The patch implements the methods as rb_f_notimplement. To test for compaction users can now use `GC.respond_to?(:compact)`. The upstream patch relies on the macro `GC_COMPACTION_SUPPORTED` that is defined when the `__wasi__` is false. The define is defined by an arch conditional in the specfile, which is not optimal but works in our case. https://github.com/ruby/ruby/commit/663833b08fbae8d92cb2245a729312b86aa33a35 https://bugs.ruby-lang.org/issues/18829 This also requires regenerating the gc.rbinc and miniprelude.c since the patch touches gc.rb. This patch is available in ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch. To regenerate the gc.rbinc and miniprelude.c files patch: ~~~ tar -Jxvf ./ruby-3.1.2.tar.xz git clone https://github.com/ruby/ruby.git cd ruby && git checkout v3_1_2 patch -p1 < ../ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch ./autogen.sh && ./configure make gc.rbinc miniprelude.c cd .. diff -u {ruby-3.1.2,ruby}/gc.rbinc > ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch diff -u {ruby-3.1.2,ruby}/miniprelude.c >> ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch ~~~ Uptream bug: https://bugs.ruby-lang.org/issues/18779 Upstream PR: https://github.com/ruby/ruby/pull/5934 --- ...paction-methods-as-rb_f_notimplement.patch | 402 ++++++++++++++ ...c-compaction-methods_generated-files.patch | 502 ++++++++++++++++++ ruby.spec | 29 +- 3 files changed, 932 insertions(+), 1 deletion(-) create mode 100644 ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch create mode 100644 ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch diff --git a/ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch b/ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch new file mode 100644 index 0000000..1e34def --- /dev/null +++ b/ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch @@ -0,0 +1,402 @@ +commit 6d1ca6737f31b2e24664a093f1827dd74a121a9f +Author: Jarek Prokop +Date: Thu May 26 11:28:13 2022 +0200 + + Gc ppc64le fix + +diff --git a/gc.c b/gc.c +index ef9327df1f..1c35856c44 100644 +--- a/gc.c ++++ b/gc.c +@@ -9421,6 +9421,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t slot_size) + return (VALUE)src; + } + ++#if GC_COMPACTION_SUPPORTED + static int + compare_free_slots(const void *left, const void *right, void *dummy) + { +@@ -9468,6 +9469,7 @@ gc_sort_heap_by_empty_slots(rb_objspace_t *objspace) + free(page_list); + } + } ++#endif + + static void + gc_ref_update_array(rb_objspace_t * objspace, VALUE v) +@@ -10147,8 +10149,21 @@ gc_update_references(rb_objspace_t *objspace) + gc_update_table_refs(objspace, finalizer_table); + } + ++#if GC_COMPACTION_SUPPORTED ++/* ++ * call-seq: ++ * GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}} ++ * ++ * Returns information about object moved in the most recent GC compaction. ++ * ++ * The returned hash has two keys :considered and :moved. The hash for ++ * :considered lists the number of objects that were considered for movement ++ * by the compactor, and the :moved hash lists the number of objects that ++ * were actually moved. Some objects can't be moved (maybe they were pinned) ++ * so these numbers can be used to calculate compaction efficiency. ++ */ + static VALUE +-gc_compact_stats(rb_execution_context_t *ec, VALUE self) ++gc_compact_stats(VALUE self) + { + size_t i; + rb_objspace_t *objspace = &rb_objspace; +@@ -10171,7 +10186,11 @@ gc_compact_stats(rb_execution_context_t *ec, VALUE self) + + return h; + } ++#else ++# define gc_compact_stats rb_f_notimplement ++#endif + ++#if GC_COMPACTION_SUPPORTED + static void + root_obj_check_moved_i(const char *category, VALUE obj, void *data) + { +@@ -10221,22 +10240,78 @@ heap_check_moved_i(void *vstart, void *vend, size_t stride, void *data) + return 0; + } + ++/* ++ * call-seq: ++ * GC.compact ++ * ++ * This function compacts objects together in Ruby's heap. It eliminates ++ * unused space (or fragmentation) in the heap by moving objects in to that ++ * unused space. This function returns a hash which contains statistics about ++ * which objects were moved. See `GC.latest_gc_info` for details about ++ * compaction statistics. ++ * ++ * This method is implementation specific and not expected to be implemented ++ * in any implementation besides MRI. ++ * ++ * To test whether GC compaction is supported, use the idiom: ++ * ++ * GC.respond_to?(:compact) ++ */ + static VALUE +-gc_compact(rb_execution_context_t *ec, VALUE self) ++gc_compact(VALUE self) + { + /* Run GC with compaction enabled */ +- gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qtrue); ++ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qtrue); + +- return gc_compact_stats(ec, self); ++ return gc_compact_stats(self); + } ++#else ++# define gc_compact rb_f_notimplement ++#endif + ++#if GC_COMPACTION_SUPPORTED ++/* ++ * call-seq: ++ * GC.verify_compaction_references(toward: nil, double_heap: false) -> hash ++ * ++ * Verify compaction reference consistency. ++ * ++ * This method is implementation specific. During compaction, objects that ++ * were moved are replaced with T_MOVED objects. No object should have a ++ * reference to a T_MOVED object after compaction. ++ * ++ * This function doubles the heap to ensure room to move all objects, ++ * compacts the heap to make sure everything moves, updates all references, ++ * then performs a full GC. If any object contains a reference to a T_MOVED ++ * object, that object should be pushed on the mark stack, and will ++ * make a SEGV. ++ */ + static VALUE +-gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE double_heap, VALUE toward_empty) ++gc_verify_compaction_references(int argc, VALUE *argv, VALUE self) + { + rb_objspace_t *objspace = &rb_objspace; ++ VALUE kwargs, double_heap = Qfalse, toward_empty = Qfalse; ++ static ID id_toward, id_double_heap, id_empty; ++ ++ if (!id_toward) { ++ id_toward = rb_intern("toward"); ++ id_double_heap = rb_intern("double_heap"); ++ id_empty = rb_intern("empty"); ++ } ++ ++ rb_scan_args(argc, argv, ":", &kwargs); ++ if (!NIL_P(kwargs)) { ++ if (rb_hash_has_key(kwargs, ID2SYM(id_toward))) { ++ VALUE toward = rb_hash_aref(kwargs, ID2SYM(id_toward)); ++ toward_empty = (toward == ID2SYM(id_empty)) ? Qtrue : Qfalse; ++ } ++ if (rb_hash_has_key(kwargs, ID2SYM(id_double_heap))) { ++ double_heap = rb_hash_aref(kwargs, ID2SYM(id_double_heap)); ++ } ++ } + + /* Clear the heap. */ +- gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qfalse); ++ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qfalse); + + RB_VM_LOCK_ENTER(); + { +@@ -10256,13 +10331,16 @@ gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE do + } + RB_VM_LOCK_LEAVE(); + +- gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qtrue); ++ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qtrue); + + objspace_reachable_objects_from_root(objspace, root_obj_check_moved_i, NULL); + objspace_each_objects(objspace, heap_check_moved_i, NULL, TRUE); + +- return gc_compact_stats(ec, self); ++ return gc_compact_stats(self); + } ++#else ++# define gc_verify_compaction_references rb_f_notimplement ++#endif + + VALUE + rb_gc_start(void) +@@ -10722,26 +10800,45 @@ gc_disable(rb_execution_context_t *ec, VALUE _) + return rb_gc_disable(); + } + ++#if GC_COMPACTION_SUPPORTED ++/* ++ * call-seq: ++ * GC.auto_compact = flag ++ * ++ * Updates automatic compaction mode. ++ * ++ * When enabled, the compactor will execute on every major collection. ++ * ++ * Enabling compaction will degrade performance on major collections. ++ */ + static VALUE +-gc_set_auto_compact(rb_execution_context_t *ec, VALUE _, VALUE v) ++gc_set_auto_compact(VALUE _, VALUE v) + { + /* 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; + } ++#else ++# define gc_set_auto_compact rb_f_notimplement ++#endif + ++#if GC_COMPACTION_SUPPORTED ++/* ++ * call-seq: ++ * GC.auto_compact -> true or false ++ * ++ * Returns whether or not automatic compaction has been enabled. ++ */ + static VALUE +-gc_get_auto_compact(rb_execution_context_t *ec, VALUE _) ++gc_get_auto_compact(VALUE _) + { + return RBOOL(ruby_enable_autocompact); + } ++#else ++# define gc_get_auto_compact rb_f_notimplement ++#endif + + static int + get_envparam_size(const char *name, size_t *default_value, size_t lower_bound) +@@ -13599,6 +13696,11 @@ Init_GC(void) + rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0); + rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0); + #endif ++ rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0); ++ rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0); ++ rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1); ++ rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0); ++ rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1); + + #if GC_DEBUG_STRESS_TO_CLASS + rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1); +diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb +index 42ad028530..411d5eab69 100644 +--- a/test/ruby/test_gc_compact.rb ++++ b/test/ruby/test_gc_compact.rb +@@ -9,14 +9,7 @@ + end + + class TestGCCompact < Test::Unit::TestCase +- module SupportsCompact +- def setup +- skip "autocompact not supported on this platform" unless supports_auto_compact? +- super +- end +- +- private +- ++ module CompactionSupportInspector + def supports_auto_compact? + return true unless defined?(Etc::SC_PAGE_SIZE) + +@@ -30,10 +23,19 @@ def supports_auto_compact? + end + end + +- include SupportsCompact ++ module OmitUnlessCompactSupported ++ include CompactionSupportInspector ++ ++ def setup ++ omit "autocompact not supported on this platform" unless supports_auto_compact? ++ super ++ end ++ end ++ ++ include OmitUnlessCompactSupported + + class AutoCompact < Test::Unit::TestCase +- include SupportsCompact ++ include OmitUnlessCompactSupported + + def test_enable_autocompact + before = GC.auto_compact +@@ -87,13 +89,39 @@ def test_implicit_compaction_does_something + end + end + +- def os_page_size +- return true unless defined?(Etc::SC_PAGE_SIZE) ++ class CompactMethodsNotImplemented < Test::Unit::TestCase ++ include CompactionSupportInspector ++ ++ def assert_not_implemented(method, *args) ++ omit "autocompact is supported on this platform" if supports_auto_compact? ++ ++ assert_raise(NotImplementedError) { GC.send(method, *args) } ++ refute(GC.respond_to?(method), "GC.#{method} should be defined as rb_f_notimplement") ++ end ++ ++ def test_gc_compact_not_implemented ++ assert_not_implemented(:compact) ++ end ++ ++ def test_gc_auto_compact_get_not_implemented ++ assert_not_implemented(:auto_compact) ++ end ++ ++ def test_gc_auto_compact_set_not_implemented ++ assert_not_implemented(:auto_compact=, true) ++ end ++ ++ def test_gc_latest_compact_info_not_implemented ++ assert_not_implemented(:latest_compact_info) ++ end ++ ++ def test_gc_verify_compaction_references_not_implemented ++ assert_not_implemented(:verify_compaction_references) ++ end + end + +- def setup +- skip "autocompact not supported on this platform" unless supports_auto_compact? +- super ++ def os_page_size ++ return true unless defined?(Etc::SC_PAGE_SIZE) + end + + def test_gc_compact_stats +diff --git a/gc.rb b/gc.rb +index 72637f3796..9265dd7b57 100644 +--- a/gc.rb ++++ b/gc.rb +@@ -38,27 +38,6 @@ def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true + Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false + end + +- # call-seq: +- # GC.auto_compact -> true or false +- # +- # Returns whether or not automatic compaction has been enabled. +- # +- def self.auto_compact +- Primitive.gc_get_auto_compact +- end +- +- # call-seq: +- # GC.auto_compact = flag +- # +- # Updates automatic compaction mode. +- # +- # When enabled, the compactor will execute on every major collection. +- # +- # Enabling compaction will degrade performance on major collections. +- def self.auto_compact=(flag) +- Primitive.gc_set_auto_compact(flag) +- end +- + # call-seq: + # GC.enable -> true or false + # +@@ -210,53 +189,6 @@ def self.latest_gc_info hash_or_key = nil + Primitive.gc_latest_gc_info hash_or_key + end + +- # call-seq: +- # GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}} +- # +- # Returns information about object moved in the most recent GC compaction. +- # +- # The returned hash has two keys :considered and :moved. The hash for +- # :considered lists the number of objects that were considered for movement +- # by the compactor, and the :moved hash lists the number of objects that +- # were actually moved. Some objects can't be moved (maybe they were pinned) +- # so these numbers can be used to calculate compaction efficiency. +- def self.latest_compact_info +- Primitive.gc_compact_stats +- end +- +- # call-seq: +- # GC.compact +- # +- # This function compacts objects together in Ruby's heap. It eliminates +- # unused space (or fragmentation) in the heap by moving objects in to that +- # unused space. This function returns a hash which contains statistics about +- # which objects were moved. See `GC.latest_gc_info` for details about +- # compaction statistics. +- # +- # This method is implementation specific and not expected to be implemented +- # in any implementation besides MRI. +- def self.compact +- Primitive.gc_compact +- end +- +- # call-seq: +- # GC.verify_compaction_references(toward: nil, double_heap: false) -> hash +- # +- # Verify compaction reference consistency. +- # +- # This method is implementation specific. During compaction, objects that +- # were moved are replaced with T_MOVED objects. No object should have a +- # reference to a T_MOVED object after compaction. +- # +- # This function doubles the heap to ensure room to move all objects, +- # compacts the heap to make sure everything moves, updates all references, +- # then performs a full GC. If any object contains a reference to a T_MOVED +- # object, that object should be pushed on the mark stack, and will +- # make a SEGV. +- def self.verify_compaction_references(toward: nil, double_heap: false) +- Primitive.gc_verify_compaction_references(double_heap, toward == :empty) +- end +- + # call-seq: + # GC.using_rvargc? -> true or false + # diff --git a/ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch b/ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch new file mode 100644 index 0000000..240cc9c --- /dev/null +++ b/ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch @@ -0,0 +1,502 @@ +--- ruby-3.1.2/gc.rbinc 2022-04-12 13:11:17.000000000 +0200 ++++ ruby/gc.rbinc 2022-06-08 12:49:16.288024971 +0200 +@@ -9,27 +9,27 @@ + #include "builtin.h" /* for RB_BUILTIN_FUNCTION */ + struct rb_execution_context_struct; /* in vm_core.h */ + +-static VALUE builtin_inline_class_277(struct rb_execution_context_struct *ec, const VALUE self) ++static VALUE builtin_inline_class_209(struct rb_execution_context_struct *ec, const VALUE self) + { + MAYBE_UNUSED(const VALUE) flag = rb_vm_lvar(ec, -3); +-#line 277 "gc.rb" ++#line 209 "gc.rb" + + rb_objspace.flags.measure_gc = RTEST(flag) ? TRUE : FALSE; + return flag; + #line 20 "gc.rbinc" + } + +-static VALUE builtin_inline_class_289(struct rb_execution_context_struct *ec, const VALUE self) ++static VALUE builtin_inline_class_221(struct rb_execution_context_struct *ec, const VALUE self) + { +-#line 289 "gc.rb" ++#line 221 "gc.rb" + return + RBOOL(rb_objspace.flags.measure_gc); + #line 28 "gc.rbinc" + } + +-static VALUE builtin_inline_class_299(struct rb_execution_context_struct *ec, const VALUE self) ++static VALUE builtin_inline_class_231(struct rb_execution_context_struct *ec, const VALUE self) + { +-#line 299 "gc.rb" ++#line 231 "gc.rb" + return + ULL2NUM(rb_objspace.profile.total_time_ns); + #line 36 "gc.rbinc" +@@ -52,31 +52,6 @@ + } + + static void +-mjit_compile_invokebuiltin_for_gc_get_auto_compact(FILE *f, long index, unsigned stack_size, bool inlinable_p) +-{ +- fprintf(f, " VALUE self = GET_SELF();\n"); +- fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE);\n"); +- fprintf(f, " func f = (func)%"PRIuVALUE"; /* == gc_get_auto_compact */\n", (VALUE)gc_get_auto_compact); +- fprintf(f, " val = f(ec, self);\n"); +-} +- +-static void +-mjit_compile_invokebuiltin_for_gc_set_auto_compact(FILE *f, long index, unsigned stack_size, bool inlinable_p) +-{ +- fprintf(f, " VALUE self = GET_SELF();\n"); +- fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE, VALUE);\n"); +- if (index == -1) { +- fprintf(f, " const VALUE *argv = &stack[%d];\n", stack_size - 1); +- } +- else { +- fprintf(f, " const unsigned int lnum = GET_ISEQ()->body->local_table_size;\n"); +- fprintf(f, " const VALUE *argv = GET_EP() - lnum - VM_ENV_DATA_SIZE + 1 + %ld;\n", index); +- } +- fprintf(f, " func f = (func)%"PRIuVALUE"; /* == gc_set_auto_compact */\n", (VALUE)gc_set_auto_compact); +- fprintf(f, " val = f(ec, self, argv[0]);\n"); +-} +- +-static void + mjit_compile_invokebuiltin_for_gc_enable(FILE *f, long index, unsigned stack_size, bool inlinable_p) + { + fprintf(f, " VALUE self = GET_SELF();\n"); +@@ -161,40 +136,6 @@ + } + + static void +-mjit_compile_invokebuiltin_for_gc_compact_stats(FILE *f, long index, unsigned stack_size, bool inlinable_p) +-{ +- fprintf(f, " VALUE self = GET_SELF();\n"); +- fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE);\n"); +- fprintf(f, " func f = (func)%"PRIuVALUE"; /* == gc_compact_stats */\n", (VALUE)gc_compact_stats); +- fprintf(f, " val = f(ec, self);\n"); +-} +- +-static void +-mjit_compile_invokebuiltin_for_gc_compact(FILE *f, long index, unsigned stack_size, bool inlinable_p) +-{ +- fprintf(f, " VALUE self = GET_SELF();\n"); +- fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE);\n"); +- fprintf(f, " func f = (func)%"PRIuVALUE"; /* == gc_compact */\n", (VALUE)gc_compact); +- fprintf(f, " val = f(ec, self);\n"); +-} +- +-static void +-mjit_compile_invokebuiltin_for_gc_verify_compaction_references(FILE *f, long index, unsigned stack_size, bool inlinable_p) +-{ +- fprintf(f, " VALUE self = GET_SELF();\n"); +- fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE, VALUE, VALUE);\n"); +- if (index == -1) { +- fprintf(f, " const VALUE *argv = &stack[%d];\n", stack_size - 2); +- } +- else { +- fprintf(f, " const unsigned int lnum = GET_ISEQ()->body->local_table_size;\n"); +- fprintf(f, " const VALUE *argv = GET_EP() - lnum - VM_ENV_DATA_SIZE + 1 + %ld;\n", index); +- } +- fprintf(f, " func f = (func)%"PRIuVALUE"; /* == gc_verify_compaction_references */\n", (VALUE)gc_verify_compaction_references); +- fprintf(f, " val = f(ec, self, argv[0], argv[1]);\n"); +-} +- +-static void + mjit_compile_invokebuiltin_for__bi0(FILE *f, long index, unsigned stack_size, bool inlinable_p) + { + fprintf(f, " VALUE self = GET_SELF();\n"); +@@ -202,7 +143,7 @@ + if (inlinable_p) { + fprintf(f, "%s", " {\n"); + fprintf(f, "%s", " MAYBE_UNUSED(const VALUE) flag = rb_vm_lvar(ec, -3);\n"); +- fprintf(f, "%s", "#line 277 \"gc.rb\"\n"); ++ fprintf(f, "%s", "#line 209 \"gc.rb\"\n"); + fprintf(f, "%s", " \n"); + fprintf(f, "%s", " rb_objspace.flags.measure_gc = RTEST(flag) ? TRUE : FALSE;\n"); + fprintf(f, "%s", " return flag;\n"); +@@ -211,7 +152,7 @@ + fprintf(f, "%s", " \n"); + return; + } +- fprintf(f, " func f = (func)%"PRIuVALUE"; /* == builtin_inline_class_277 */\n", (VALUE)builtin_inline_class_277); ++ fprintf(f, " func f = (func)%"PRIuVALUE"; /* == builtin_inline_class_209 */\n", (VALUE)builtin_inline_class_209); + fprintf(f, " val = f(ec, self);\n"); + } + +@@ -222,7 +163,7 @@ + fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE);\n"); + if (inlinable_p) { + fprintf(f, "%s", " {\n"); +- fprintf(f, "%s", "#line 289 \"gc.rb\"\n"); ++ fprintf(f, "%s", "#line 221 \"gc.rb\"\n"); + fprintf(f, "%s", " return \n"); + fprintf(f, "%s", " RBOOL(rb_objspace.flags.measure_gc);\n"); + fprintf(f, "%s", "#line 52 \"gc.rbinc\"\n"); +@@ -230,7 +171,7 @@ + fprintf(f, "%s", " \n"); + return; + } +- fprintf(f, " func f = (func)%"PRIuVALUE"; /* == builtin_inline_class_289 */\n", (VALUE)builtin_inline_class_289); ++ fprintf(f, " func f = (func)%"PRIuVALUE"; /* == builtin_inline_class_221 */\n", (VALUE)builtin_inline_class_221); + fprintf(f, " val = f(ec, self);\n"); + } + +@@ -241,7 +182,7 @@ + fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE);\n"); + if (inlinable_p) { + fprintf(f, "%s", " {\n"); +- fprintf(f, "%s", "#line 299 \"gc.rb\"\n"); ++ fprintf(f, "%s", "#line 231 \"gc.rb\"\n"); + fprintf(f, "%s", " return \n"); + fprintf(f, "%s", " ULL2NUM(rb_objspace.profile.total_time_ns);\n"); + fprintf(f, "%s", "#line 59 \"gc.rbinc\"\n"); +@@ -249,7 +190,7 @@ + fprintf(f, "%s", " \n"); + return; + } +- fprintf(f, " func f = (func)%"PRIuVALUE"; /* == builtin_inline_class_299 */\n", (VALUE)builtin_inline_class_299); ++ fprintf(f, " func f = (func)%"PRIuVALUE"; /* == builtin_inline_class_231 */\n", (VALUE)builtin_inline_class_231); + fprintf(f, " val = f(ec, self);\n"); + } + +@@ -258,21 +199,16 @@ + // table definition + static const struct rb_builtin_function gc_table[] = { + RB_BUILTIN_FUNCTION(0, gc_start_internal, gc_start_internal, 4, mjit_compile_invokebuiltin_for_gc_start_internal), +- RB_BUILTIN_FUNCTION(1, gc_get_auto_compact, gc_get_auto_compact, 0, mjit_compile_invokebuiltin_for_gc_get_auto_compact), +- RB_BUILTIN_FUNCTION(2, gc_set_auto_compact, gc_set_auto_compact, 1, mjit_compile_invokebuiltin_for_gc_set_auto_compact), +- RB_BUILTIN_FUNCTION(3, gc_enable, gc_enable, 0, mjit_compile_invokebuiltin_for_gc_enable), +- RB_BUILTIN_FUNCTION(4, gc_disable, gc_disable, 0, mjit_compile_invokebuiltin_for_gc_disable), +- RB_BUILTIN_FUNCTION(5, gc_stress_get, gc_stress_get, 0, mjit_compile_invokebuiltin_for_gc_stress_get), +- RB_BUILTIN_FUNCTION(6, gc_stress_set_m, gc_stress_set_m, 1, mjit_compile_invokebuiltin_for_gc_stress_set_m), +- RB_BUILTIN_FUNCTION(7, gc_count, gc_count, 0, mjit_compile_invokebuiltin_for_gc_count), +- RB_BUILTIN_FUNCTION(8, gc_stat, gc_stat, 1, mjit_compile_invokebuiltin_for_gc_stat), +- RB_BUILTIN_FUNCTION(9, gc_latest_gc_info, gc_latest_gc_info, 1, mjit_compile_invokebuiltin_for_gc_latest_gc_info), +- RB_BUILTIN_FUNCTION(10, gc_compact_stats, gc_compact_stats, 0, mjit_compile_invokebuiltin_for_gc_compact_stats), +- RB_BUILTIN_FUNCTION(11, gc_compact, gc_compact, 0, mjit_compile_invokebuiltin_for_gc_compact), +- RB_BUILTIN_FUNCTION(12, gc_verify_compaction_references, gc_verify_compaction_references, 2, mjit_compile_invokebuiltin_for_gc_verify_compaction_references), +- RB_BUILTIN_FUNCTION(13, _bi0, builtin_inline_class_277, 0, mjit_compile_invokebuiltin_for__bi0), +- RB_BUILTIN_FUNCTION(14, _bi1, builtin_inline_class_289, 0, mjit_compile_invokebuiltin_for__bi1), +- RB_BUILTIN_FUNCTION(15, _bi2, builtin_inline_class_299, 0, mjit_compile_invokebuiltin_for__bi2), ++ RB_BUILTIN_FUNCTION(1, gc_enable, gc_enable, 0, mjit_compile_invokebuiltin_for_gc_enable), ++ RB_BUILTIN_FUNCTION(2, gc_disable, gc_disable, 0, mjit_compile_invokebuiltin_for_gc_disable), ++ RB_BUILTIN_FUNCTION(3, gc_stress_get, gc_stress_get, 0, mjit_compile_invokebuiltin_for_gc_stress_get), ++ RB_BUILTIN_FUNCTION(4, gc_stress_set_m, gc_stress_set_m, 1, mjit_compile_invokebuiltin_for_gc_stress_set_m), ++ RB_BUILTIN_FUNCTION(5, gc_count, gc_count, 0, mjit_compile_invokebuiltin_for_gc_count), ++ RB_BUILTIN_FUNCTION(6, gc_stat, gc_stat, 1, mjit_compile_invokebuiltin_for_gc_stat), ++ RB_BUILTIN_FUNCTION(7, gc_latest_gc_info, gc_latest_gc_info, 1, mjit_compile_invokebuiltin_for_gc_latest_gc_info), ++ RB_BUILTIN_FUNCTION(8, _bi0, builtin_inline_class_209, 0, mjit_compile_invokebuiltin_for__bi0), ++ RB_BUILTIN_FUNCTION(9, _bi1, builtin_inline_class_221, 0, mjit_compile_invokebuiltin_for__bi1), ++ RB_BUILTIN_FUNCTION(10, _bi2, builtin_inline_class_231, 0, mjit_compile_invokebuiltin_for__bi2), + RB_BUILTIN_FUNCTION(-1, NULL, NULL, 0, 0), + }; + +@@ -282,8 +218,6 @@ + COMPILER_WARNING_ERROR(-Wincompatible-pointer-types) + #endif + if (0) rb_builtin_function_check_arity4(gc_start_internal); +- if (0) rb_builtin_function_check_arity0(gc_get_auto_compact); +- if (0) rb_builtin_function_check_arity1(gc_set_auto_compact); + if (0) rb_builtin_function_check_arity0(gc_enable); + if (0) rb_builtin_function_check_arity0(gc_disable); + if (0) rb_builtin_function_check_arity0(gc_stress_get); +@@ -291,12 +225,9 @@ + if (0) rb_builtin_function_check_arity0(gc_count); + if (0) rb_builtin_function_check_arity1(gc_stat); + if (0) rb_builtin_function_check_arity1(gc_latest_gc_info); +- if (0) rb_builtin_function_check_arity0(gc_compact_stats); +- if (0) rb_builtin_function_check_arity0(gc_compact); +- if (0) rb_builtin_function_check_arity2(gc_verify_compaction_references); +- if (0) rb_builtin_function_check_arity0(builtin_inline_class_277); +- if (0) rb_builtin_function_check_arity0(builtin_inline_class_289); +- if (0) rb_builtin_function_check_arity0(builtin_inline_class_299); ++ if (0) rb_builtin_function_check_arity0(builtin_inline_class_209); ++ if (0) rb_builtin_function_check_arity0(builtin_inline_class_221); ++ if (0) rb_builtin_function_check_arity0(builtin_inline_class_231); + COMPILER_WARNING_POP + + // load +--- ruby-3.1.2/miniprelude.c 2022-04-12 13:11:17.000000000 +0200 ++++ ruby/miniprelude.c 2022-06-08 12:49:16.377024871 +0200 +@@ -545,11 +545,10 @@ + + static const char prelude_name2[] = ""; + static const struct { +- char L0[479]; /* 1..58 */ +- char L58[508]; /* 59..204 */ +- char L204[504]; /* 205..275 */ +- char L275[490]; /* 276..306 */ +- char L306[128]; /* 307..312 */ ++ char L0[492]; /* 1..70 */ ++ char L70[468]; /* 71..197 */ ++ char L197[470]; /* 198..237 */ ++ char L237[211]; /* 238..244 */ + } prelude_code2 = { + #line 1 "gc.rb" + ""/* for gc.c */ +@@ -593,29 +592,6 @@ + " end\n" + "\n" + "\n"/* call-seq: */ +-"\n"/* GC.auto_compact -> true or false */ +-"\n"/* */ +-"\n"/* Returns whether or not automatic compaction has been enabled. */ +-"\n"/* */ +-" def self.auto_compact\n" +-" Primitive.gc_get_auto_compact\n" +-" end\n" +-"\n" +-"\n"/* call-seq: */ +-"\n"/* GC.auto_compact = flag */ +-"\n"/* */ +-"\n"/* Updates automatic compaction mode. */ +-"\n"/* */ +-"\n"/* When enabled, the compactor will execute on every major collection. */ +-"\n"/* */ +-"\n"/* Enabling compaction will degrade performance on major collections. */ +-" def self.auto_compact=(flag)\n" +-, +-#line 59 "gc.rb" +-" Primitive.gc_set_auto_compact(flag)\n" +-" end\n" +-"\n" +-"\n"/* call-seq: */ + "\n"/* GC.enable -> true or false */ + "\n"/* */ + "\n"/* Enables garbage collection, returning +true+ if garbage */ +@@ -645,6 +621,8 @@ + "\n"/* GC.stress -> integer, true or false */ + "\n"/* */ + "\n"/* Returns current status of GC stress mode. */ ++, ++#line 71 "gc.rb" + " def self.stress\n" + " Primitive.gc_stress_get\n" + " end\n" +@@ -758,8 +736,6 @@ + "\n"/* GC.latest_gc_info(:major_by) -> :malloc */ + "\n"/* */ + "\n"/* Returns information about the most recent garbage collection. */ +-, +-#line 205 "gc.rb" + "\n"/* */ + "\n"/* If the optional argument, hash, is given, */ + "\n"/* it is overwritten and returned. */ +@@ -768,59 +744,14 @@ + " Primitive.gc_latest_gc_info hash_or_key\n" + " end\n" + "\n" +-"\n"/* call-seq: */ +-"\n"/* GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}} */ +-"\n"/* */ +-"\n"/* Returns information about object moved in the most recent GC compaction. */ +-"\n"/* */ +-"\n"/* The returned hash has two keys :considered and :moved. The hash for */ +-"\n"/* :considered lists the number of objects that were considered for movement */ +-"\n"/* by the compactor, and the :moved hash lists the number of objects that */ +-"\n"/* were actually moved. Some objects can't be moved (maybe they were pinned) */ +-"\n"/* so these numbers can be used to calculate compaction efficiency. */ +-" def self.latest_compact_info\n" +-" Primitive.gc_compact_stats\n" +-" end\n" +-"\n" +-"\n"/* call-seq: */ +-"\n"/* GC.compact */ +-"\n"/* */ +-"\n"/* This function compacts objects together in Ruby's heap. It eliminates */ +-"\n"/* unused space (or fragmentation) in the heap by moving objects in to that */ +-"\n"/* unused space. This function returns a hash which contains statistics about */ +-"\n"/* which objects were moved. See `GC.latest_gc_info` for details about */ +-"\n"/* compaction statistics. */ +-"\n"/* */ +-"\n"/* This method is implementation specific and not expected to be implemented */ +-"\n"/* in any implementation besides MRI. */ +-" def self.compact\n" +-" Primitive.gc_compact\n" +-" end\n" +-"\n" +-"\n"/* call-seq: */ +-"\n"/* GC.verify_compaction_references(toward: nil, double_heap: false) -> hash */ +-"\n"/* */ +-"\n"/* Verify compaction reference consistency. */ +-"\n"/* */ +-"\n"/* This method is implementation specific. During compaction, objects that */ +-"\n"/* were moved are replaced with T_MOVED objects. No object should have a */ +-"\n"/* reference to a T_MOVED object after compaction. */ +-"\n"/* */ +-"\n"/* This function doubles the heap to ensure room to move all objects, */ +-"\n"/* compacts the heap to make sure everything moves, updates all references, */ +-"\n"/* then performs a full GC. If any object contains a reference to a T_MOVED */ +-"\n"/* object, that object should be pushed on the mark stack, and will */ +-"\n"/* make a SEGV. */ +-" def self.verify_compaction_references(toward: nil, double_heap: false)\n" +-" Primitive.gc_verify_compaction_references(double_heap, toward == :empty)\n" +-" end\n" +-"\n" + "\n"/* call-seq: */ + "\n"/* GC.using_rvargc? -> true or false */ + "\n"/* */ + "\n"/* Returns true if using experimental feature Variable Width Allocation, false */ + "\n"/* otherwise. */ + " def self.using_rvargc?\n"/* :nodoc: */ ++, ++#line 198 "gc.rb" + " GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] > 1\n" + " end\n" + "\n" +@@ -831,8 +762,6 @@ + "\n"/* Enable to measure GC time. */ + "\n"/* You can get the result with GC.stat(:time). */ + "\n"/* Note that GC time measurement can cause some performance overhead. */ +-, +-#line 276 "gc.rb" + " def self.measure_total_time=(flag)\n" + " Primitive.cstmt! %{\n" + " rb_objspace.flags.measure_gc = RTEST(flag) ? TRUE : FALSE;\n" +@@ -863,15 +792,15 @@ + "end\n" + "\n" + "module ObjectSpace\n" +-" def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true\n" + , +-#line 307 "gc.rb" ++#line 238 "gc.rb" ++" def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true\n" + " Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false\n" + " end\n" + "\n" + " module_function :garbage_collect\n" + "end\n" +-#line 875 "miniprelude.c" ++#line 804 "miniprelude.c" + }; + + static const char prelude_name3[] = ""; +@@ -1223,7 +1152,7 @@ + " end\n" + "\n" + "end\n" +-#line 1227 "miniprelude.c" ++#line 1156 "miniprelude.c" + }; + + static const char prelude_name4[] = ""; +@@ -1354,7 +1283,7 @@ + " Primitive.io_write_nonblock(buf, exception)\n" + " end\n" + "end\n" +-#line 1358 "miniprelude.c" ++#line 1287 "miniprelude.c" + }; + + static const char prelude_name5[] = ""; +@@ -1402,7 +1331,7 @@ + " alias restore load\n" + " end\n" + "end\n" +-#line 1406 "miniprelude.c" ++#line 1335 "miniprelude.c" + }; + + static const char prelude_name6[] = ""; +@@ -1724,7 +1653,7 @@ + " Primitive.pack_unpack1(fmt, offset)\n" + " end\n" + "end\n" +-#line 1728 "miniprelude.c" ++#line 1657 "miniprelude.c" + }; + + static const char prelude_name7[] = ""; +@@ -2111,7 +2040,7 @@ + " Primitive.tracepoint_attr_instruction_sequence\n" + " end\n" + "end\n" +-#line 2115 "miniprelude.c" ++#line 2044 "miniprelude.c" + }; + + static const char prelude_name8[] = ""; +@@ -2172,7 +2101,7 @@ + " Primitive.rb_warn_m(msgs, uplevel, category)\n" + " end\n" + "end\n" +-#line 2176 "miniprelude.c" ++#line 2105 "miniprelude.c" + }; + + static const char prelude_name9[] = ""; +@@ -2249,7 +2178,7 @@ + " end\n" + " end\n" + "end\n" +-#line 2253 "miniprelude.c" ++#line 2182 "miniprelude.c" + }; + + static const char prelude_name10[] = ""; +@@ -2438,7 +2367,7 @@ + " end\n" + " end\n" + "end\n" +-#line 2442 "miniprelude.c" ++#line 2371 "miniprelude.c" + }; + + static const char prelude_name11[] = ""; +@@ -3305,7 +3234,7 @@ + " }\n" + " end\n" + "end\n" +-#line 3309 "miniprelude.c" ++#line 3238 "miniprelude.c" + }; + + static const char prelude_name12[] = ""; +@@ -3628,7 +3557,7 @@ + " Primitive.time_init_args(year, mon, mday, hour, min, sec, zone)\n" + " end\n" + "end\n" +-#line 3632 "miniprelude.c" ++#line 3561 "miniprelude.c" + }; + + static const char prelude_name13[] = ""; +@@ -3661,7 +3590,7 @@ + " return 0.0\n" + " end\n" + "end\n" +-#line 3665 "miniprelude.c" ++#line 3594 "miniprelude.c" + }; + + static const char prelude_name14[] = ""; +@@ -3691,7 +3620,7 @@ + "\n" + " private :pp\n" + "end\n" +-#line 3695 "miniprelude.c" ++#line 3624 "miniprelude.c" + }; + + static const char prelude_name15[] = ""; +@@ -3718,7 +3647,7 @@ + "rescue LoadError\n" + " warn \"`did_you_mean' was not loaded.\"\n" + "end if defined?(DidYouMean)\n" +-#line 3722 "miniprelude.c" ++#line 3651 "miniprelude.c" + }; + + static const char prelude_name16[] = ""; +@@ -4059,7 +3988,7 @@ + " end\n" + " end\n" + "end\n" +-#line 4063 "miniprelude.c" ++#line 3992 "miniprelude.c" + }; + + COMPILER_WARNING_POP diff --git a/ruby.spec b/ruby.spec index a92223c..eb3ac14 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 164 +%global release 165 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -171,6 +171,22 @@ Patch20: ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch # https://bugs.ruby-lang.org/issues/18373 # https://github.com/ruby/ruby/pull/5774 Patch21: ruby-3.2.0-Build-extension-libraries-in-bundled-gems.patch +# If GC compaction is not supported on platform, define the +# corresponding GC methods as not implemented. +# https://bugs.ruby-lang.org/issues/18779 +# https://github.com/ruby/ruby/pull/5934 +Patch22: ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch +# To regenerate the patch you need to have ruby, autoconf, xz, tar and make installed: +# tar -Jxvf ./ruby-3.1.2.tar.xz +# git clone https://github.com/ruby/ruby.git +# cd ruby && git checkout v3_1_2 +# patch -p1 < ../ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch +# ./autogen.sh && ./configure +# make gc.rbinc miniprelude.c +# cd .. +# diff -u {ruby-3.1.2,ruby}/gc.rbinc > ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch +# diff -u {ruby-3.1.2,ruby}/miniprelude.c >> ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch +Patch23: ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -643,6 +659,8 @@ rm -rf ext/fiddle/libffi* mkdir .bundle/specifications find .bundle/gems -name '*-[0-9]*.gemspec' -exec cp -t .bundle/specifications/ {} + %patch21 -p1 +%patch22 -p1 +%patch23 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -650,6 +668,12 @@ cp -a %{SOURCE3} . %build autoconf +# Some platforms do not support compaction and upstream does not seem to provide the +# right mechanism for the enablement of the preprocessor macros. +# https://bugs.ruby-lang.org/issues/18829 +%ifnarch ppc64le +CFLAGS="%{build_cflags} -DGC_COMPACTION_SUPPORTED" +%endif %configure \ --with-rubylibprefix='%{ruby_libdir}' \ --with-archlibdir='%{_libdir}' \ @@ -1499,6 +1523,9 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Tue Jun 07 2022 Jarek Prokop - 3.1.2-165 +- Define GC compaction methods as rb_f_notimplement on unsupported platforms. + * Thu Apr 14 2022 Vít Ondruch - 3.1.2-164 - Upgrade to Ruby 3.1.2. - Use upstream patch for correct build of gem extensions. From ca94aff023c5779dec1e03094784bdf736beca83 Mon Sep 17 00:00:00 2001 From: Jarek Prokop Date: Thu, 16 Jun 2022 13:00:59 +0200 Subject: [PATCH 042/141] Define the GC compaction support during run time. Previous commit changed GC compaction methods to not be implemented when not supported. However, that commit only does compile time checks, but there are additional compaction support checks during run time. This commit changes it so that GC compaction methods aren't defined also during run time if the platform does not support GC compaction. The patch is manually backported from following change set: https://github.com/ruby/ruby/pull/6019 https://github.com/ruby/ruby/commit/2c190863239bee3f54cfb74b16bb6ea4cae6ed20 To apply the patch included with this commit, first apply `ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch` and then apply the `ruby-3.2.0-detect_compaction_support_during_runtime.patch`. Related upstream issue: https://bugs.ruby-lang.org/issues/18829 --- ...ct-compaction-support-during-runtime.patch | 293 ++++++++++++++++++ ruby.spec | 17 +- 2 files changed, 303 insertions(+), 7 deletions(-) create mode 100644 ruby-3.2.0-Detect-compaction-support-during-runtime.patch diff --git a/ruby-3.2.0-Detect-compaction-support-during-runtime.patch b/ruby-3.2.0-Detect-compaction-support-during-runtime.patch new file mode 100644 index 0000000..fd8162f --- /dev/null +++ b/ruby-3.2.0-Detect-compaction-support-during-runtime.patch @@ -0,0 +1,293 @@ +From 4d9cc9afa47981520d991d19fd78b322f1ba9f2a Mon Sep 17 00:00:00 2001 +From: Jarek Prokop +Date: Wed, 22 Jun 2022 01:03:49 +0200 +Subject: [PATCH] Detect compaction support during runtime. + +The patch is created by backporting 3 commits from +the upstream Ruby master branch in the chronological order below. + +https://github.com/ruby/ruby/commit/52d42e702375446746164a0251e1a10bce813b78 +https://github.com/ruby/ruby/commit/79eaaf2d0b641710613f16525e4b4c439dfe854e +https://github.com/ruby/ruby/commit/2c190863239bee3f54cfb74b16bb6ea4cae6ed20 + +== How to create this patch == + +Download Ruby source code. +``` +$ git clone https://github.com/ruby/ruby.git +$ cd ruby +``` + +First create a commit squashed from the 3 commits above. +Checkout the second commmit above, and create a temporary branch. +``` +$ git checkout 79eaaf2d0b641710613f16525e4b4c439dfe854e +$ git checkout -b wip/detect-compaction-runtime-tmp +``` + +Cherry pick the third commit on the second commit. +``` +$ git cherry-pick 2c190863239bee3f54cfb74b16bb6ea4cae6ed20 +``` + +Squash the last 3 commits on the branch. +``` +$ git rebase -i 2223eb082afa6d05321b69df783d4133b9aacba6 +``` + +Then checkout Ruby 3.1.2 branch. +Create a new branch. +Merge the Fedora Ruby's +ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch. +``` +$ git checkout v3_1_2 +$ git checkout -b wip/detect-compaction-runtime +$ patch -p1 < +~/fed/ruby/ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch +$ git add gc.c gc.rb test/ruby/test_gc_compact.rb +$ git commit +``` + +Merge the squashed one commit on the +`wip/detect-compaction-runtime-tmp` branch +into the `wip/detect-compaction-runtime` branch. +``` +$ git cherry-pick +``` + +Fix conflicts seeing the difference by `git show ` +on another terminal. +``` +$ vi gc.c +$ git add gc.c +$ git commit +``` + +== Notes for the patch == + +``` ++# define GC_COMPACTION_SUPPORTED (GC_CAN_COMPILE_COMPACTION && USE_MMAP_ALIGNED_ALLOC) +``` + +We use the USE_MMAP_ALIGNED_ALLOC instead of HEAP_PAGE_ALLOC_USE_MMAP on +the line above. Because while the Ruby on the master branch replaced the +USE_MMAP_ALIGNED_ALLOC with HEAP_PAGE_ALLOC_USE_MMAP, Ruby 3.1.2 doesn't. +See . + + +``` ++ rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1); +``` + +We added the line in the case that GC_COMPACTION_SUPPORTED is true. +Because while the Ruby on the master branch defines the +GC.verify_compaction_references in the gc.rb in +the case that GC_COMPACTION_SUPPORTED is true, Ruby 3.1.2 +doesn't define it in the gc.rb. +See . + + +``` ++ OPT(GC_COMPACTION_SUPPORTED); +``` + +We added the line to expose the C macro to Ruby level. +In Ruby the macro existance can then be checked like so: +```Ruby +GC::OPTS.include?("GC_COMPACTION_SUPPORTED") +``` +It will return `true` if the GC_COMPACTION_SUPPORTED evaluates to `true` on the +C level, `false` otherwise. +See + +== Original commit messages == + +This is a combination of 3 commits. +This is the 1st commit message: +~~~ +Rename GC_COMPACTION_SUPPORTED + +Naming this macro GC_COMPACTION_SUPPORTED is misleading because it +only checks whether compaction is supported at compile time. + +[Bug #18829] +~~~ + +This is the commit message #2: +~~~ +Include runtime checks for compaction support + +Commit 0c36ba53192c5a0d245c9b626e4346a32d7d144e changed GC compaction +methods to not be implemented when not supported. However, that commit +only does compile time checks (which currently only checks for WASM), +but there are additional compaction support checks during run time. + +This commit changes it so that GC compaction methods aren't defined +during run time if the platform does not support GC compaction. + +[Bug #18829] +~~~ + +This is the commit message #3: +~~~ +Suppress code unused unless GC_CAN_COMPILE_COMPACTION +~~~ +--- + gc.c | 63 +++++++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 43 insertions(+), 20 deletions(-) + +diff --git a/gc.c b/gc.c +index 1c35856c44..bff0666a17 100644 +--- a/gc.c ++++ b/gc.c +@@ -4980,6 +4980,23 @@ gc_unprotect_pages(rb_objspace_t *objspace, rb_heap_t *heap) + static void gc_update_references(rb_objspace_t * objspace); + static void invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page); + ++#ifndef GC_CAN_COMPILE_COMPACTION ++#if defined(__wasi__) /* WebAssembly doesn't support signals */ ++# define GC_CAN_COMPILE_COMPACTION 0 ++#else ++# define GC_CAN_COMPILE_COMPACTION 1 ++#endif ++#endif ++ ++#if defined(__MINGW32__) || defined(_WIN32) ++# define GC_COMPACTION_SUPPORTED 1 ++#else ++/* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for ++ * the read barrier, so we must disable compaction. */ ++# define GC_COMPACTION_SUPPORTED (GC_CAN_COMPILE_COMPACTION && USE_MMAP_ALIGNED_ALLOC) ++#endif ++ ++#if GC_CAN_COMPILE_COMPACTION + static void + read_barrier_handler(uintptr_t address) + { +@@ -5000,6 +5017,7 @@ read_barrier_handler(uintptr_t address) + } + RB_VM_LOCK_LEAVE(); + } ++#endif + + #if defined(_WIN32) + static LPTOP_LEVEL_EXCEPTION_FILTER old_handler; +@@ -9250,13 +9268,7 @@ 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 ++ GC_ASSERT(GC_COMPACTION_SUPPORTED); + + reason |= GPR_FLAG_COMPACT; + } +@@ -9421,7 +9433,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t slot_size) + return (VALUE)src; + } + +-#if GC_COMPACTION_SUPPORTED ++#if GC_CAN_COMPILE_COMPACTION + static int + compare_free_slots(const void *left, const void *right, void *dummy) + { +@@ -10149,7 +10161,7 @@ gc_update_references(rb_objspace_t *objspace) + gc_update_table_refs(objspace, finalizer_table); + } + +-#if GC_COMPACTION_SUPPORTED ++#if GC_CAN_COMPILE_COMPACTION + /* + * call-seq: + * GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}} +@@ -10190,7 +10202,7 @@ gc_compact_stats(VALUE self) + # define gc_compact_stats rb_f_notimplement + #endif + +-#if GC_COMPACTION_SUPPORTED ++#if GC_CAN_COMPILE_COMPACTION + static void + root_obj_check_moved_i(const char *category, VALUE obj, void *data) + { +@@ -10269,7 +10281,7 @@ gc_compact(VALUE self) + # define gc_compact rb_f_notimplement + #endif + +-#if GC_COMPACTION_SUPPORTED ++#if GC_CAN_COMPILE_COMPACTION + /* + * call-seq: + * GC.verify_compaction_references(toward: nil, double_heap: false) -> hash +@@ -10800,7 +10812,7 @@ gc_disable(rb_execution_context_t *ec, VALUE _) + return rb_gc_disable(); + } + +-#if GC_COMPACTION_SUPPORTED ++#if GC_CAN_COMPILE_COMPACTION + /* + * call-seq: + * GC.auto_compact = flag +@@ -10814,8 +10826,7 @@ gc_disable(rb_execution_context_t *ec, VALUE _) + static VALUE + gc_set_auto_compact(VALUE _, VALUE v) + { +- /* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for +- * the read barrier, so we must disable automatic compaction. */ ++ GC_ASSERT(GC_COMPACTION_SUPPORTED); + + ruby_enable_autocompact = RTEST(v); + return v; +@@ -10824,7 +10835,8 @@ gc_set_auto_compact(VALUE _, VALUE v) + # define gc_set_auto_compact rb_f_notimplement + #endif + +-#if GC_COMPACTION_SUPPORTED ++ ++#if GC_CAN_COMPILE_COMPACTION + /* + * call-seq: + * GC.auto_compact -> true or false +@@ -13696,11 +13708,21 @@ Init_GC(void) + rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0); + rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0); + #endif +- rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0); +- rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0); +- rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1); +- rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0); +- rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1); ++ if (GC_COMPACTION_SUPPORTED) { ++ rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0); ++ rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0); ++ rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1); ++ rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0); ++ rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1); ++ } ++ else { ++ rb_define_singleton_method(rb_mGC, "compact", rb_f_notimplement, 0); ++ rb_define_singleton_method(rb_mGC, "auto_compact", rb_f_notimplement, 0); ++ rb_define_singleton_method(rb_mGC, "auto_compact=", rb_f_notimplement, 1); ++ rb_define_singleton_method(rb_mGC, "latest_compact_info", rb_f_notimplement, 0); ++ /* When !GC_COMPACTION_SUPPORTED, this method is not defined in gc.rb */ ++ rb_define_singleton_method(rb_mGC, "verify_compaction_references", rb_f_notimplement, -1); ++ } + + #if GC_DEBUG_STRESS_TO_CLASS + rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1); +@@ -13724,6 +13746,7 @@ Init_GC(void) + OPT(MALLOC_ALLOCATED_SIZE); + OPT(MALLOC_ALLOCATED_SIZE_CHECK); + OPT(GC_PROFILE_DETAIL_MEMORY); ++ OPT(GC_COMPACTION_SUPPORTED); + #undef OPT + OBJ_FREEZE(opts); + } +-- +2.36.1 + diff --git a/ruby.spec b/ruby.spec index eb3ac14..3cbd793 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 165 +%global release 166 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -187,6 +187,11 @@ Patch22: ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplemen # diff -u {ruby-3.1.2,ruby}/gc.rbinc > ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch # diff -u {ruby-3.1.2,ruby}/miniprelude.c >> ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch Patch23: ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch +# Define the GC compaction support macro at run time. +# https://bugs.ruby-lang.org/issues/18829 +# https://github.com/ruby/ruby/pull/6019 +# https://github.com/ruby/ruby/commit/2c190863239bee3f54cfb74b16bb6ea4cae6ed20 +Patch24: ruby-3.2.0-Detect-compaction-support-during-runtime.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -661,6 +666,7 @@ find .bundle/gems -name '*-[0-9]*.gemspec' -exec cp -t .bundle/specifications/ { %patch21 -p1 %patch22 -p1 %patch23 -p1 +%patch24 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -668,12 +674,6 @@ cp -a %{SOURCE3} . %build autoconf -# Some platforms do not support compaction and upstream does not seem to provide the -# right mechanism for the enablement of the preprocessor macros. -# https://bugs.ruby-lang.org/issues/18829 -%ifnarch ppc64le -CFLAGS="%{build_cflags} -DGC_COMPACTION_SUPPORTED" -%endif %configure \ --with-rubylibprefix='%{ruby_libdir}' \ --with-archlibdir='%{_libdir}' \ @@ -1523,6 +1523,9 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Thu Jun 16 2022 Jarek Prokop - 3.1.2-166 +- Detect compaction support during run time. + * Tue Jun 07 2022 Jarek Prokop - 3.1.2-165 - Define GC compaction methods as rb_f_notimplement on unsupported platforms. From e2951e6856e1e3480ff232948fa25dd6674c4b84 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 23 Jul 2022 01:10:40 +0000 Subject: [PATCH 043/141] Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- ruby.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ruby.spec b/ruby.spec index 3cbd793..0d4cb8c 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 166 +%global release 167 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -1523,6 +1523,9 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Sat Jul 23 2022 Fedora Release Engineering +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild + * Thu Jun 16 2022 Jarek Prokop - 3.1.2-166 - Detect compaction support during run time. From f93afdebdd045891fa0b723ea2330f5fcfd027b0 Mon Sep 17 00:00:00 2001 From: Jarek Prokop Date: Mon, 11 Jul 2022 13:02:25 +0200 Subject: [PATCH 044/141] Fix Ruby build failing due to unremovable tmp subdirectory. RPM 4.18.0-beta1 or later versions remove the build directory automatically, the build fails on removing temporary directories with the missing 'w' bit. RubyGems contain this patch since version 3.3.8. This was merged to ruby_3_1 branch in upstream ruby, but it is not included in the v3_1_2 tag, so new Ruby 3.1 release should contain this change. Relevant RPM upstream PR: https://github.com/rpm-software-management/rpm/pull/2080 Relevant bug: https://bugzilla.redhat.com/show_bug.cgi?id=2105393 --- ...aned-up-error-with-temporary-gemhome.patch | 22 +++++++++++++++++++ ruby.spec | 11 ++++++++++ 2 files changed, 33 insertions(+) create mode 100644 ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.patch diff --git a/ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.patch b/ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.patch new file mode 100644 index 0000000..66c3382 --- /dev/null +++ b/ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.patch @@ -0,0 +1,22 @@ +From 623162ad2bb3b589bddcc32616492a2bc4651726 Mon Sep 17 00:00:00 2001 +From: Hiroshi SHIBATA +Date: Tue, 22 Feb 2022 11:58:54 +0900 +Subject: [PATCH] Resolve cleaned-up error with temporary gemhome + +--- + test/rubygems/test_gem_commands_setup_command.rb | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/test/rubygems/test_gem_commands_setup_command.rb b/test/rubygems/test_gem_commands_setup_command.rb +index 5cf94a1dc99..934c76b1d1a 100644 +--- a/test/rubygems/test_gem_commands_setup_command.rb ++++ b/test/rubygems/test_gem_commands_setup_command.rb +@@ -274,6 +274,8 @@ def test_install_default_bundler_gem_with_destdir_flag + spec.executables.each do |e| + assert_path_exist File.join destdir, @gemhome.gsub(/^[a-zA-Z]:/, ''), 'gems', spec.full_name, spec.bindir, e + end ++ ensure ++ FileUtils.chmod "+w", @gemhome + end + + def test_install_default_bundler_gem_with_destdir_and_prefix_flags diff --git a/ruby.spec b/ruby.spec index 0d4cb8c..3176d99 100644 --- a/ruby.spec +++ b/ruby.spec @@ -192,6 +192,13 @@ Patch23: ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.pat # https://github.com/ruby/ruby/pull/6019 # https://github.com/ruby/ruby/commit/2c190863239bee3f54cfb74b16bb6ea4cae6ed20 Patch24: ruby-3.2.0-Detect-compaction-support-during-runtime.patch +# RPM 4.18.0-beta1 or later versions remove the build directory automatically +# on successful build, the build then fails on removing temporary directories +# that are missing the 'w' bit. +# https://bugzilla.redhat.com/show_bug.cgi?id=2105393 +# https://github.com/rpm-software-management/rpm/pull/2080 +# https://github.com/rubygems/rubygems/pull/5372 +Patch25: ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -667,6 +674,7 @@ find .bundle/gems -name '*-[0-9]*.gemspec' -exec cp -t .bundle/specifications/ { %patch22 -p1 %patch23 -p1 %patch24 -p1 +%patch25 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -1523,6 +1531,9 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Mon Jul 25 2022 Jarek Prokop - 3.1.2-167 +- Fix directory permissions in one of the rubygems tests. + * Sat Jul 23 2022 Fedora Release Engineering - Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild From ad7f78b5c865f3cbf8721d7eecf950a508a6bc5d Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Wed, 24 Aug 2022 13:44:41 +0200 Subject: [PATCH 045/141] Fix tests with Europe/Amsterdam pre-1970 time on tzdata version 2022b. Resolves: rhbz#2120354 --- ruby-spec-Fix-tests-on-tzdata-2022b.patch | 40 +++++++++++++++++++++++ ruby.spec | 10 +++++- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 ruby-spec-Fix-tests-on-tzdata-2022b.patch diff --git a/ruby-spec-Fix-tests-on-tzdata-2022b.patch b/ruby-spec-Fix-tests-on-tzdata-2022b.patch new file mode 100644 index 0000000..19386d9 --- /dev/null +++ b/ruby-spec-Fix-tests-on-tzdata-2022b.patch @@ -0,0 +1,40 @@ +From 7e9ec8a20b0f7469b415283d2ec0c22087f8eb2b Mon Sep 17 00:00:00 2001 +From: Jun Aruga +Date: Wed, 24 Aug 2022 12:02:56 +0200 +Subject: [PATCH] Fix tests with Europe/Amsterdam pre-1970 time on tzdata + version 2022b. + +The Time Zone Database (tzdata) changed the pre-1970 timestamps in some zones +including Europe/Amsterdam on tzdata version 2022b or later. +See . + +The tzdata RPM package maintainer on Fedora project suggested changing the Ruby +test, because the change is intentional. +See . + +We use post-1970 time test data to simplify the test. +--- + core/time/shared/local.rb | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/spec/ruby/core/time/shared/local.rb b/spec/ruby/core/time/shared/local.rb +index 43f331c4c..c4aa7a7ea 100644 +--- a/spec/ruby/core/time/shared/local.rb ++++ b/spec/ruby/core/time/shared/local.rb +@@ -8,10 +8,10 @@ describe :time_local, shared: true do + + platform_is_not :windows do + describe "timezone changes" do +- it "correctly adjusts the timezone change to 'CEST' on 'Europe/Amsterdam'" do ++ it "correctly adjusts the timezone change to 'CET' on 'Europe/Amsterdam'" do + with_timezone("Europe/Amsterdam") do +- Time.send(@method, 1940, 5, 16).to_a.should == +- [0, 40, 1, 16, 5, 1940, 4, 137, true, "CEST"] ++ Time.send(@method, 1970, 5, 16).to_a.should == ++ [0, 0, 0, 16, 5, 1970, 6, 136, false, "CET"] + end + end + end +-- +2.36.1 + diff --git a/ruby.spec b/ruby.spec index 3176d99..3de20eb 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 167 +%global release 168 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -199,6 +199,9 @@ Patch24: ruby-3.2.0-Detect-compaction-support-during-runtime.patch # https://github.com/rpm-software-management/rpm/pull/2080 # https://github.com/rubygems/rubygems/pull/5372 Patch25: ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.patch +# Fix tests with Europe/Amsterdam pre-1970 time on tzdata version 2022b. +# https://github.com/ruby/spec/pull/939 +Patch26: ruby-spec-Fix-tests-on-tzdata-2022b.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -675,6 +678,7 @@ find .bundle/gems -name '*-[0-9]*.gemspec' -exec cp -t .bundle/specifications/ { %patch23 -p1 %patch24 -p1 %patch25 -p1 +%patch26 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -1531,6 +1535,10 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Wed Aug 24 2022 Jun Aruga - 3.1.2-168 +- Fix tests with Europe/Amsterdam pre-1970 time on tzdata version 2022b. + Resolves: rhbz#2120354 + * Mon Jul 25 2022 Jarek Prokop - 3.1.2-167 - Fix directory permissions in one of the rubygems tests. From bf921512e288965724353ecf73ca9aa6d4975489 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Fri, 26 Aug 2022 14:36:43 +0200 Subject: [PATCH 046/141] Make RDoc soft dependnecy in IRB. Resolves: rhbz#2119964 --- ruby-irb-1.4.1-drop-rdoc-hard-dep.patch | 24 +++++++++++++++ ruby-irb-1.4.1-set-rdoc-soft-dep.patch | 41 +++++++++++++++++++++++++ ruby.spec | 13 ++++++++ 3 files changed, 78 insertions(+) create mode 100644 ruby-irb-1.4.1-drop-rdoc-hard-dep.patch create mode 100644 ruby-irb-1.4.1-set-rdoc-soft-dep.patch diff --git a/ruby-irb-1.4.1-drop-rdoc-hard-dep.patch b/ruby-irb-1.4.1-drop-rdoc-hard-dep.patch new file mode 100644 index 0000000..711c514 --- /dev/null +++ b/ruby-irb-1.4.1-drop-rdoc-hard-dep.patch @@ -0,0 +1,24 @@ +From 54c8df06ff9e161012f89d19a4e3aa2e0e37e1b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Tue, 23 Aug 2022 10:41:28 +0200 +Subject: [PATCH] Drop hard dependency on RDoc. + +This has been introduced in 026700499dfd640b2072d7bf0370247a98d5ac40, +but it seems that this is just be mistake, otherwise the later handling +of `LoadError` would not be needed. +--- + lib/irb/input-method.rb | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb +index fd68239e..a8227caa 100644 +--- a/lib/irb/input-method.rb ++++ b/lib/irb/input-method.rb +@@ -14,7 +14,6 @@ + require_relative 'completion' + require 'io/console' + require 'reline' +-require 'rdoc' + + module IRB + STDIN_FILE_NAME = "(line)" # :nodoc: diff --git a/ruby-irb-1.4.1-set-rdoc-soft-dep.patch b/ruby-irb-1.4.1-set-rdoc-soft-dep.patch new file mode 100644 index 0000000..0156fe0 --- /dev/null +++ b/ruby-irb-1.4.1-set-rdoc-soft-dep.patch @@ -0,0 +1,41 @@ +From b24852058fc87c940252c8a711c60ae2eb298082 Mon Sep 17 00:00:00 2001 +From: Jun Aruga +Date: Thu, 25 Aug 2022 20:11:34 +0200 +Subject: [PATCH] Require RDoc in `input-method.rb` again in a limited scope. + +RDoc is implemented as soft dependency in IRB. See how the rdoc is required in +the files. I reverted the commit below. + +``` +$ grep -ril rdoc lib/ +lib/irb/cmd/help.rb +lib/irb/completion.rb +lib/irb/easter-egg.rb +lib/irb/input-method.rb +``` + +--- + +Revert "Remove `require` in signal handler to avoid ThreadError" + +This reverts commit 5f749c613c895cf1b11b5e4cbd1205363bc58028. +--- + lib/irb/input-method.rb | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb +index a8227ca..b77fd32 100644 +--- a/lib/irb/input-method.rb ++++ b/lib/irb/input-method.rb +@@ -320,6 +320,11 @@ def auto_indent(&block) + [195, 164], # The "ä" that appears when Alt+d is pressed on xterm. + [226, 136, 130] # The "∂" that appears when Alt+d in pressed on iTerm2. + ] ++ begin ++ require 'rdoc' ++ rescue LoadError ++ return nil ++ end + + if just_cursor_moving and completion_journey_data.nil? + return nil diff --git a/ruby.spec b/ruby.spec index 3de20eb..e2429ac 100644 --- a/ruby.spec +++ b/ruby.spec @@ -202,6 +202,12 @@ Patch25: ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.pat # Fix tests with Europe/Amsterdam pre-1970 time on tzdata version 2022b. # https://github.com/ruby/spec/pull/939 Patch26: ruby-spec-Fix-tests-on-tzdata-2022b.patch +# Drop hard dependency on RDoc in IRB. +# https://github.com/ruby/irb/pull/393 +Patch27: ruby-irb-1.4.1-drop-rdoc-hard-dep.patch +# Set soft dependency on RDoc in input-method.rb in IRB. +# https://github.com/ruby/irb/pull/395 +Patch28: ruby-irb-1.4.1-set-rdoc-soft-dep.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -354,6 +360,7 @@ Requires: ruby(rubygems) >= %{rubygems_version} # ruby-default-gems is required to run irb. # https://bugs.ruby-lang.org/issues/16951 Requires: ruby-default-gems >= %{ruby_version} +Recommends: rubygem(rdoc) >= %{rdoc_version} Provides: irb = %{version}-%{release} Provides: rubygem(irb) = %{version}-%{release} # Obsoleted by Ruby 2.6 in F30 timeframe. @@ -679,6 +686,8 @@ find .bundle/gems -name '*-[0-9]*.gemspec' -exec cp -t .bundle/specifications/ { %patch24 -p1 %patch25 -p1 %patch26 -p1 +%patch27 -p1 +%patch28 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -1535,6 +1544,10 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Mon Aug 29 2022 Jun Aruga - 3.1.2-168 +- Make RDoc soft dependnecy in IRB. + Resolves: rhbz#2119964 + * Wed Aug 24 2022 Jun Aruga - 3.1.2-168 - Fix tests with Europe/Amsterdam pre-1970 time on tzdata version 2022b. Resolves: rhbz#2120354 From 3f106c188ea6368c950ba7d610594f910773a25f Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Fri, 26 Aug 2022 15:58:52 +0200 Subject: [PATCH 047/141] Add IRB to ruby-bundled-gems recommends. Resolves: rhbz#2120562 --- ruby.spec | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ruby.spec b/ruby.spec index e2429ac..22f7e84 100644 --- a/ruby.spec +++ b/ruby.spec @@ -500,6 +500,8 @@ many machines, systematically and repeatably. %package bundled-gems Summary: Bundled gems which are part of Ruby StdLib Requires: ruby(rubygems) >= %{rubygems_version} +# Runtime dependency of rubygem(debug). +Recommends: rubygem(irb) >= %{irb_version} Provides: rubygem(net-ftp) = %{net_ftp_version} Provides: rubygem(net-imap) = %{net_imap_version} Provides: rubygem(net-pop) = %{net_pop_version} @@ -1547,6 +1549,8 @@ mv test/fiddle/test_import.rb{,.disable} * Mon Aug 29 2022 Jun Aruga - 3.1.2-168 - Make RDoc soft dependnecy in IRB. Resolves: rhbz#2119964 +- Add IRB to ruby-bundled-gems recommends. + Resolves: rhbz#2120562 * Wed Aug 24 2022 Jun Aruga - 3.1.2-168 - Fix tests with Europe/Amsterdam pre-1970 time on tzdata version 2022b. From c2026da1750e6d0cc70c7370a0840628bbbfa965 Mon Sep 17 00:00:00 2001 From: Jarek Prokop Date: Fri, 2 Sep 2022 10:21:43 +0200 Subject: [PATCH 048/141] Disable Fiddle test cases making use of FFI closure. Fiddle::Closure object is making use of FFI closure from libffi. When such object is created (instantiated) in Ruby, and then the process forks on an SELinux-enabled system, the memory will become corrupted. That is usually not a problem until the The garbage collector sweeps the object and tries to free it, in which case the Ruby process will fail with signal SIGABRT. Tests in test/fiddle/test_closure.rb, test/fiddle/test_func.rb, and test/fiddle/test_function.rb use the `Fiddle::Closure` class directly and fiddle/test_import.rb use the class indirectly through `bind_function` method, therefore they are disabled to prevent introducing the problematic object into the Ruby GC during test suite execution instead of relying on that fork and subsequent garbage collection will not happen. If an FFI closure object is allocated in Ruby and the `fork` function is used afterward, the memory pointing to the closure gets corrupted, and if Ruby GC tries to collect the object in that state, a SIGABRT error occurs. The minimal Ruby reproducer for the issue is the following: ~~~ $ cat fiddle_fork.rb require 'fiddle/closure' require 'fiddle/struct' Fiddle::Closure.new(Fiddle::TYPE_VOID, []) fork { } GC.start ~~~ We allocate an unused Closure object, so it is free for the GC to pick up. Before we call `GC.start` we fork the process as that corrupts the memory. Running this with ruby-3.1.2-167.fc37.x86_64 on SELinux enabled system: ~~~ $ ruby fiddle_fork.rb Aborted (core dumped) ~~~ Such issues may appear at random (depending on the use of forking and GC) in larger applications that use Fiddle::Closure but can be spotted by the following functions appearing in the coredump backtrace: ~~~ 0x00007f6284d3e5b3 in dlfree (mem=) at ../src/dlmalloc.c:4350 0x00007f6284d6d0b1 in dealloc () from /usr/lib64/ruby/fiddle.so 0x00007f6295e432ec in finalize_list () from /lib64/libruby.so.3.1 0x00007f6295e43420 in finalize_deferred.lto_priv () from /lib64/libruby.so.3.1 0x00007f6295e4ff1c in gc_start_internal.lto_priv () from /lib64/libruby.so.3.1 ~~~ Possible solutions to prevent Ruby from crashing: * Do not use Fiddle::Closure. * Use the Fiddle::Closure object only in isolated subprocess that will not fork further. * Enable static trampolines in libffi as noted in bugzilla comment: See related discussion on Ruby upstream ticket: Ruby Fiddle ticket: --- ruby.spec | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ruby.spec b/ruby.spec index 22f7e84..c7198db 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 168 +%global release 169 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -991,6 +991,9 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/TestReadline#test_interrupt_in_other_thread/" # other components are fixed. # https://bugzilla.redhat.com/show_bug.cgi?id=2040380 mv test/fiddle/test_import.rb{,.disable} +mv test/fiddle/test_closure.rb{,.disable} +DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunc#test_qsort1/" +DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" # Give an option to increase the timeout in tests. # https://bugs.ruby-lang.org/issues/16921 @@ -1546,6 +1549,10 @@ mv test/fiddle/test_import.rb{,.disable} %changelog +* Fri Sep 02 2022 Jarek Prokop - 3.1.2-169 +- Disable fiddle tests that use FFI closures. + Related: rhbz#2040380 + * Mon Aug 29 2022 Jun Aruga - 3.1.2-168 - Make RDoc soft dependnecy in IRB. Resolves: rhbz#2119964 From 588a4ae9f02928d7bedbcf46a739d36b0a76e632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Thu, 29 Sep 2022 09:27:01 +0200 Subject: [PATCH 049/141] Re-enable package notes. The rhbz#2043092 is not resolved. Nevertheless, the generation of package notes should not break builds of rubygem- packages anymore. Nevertheless, the additional linker options will keep making issues for `gem install`ed gems. Nothing new here unfortunately. --- ruby.spec | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ruby.spec b/ruby.spec index c7198db..ff1d6da 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 169 +%global release 170 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -92,10 +92,6 @@ %bcond_without hardening_test %endif -# The additional linker flags break binary rubygem- packages. -# https://bugzilla.redhat.com/show_bug.cgi?id=2043092 -%undefine _package_note_flags - Summary: An interpreter of object-oriented scripting language Name: ruby Version: %{ruby_version} @@ -1549,6 +1545,9 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" %changelog +* Thu Sep 29 2022 Vít Ondruch - 3.1.2-170 +- Re-enable package notes. + * Fri Sep 02 2022 Jarek Prokop - 3.1.2-169 - Disable fiddle tests that use FFI closures. Related: rhbz#2040380 From 79d75fdcddac78d2c73000a6ae7569eabb05f7bc Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Wed, 2 Nov 2022 18:30:04 +0100 Subject: [PATCH 050/141] Bypass git submodule test failure on Git >= 2.38.1. --- ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch | 27 +++++++++++++++++++ ruby.spec | 4 +++ 2 files changed, 31 insertions(+) create mode 100644 ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch diff --git a/ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch b/ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch new file mode 100644 index 0000000..73f9a02 --- /dev/null +++ b/ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch @@ -0,0 +1,27 @@ +From dae843f6b7502f921a7e66f39e3714a39d860181 Mon Sep 17 00:00:00 2001 +From: Hiroshi SHIBATA +Date: Wed, 19 Oct 2022 19:40:00 +0900 +Subject: [PATCH] Bypass git submodule add/update with git config + protocol.file.allow=always option. + +Co-authored-by: Nobuyoshi Nakada +--- + test/rubygems/test_gem_source_git.rb | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/test/rubygems/test_gem_source_git.rb b/test/rubygems/test_gem_source_git.rb +index 5702da05974b6..c3b324771fa4d 100644 +--- a/test/rubygems/test_gem_source_git.rb ++++ b/test/rubygems/test_gem_source_git.rb +@@ -63,6 +63,11 @@ def test_checkout_local_cached + end + + def test_checkout_submodules ++ # We need to allow to checkout submodules with file:// protocol ++ # CVE-2022-39253 ++ # https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/ ++ system(@git, *%W"config --global protocol.file.allow always") ++ + source = Gem::Source::Git.new @name, @repository, 'master', true + + git_gem 'b' diff --git a/ruby.spec b/ruby.spec index ff1d6da..565a547 100644 --- a/ruby.spec +++ b/ruby.spec @@ -204,6 +204,9 @@ Patch27: ruby-irb-1.4.1-drop-rdoc-hard-dep.patch # Set soft dependency on RDoc in input-method.rb in IRB. # https://github.com/ruby/irb/pull/395 Patch28: ruby-irb-1.4.1-set-rdoc-soft-dep.patch +# Bypass git submodule test failure on Git >= 2.38.1. +# https://github.com/ruby/ruby/pull/6587 +Patch29: ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -686,6 +689,7 @@ find .bundle/gems -name '*-[0-9]*.gemspec' -exec cp -t .bundle/specifications/ { %patch26 -p1 %patch27 -p1 %patch28 -p1 +%patch29 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . From 1d0c071aebd50621eb049a2ab8d20da3133f9f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Tue, 22 Nov 2022 17:41:49 +0100 Subject: [PATCH 051/141] Revert "Re-enable package notes." This reverts commit 588a4ae9f02928d7bedbcf46a739d36b0a76e632, because it causes additional issues: https://bugzilla.redhat.com/show_bug.cgi?id=2043092#c67 --- ruby.spec | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ruby.spec b/ruby.spec index 565a547..3375cc6 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 170 +%global release 171 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -92,6 +92,10 @@ %bcond_without hardening_test %endif +# The additional linker flags break binary rubygem- packages. +# https://bugzilla.redhat.com/show_bug.cgi?id=2043092 +%undefine _package_note_flags + Summary: An interpreter of object-oriented scripting language Name: ruby Version: %{ruby_version} @@ -1549,6 +1553,10 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" %changelog +* Tue Nov 22 2022 Vít Ondruch - 3.1.2-171 +- Re-disable package notes. It causes additional issues with installing binary + gems. + * Thu Sep 29 2022 Vít Ondruch - 3.1.2-170 - Re-enable package notes. From 649a6e3083fc66b95c956427cc269bdc7dc21cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Fri, 25 Nov 2022 13:49:21 +0100 Subject: [PATCH 052/141] Upgrade to Ruby 3.1.3. --- ruby-1.9.3-mkmf-verbose.patch | 4 +- ...0-Enable-configuration-of-archlibdir.patch | 2 +- ...ed-paths-when-empty-version-string-i.patch | 2 +- ruby-2.1.0-always-use-i386.patch | 2 +- ruby-2.1.0-custom-rubygems-location.patch | 4 +- ruby-2.3.0-ruby_version.patch | 42 +- ruby-2.7.0-Initialize-ABRT-hook.patch | 4 +- ...-extension-libraries-in-bundled-gems.patch | 338 -------------- ...ct-compaction-support-during-runtime.patch | 26 +- ...paction-methods-as-rb_f_notimplement.patch | 414 +++++++++++------- ...c-compaction-methods_generated-files.patch | 44 +- ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch | 27 -- ...0-bundle-update-bundler-test-in-ruby.patch | 31 -- ruby-irb-1.4.1-set-rdoc-soft-dep.patch | 6 - ...aned-up-error-with-temporary-gemhome.patch | 22 - ruby-spec-Fix-tests-on-tzdata-2022b.patch | 40 -- ruby.spec | 97 ++-- sources | 2 +- 18 files changed, 362 insertions(+), 745 deletions(-) delete mode 100644 ruby-3.2.0-Build-extension-libraries-in-bundled-gems.patch delete mode 100644 ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch delete mode 100644 ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch delete mode 100644 ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.patch delete mode 100644 ruby-spec-Fix-tests-on-tzdata-2022b.patch diff --git a/ruby-1.9.3-mkmf-verbose.patch b/ruby-1.9.3-mkmf-verbose.patch index 2113bea..03128be 100644 --- a/ruby-1.9.3-mkmf-verbose.patch +++ b/ruby-1.9.3-mkmf-verbose.patch @@ -11,11 +11,11 @@ diff --git a/lib/mkmf.rb b/lib/mkmf.rb index 682eb46..e6b1445 100644 --- a/lib/mkmf.rb +++ b/lib/mkmf.rb -@@ -1974,7 +1974,7 @@ def configuration(srcdir) +@@ -1971,7 +1971,7 @@ def configuration(srcdir) SHELL = /bin/sh # V=0 quiet, V=1 verbose. other values don't work. --V = 0 +-V = #{CONFIG['MKMF_VERBOSE']} +V = 1 V0 = $(V:0=) Q1 = $(V:1=) diff --git a/ruby-2.1.0-Enable-configuration-of-archlibdir.patch b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch index f82660f..502b47a 100644 --- a/ruby-2.1.0-Enable-configuration-of-archlibdir.patch +++ b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch @@ -11,7 +11,7 @@ diff --git a/configure.ac b/configure.ac index d261ea57b5..3c13076b82 100644 --- a/configure.ac +++ b/configure.ac -@@ -3368,6 +3368,11 @@ AS_IF([test ${multiarch+set}], [ +@@ -3374,6 +3374,11 @@ AS_IF([test ${multiarch+set}], [ ]) archlibdir='${libdir}/${arch}' 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 index 041f475..8961723 100644 --- 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 @@ -14,7 +14,7 @@ diff --git a/configure.ac b/configure.ac index c42436c23d..d261ea57b5 100644 --- a/configure.ac +++ b/configure.ac -@@ -4026,7 +4026,8 @@ AS_CASE(["$ruby_version_dir_name"], +@@ -4032,7 +4032,8 @@ AS_CASE(["$ruby_version_dir_name"], ruby_version_dir=/'${ruby_version_dir_name}' if test -z "${ruby_version_dir_name}"; then diff --git a/ruby-2.1.0-always-use-i386.patch b/ruby-2.1.0-always-use-i386.patch index dffeb91..1a9a758 100644 --- a/ruby-2.1.0-always-use-i386.patch +++ b/ruby-2.1.0-always-use-i386.patch @@ -11,7 +11,7 @@ diff --git a/configure.ac b/configure.ac index 3c13076b82..93af30321d 100644 --- a/configure.ac +++ b/configure.ac -@@ -4090,6 +4090,8 @@ AC_SUBST(vendorarchdir)dnl +@@ -4096,6 +4096,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 diff --git a/ruby-2.1.0-custom-rubygems-location.patch b/ruby-2.1.0-custom-rubygems-location.patch index fdf0dfe..fe34219 100644 --- a/ruby-2.1.0-custom-rubygems-location.patch +++ b/ruby-2.1.0-custom-rubygems-location.patch @@ -15,7 +15,7 @@ diff --git a/configure.ac b/configure.ac index 93af30321d..bc13397e0e 100644 --- a/configure.ac +++ b/configure.ac -@@ -4062,6 +4062,10 @@ AC_ARG_WITH(vendorarchdir, +@@ -4068,6 +4068,10 @@ AC_ARG_WITH(vendorarchdir, [vendorarchdir=$withval], [vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby'${ruby_version_dir}}${multiarch-'${vendorlibdir}/${sitearch}'}]) @@ -26,7 +26,7 @@ index 93af30321d..bc13397e0e 100644 AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) RUBY_EXEC_PREFIX='' -@@ -4086,6 +4090,7 @@ AC_SUBST(sitearchdir)dnl +@@ -4092,6 +4096,7 @@ AC_SUBST(sitearchdir)dnl AC_SUBST(vendordir)dnl AC_SUBST(vendorlibdir)dnl AC_SUBST(vendorarchdir)dnl diff --git a/ruby-2.3.0-ruby_version.patch b/ruby-2.3.0-ruby_version.patch index 1f42472..2508aeb 100644 --- a/ruby-2.3.0-ruby_version.patch +++ b/ruby-2.3.0-ruby_version.patch @@ -20,7 +20,7 @@ diff --git a/configure.ac b/configure.ac index 80b137e380..63cd3b4f8b 100644 --- a/configure.ac +++ b/configure.ac -@@ -3977,9 +3977,6 @@ AS_CASE(["$target_os"], +@@ -3983,9 +3983,6 @@ AS_CASE(["$target_os"], rubyw_install_name='$(RUBYW_INSTALL_NAME)' ]) @@ -30,7 +30,7 @@ index 80b137e380..63cd3b4f8b 100644 rubyarchprefix=${multiarch+'${archlibdir}/${RUBY_BASE_NAME}'}${multiarch-'${rubylibprefix}/${arch}'} AC_ARG_WITH(rubyarchprefix, AS_HELP_STRING([--with-rubyarchprefix=DIR], -@@ -4002,56 +3999,62 @@ AC_ARG_WITH(ridir, +@@ -4008,56 +4005,62 @@ AC_ARG_WITH(ridir, AC_SUBST(ridir) AC_SUBST(RI_BASE_NAME) @@ -120,7 +120,7 @@ index 80b137e380..63cd3b4f8b 100644 AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) -@@ -4068,6 +4071,7 @@ AC_SUBST(sitearchincludedir)dnl +@@ -4074,6 +4077,7 @@ AC_SUBST(sitearchincludedir)dnl AC_SUBST(arch)dnl AC_SUBST(sitearch)dnl AC_SUBST(ruby_version)dnl @@ -202,8 +202,8 @@ index d4ff4a262c..3f9a5bf590 100644 # specified in the environment def self.default_dir -- @default_dir ||= File.join(RbConfig::CONFIG['rubylibprefix'], 'gems', RbConfig::CONFIG['ruby_version']) -+ @default_dir ||= File.join(RbConfig::CONFIG['rubylibprefix'], 'gems', RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version']) +- @default_dir ||= File.join(RbConfig::CONFIG["rubylibprefix"], "gems", RbConfig::CONFIG["ruby_version"]) ++ @default_dir ||= File.join(RbConfig::CONFIG["rubylibprefix"], "gems", RbConfig::CONFIG["ruby_version_dir_name"] || RbConfig::CONFIG["ruby_version"]) end ## @@ -211,18 +211,18 @@ index d4ff4a262c..3f9a5bf590 100644 gem_dir = File.join(Gem.user_home, ".gem") gem_dir = File.join(Gem.data_home, "gem") unless File.exist?(gem_dir) parts = [gem_dir, ruby_engine] -- 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 << 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 @@ -234,7 +235,7 @@ def self.vendor_dir # :nodoc: - return nil unless RbConfig::CONFIG.key? 'vendordir' + 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'] + File.join RbConfig::CONFIG["vendordir"], "gems", +- RbConfig::CONFIG["ruby_version"] ++ RbConfig::CONFIG["ruby_version_dir_name"] || RbConfig::CONFIG["ruby_version"] end ## @@ -230,22 +230,22 @@ diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index b25068405d..e9fef4a311 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb -@@ -1410,7 +1410,8 @@ def test_self_use_paths +@@ -1395,7 +1395,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 = [@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? FileUtils.mkdir_p File.join(parts) -@@ -1486,7 +1487,7 @@ def test_self_vendor_dir - vendordir(File.join(@tempdir, 'vendor')) do +@@ -1471,7 +1472,7 @@ def test_self_vendor_dir + vendordir(File.join(@tempdir, "vendor")) do expected = - File.join RbConfig::CONFIG['vendordir'], 'gems', -- RbConfig::CONFIG['ruby_version'] -+ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] + 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 @@ -267,7 +267,7 @@ diff --git a/configure.ac b/configure.ac index a00f2b6776..999e2d6d5d 100644 --- a/configure.ac +++ b/configure.ac -@@ -108,7 +108,7 @@ RUBY_BASE_NAME=`echo ruby | sed "$program_transform_name"` +@@ -115,7 +115,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) diff --git a/ruby-2.7.0-Initialize-ABRT-hook.patch b/ruby-2.7.0-Initialize-ABRT-hook.patch index fc2bd08..4d5ab29 100644 --- a/ruby-2.7.0-Initialize-ABRT-hook.patch +++ b/ruby-2.7.0-Initialize-ABRT-hook.patch @@ -45,7 +45,7 @@ index b2e5b2b6d0..f39f81da5c 100644 +++ b/common.mk @@ -82,7 +82,8 @@ ENC_MK = enc.mk MAKE_ENC = -f $(ENC_MK) V="$(V)" UNICODE_HDR_DIR="$(UNICODE_HDR_DIR)" \ - RUBY="$(MINIRUBY)" MINIRUBY="$(MINIRUBY)" $(mflags) + RUBY="$(BOOTSTRAPRUBY)" MINIRUBY="$(BOOTSTRAPRUBY)" $(mflags) -COMMONOBJS = array.$(OBJEXT) \ +COMMONOBJS = abrt.$(OBJEXT) \ @@ -57,7 +57,7 @@ diff --git a/ruby.c b/ruby.c index 60c57d6259..1eec16f2c8 100644 --- a/ruby.c +++ b/ruby.c -@@ -1611,10 +1611,14 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt) +@@ -1623,10 +1623,14 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt) void Init_builtin_features(void); diff --git a/ruby-3.2.0-Build-extension-libraries-in-bundled-gems.patch b/ruby-3.2.0-Build-extension-libraries-in-bundled-gems.patch deleted file mode 100644 index de8d4d3..0000000 --- a/ruby-3.2.0-Build-extension-libraries-in-bundled-gems.patch +++ /dev/null @@ -1,338 +0,0 @@ -From 111f8422427d78becc9183ae149b2105a16bf327 Mon Sep 17 00:00:00 2001 -From: Nobuyoshi Nakada -Date: Tue, 5 Apr 2022 23:24:00 +0900 -Subject: [PATCH 1/5] Bundled gems are expanded under `.bundle/gems` now - ---- - ext/extmk.rb | 13 +++++++------ - template/exts.mk.tmpl | 2 +- - 2 files changed, 8 insertions(+), 7 deletions(-) - -diff --git a/ext/extmk.rb b/ext/extmk.rb -index 4a087f294ac9..1da9e2704521 100755 ---- a/ext/extmk.rb -+++ b/ext/extmk.rb -@@ -146,7 +146,7 @@ def extmake(target, basedir = 'ext', maybestatic = true) - top_srcdir = $top_srcdir - topdir = $topdir - hdrdir = $hdrdir -- prefix = "../" * (target.count("/")+1) -+ prefix = "../" * (basedir.count("/")+target.count("/")+1) - $top_srcdir = relative_from(top_srcdir, prefix) - $hdrdir = relative_from(hdrdir, prefix) - $topdir = prefix + $topdir -@@ -460,10 +460,11 @@ def $mflags.defined?(var) - end unless $extstatic - - @gemname = nil --if ARGV[0] -- ext_prefix, exts = ARGV.shift.split('/', 2) -+if exts = ARGV.shift -+ ext_prefix = exts[%r[\A(?>\.bundle/)?[^/]+(?:/(?=(.+)?)|\z)]] -+ exts = $1 - $extension = [exts] if exts -- if ext_prefix == 'gems' -+ if ext_prefix.start_with?('.') - @gemname = exts - elsif exts - $static_ext.delete_if {|t, *| !File.fnmatch(t, exts)} -@@ -515,7 +516,7 @@ def $mflags.defined?(var) - exts.delete_if {|d| File.fnmatch?("-*", d)} - end - end --ext_prefix = File.basename(ext_prefix) -+ext_prefix = ext_prefix[$top_srcdir.size+1..-2] - - extend Module.new { - def timestamp_file(name, target_prefix = nil) -@@ -634,7 +635,7 @@ def initialize(src) - end - } - --Dir.chdir ".." -+Dir.chdir dir - unless $destdir.to_s.empty? - $mflags.defined?("DESTDIR") or $mflags << "DESTDIR=#{$destdir}" - end -diff --git a/template/exts.mk.tmpl b/template/exts.mk.tmpl -index 2f37f4480ac5..964939e365a1 100644 ---- a/template/exts.mk.tmpl -+++ b/template/exts.mk.tmpl -@@ -25,7 +25,7 @@ macros["old_extensions"] = [] - - contpat = /(?>(?>[^\\\n]|\\.)*\\\n)*(?>[^\\\n]|\\.)*/ - Dir.glob("{ext,.bundle/gems}/*/exts.mk") do |e| -- gem = /\Agems(?=\/)/ =~ e -+ gem = e.start_with?(".bundle/gems/") - s = File.read(e) - s.scan(/^(extensions|SUBMAKEOPTS|EXT[A-Z]+|MFLAGS|NOTE_[A-Z]+)[ \t]*=[ \t]*(#{contpat})$/o) do |n, v| - v.gsub!(/\\\n[ \t]*/, ' ') - -From 6ea34cac22131d28a9cc50e7875e854aed9bdb88 Mon Sep 17 00:00:00 2001 -From: Nobuyoshi Nakada -Date: Wed, 6 Apr 2022 20:25:53 +0900 -Subject: [PATCH 2/5] Retrieve configured gems info - ---- - template/configure-ext.mk.tmpl | 2 +- - template/exts.mk.tmpl | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/template/configure-ext.mk.tmpl b/template/configure-ext.mk.tmpl -index 6636a7759c54..8ba6b963e3ec 100644 ---- a/template/configure-ext.mk.tmpl -+++ b/template/configure-ext.mk.tmpl -@@ -27,7 +27,7 @@ SCRIPT_ARGS = <%=script_args.gsub("#", "\\#")%> - EXTMK_ARGS = $(SCRIPT_ARGS) --gnumake=$(gnumake) --extflags="$(EXTLDFLAGS)" \ - --make-flags="MINIRUBY='$(MINIRUBY)'" - --all: exts # gems -+all: exts gems - exts: - gems: - -diff --git a/template/exts.mk.tmpl b/template/exts.mk.tmpl -index 964939e365a1..e544c4c88bd7 100644 ---- a/template/exts.mk.tmpl -+++ b/template/exts.mk.tmpl -@@ -19,7 +19,7 @@ opt = OptionParser.new do |o| - o.on('--configure-exts=FILE') {|v| confexts = v} - o.order!(ARGV) - end --confexts &&= File.read(confexts).scan(/^exts: (.*\.mk)/).flatten rescue nil -+confexts &&= File.read(confexts).scan(/^(?:ext|gem)s: (.*\.mk)/).flatten rescue nil - confexts ||= [] - macros["old_extensions"] = [] - -@@ -30,7 +30,7 @@ Dir.glob("{ext,.bundle/gems}/*/exts.mk") do |e| - s.scan(/^(extensions|SUBMAKEOPTS|EXT[A-Z]+|MFLAGS|NOTE_[A-Z]+)[ \t]*=[ \t]*(#{contpat})$/o) do |n, v| - v.gsub!(/\\\n[ \t]*/, ' ') - next if v.empty? -- next if gem and n != "extensions" -+ next if n != "extensions" - n = "old_extensions" if n == "extensions" and !confexts.include?(e) - v = v.split - m = macros[n] ||= [] - -From be9d00ee7c72766551ba8c3530f1538034498a6a Mon Sep 17 00:00:00 2001 -From: Nobuyoshi Nakada -Date: Wed, 6 Apr 2022 20:28:00 +0900 -Subject: [PATCH 3/5] Move the target directory of bundled gems like as - rubygems - ---- - ext/extmk.rb | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/ext/extmk.rb b/ext/extmk.rb -index 1da9e2704521..a440af27fc5d 100755 ---- a/ext/extmk.rb -+++ b/ext/extmk.rb -@@ -2,6 +2,9 @@ - # -*- mode: ruby; coding: us-ascii -*- - # frozen_string_literal: false - -+module Gem; end # only needs Gem::Platform -+require 'rubygems/platform' -+ - # :stopdoc: - $extension = nil - $extstatic = nil -@@ -535,11 +538,12 @@ def create_makefile(*args, &block) - super(*args) do |conf| - conf.find do |s| - s.sub!(/^(TARGET_SO_DIR *= *)\$\(RUBYARCHDIR\)/) { -- "TARGET_GEM_DIR = $(extout)/gems/$(arch)/#{@gemname}\n"\ -+ "TARGET_GEM_DIR = $(topdir)/.bundle/extensions/$(gem_platform)/$(ruby_version)/#{@gemname}\n"\ - "#{$1}$(TARGET_GEM_DIR)$(target_prefix)" - } - end - conf.any? {|s| /^TARGET *= *\S/ =~ s} and conf << %{ -+gem_platform = #{Gem::Platform.local} - - # default target - all: - -From c4daf8e445925695c34bab8bf5135dcd1e8575a3 Mon Sep 17 00:00:00 2001 -From: Nobuyoshi Nakada -Date: Wed, 6 Apr 2022 22:57:01 +0900 -Subject: [PATCH 4/5] Obey spec file locations to rubygems - ---- - common.mk | 3 ++- - defs/gmake.mk | 2 +- - tool/gem-unpack.rb | 5 +++-- - 3 files changed, 6 insertions(+), 4 deletions(-) - -diff --git a/common.mk b/common.mk -index 7c552cba1e04..b4adb2729c0e 100644 ---- a/common.mk -+++ b/common.mk -@@ -1359,10 +1359,11 @@ extract-gems$(gnumake:yes=-nongnumake): PHONY - $(Q) $(RUNRUBY) -C "$(srcdir)" \ - -Itool -rgem-unpack -answ \ - -e 'BEGIN {FileUtils.mkdir_p(d = ".bundle/gems")}' \ -+ -e 'BEGIN {FileUtils.mkdir_p(s = ".bundle/specifications")}' \ - -e 'gem, ver = *$$F' \ - -e 'next if !ver or /^#/=~gem' \ - -e 'g = "#{gem}-#{ver}"' \ -- -e 'File.directory?("#{d}/#{g}") or Gem.unpack("gems/#{g}.gem", d)' \ -+ -e 'File.directory?("#{d}/#{g}") or Gem.unpack("gems/#{g}.gem", d, s)' \ - gems/bundled_gems - - update-bundled_gems: PHONY -diff --git a/defs/gmake.mk b/defs/gmake.mk -index a625379a6804..27e3e21cc4d6 100644 ---- a/defs/gmake.mk -+++ b/defs/gmake.mk -@@ -290,7 +290,7 @@ extract-gems: | $(patsubst %,.bundle/gems/%,$(bundled-gems)) - $(ECHO) Extracting bundle gem $*... - $(Q) $(BASERUBY) -C "$(srcdir)" \ - -Itool -rgem-unpack \ -- -e 'Gem.unpack("gems/$(@F).gem", ".bundle/gems")' -+ -e 'Gem.unpack("gems/$(@F).gem", ".bundle/gems", ".bundle/specifications")' - - $(srcdir)/.bundle/gems: - $(MAKEDIRS) $@ -diff --git a/tool/gem-unpack.rb b/tool/gem-unpack.rb -index cb05719463f2..fe10b0e420fa 100644 ---- a/tool/gem-unpack.rb -+++ b/tool/gem-unpack.rb -@@ -5,13 +5,14 @@ - # This library is used by "make extract-gems" to - # unpack bundled gem files. - --def Gem.unpack(file, dir = nil) -+def Gem.unpack(file, dir = nil, spec_dir = nil) - pkg = Gem::Package.new(file) - spec = pkg.spec - target = spec.full_name - target = File.join(dir, target) if dir - pkg.extract_files target -- spec_file = File.join(target, "#{spec.name}-#{spec.version}.gemspec") -+ FileUtils.mkdir_p(spec_dir ||= target) -+ spec_file = File.join(spec_dir, "#{spec.name}-#{spec.version}.gemspec") - open(spec_file, 'wb') do |f| - f.print spec.to_ruby - end - -From 3de652d8198be9cd2998c095903889a80e738275 Mon Sep 17 00:00:00 2001 -From: Nobuyoshi Nakada -Date: Thu, 7 Apr 2022 01:44:43 +0900 -Subject: [PATCH 5/5] Install built gem extension binaries - ---- - tool/rbinstall.rb | 56 ++++++++++++++--------------------------------- - 1 file changed, 16 insertions(+), 40 deletions(-) - -diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb -index 9d9b672be472..624961b4eee6 100755 ---- a/tool/rbinstall.rb -+++ b/tool/rbinstall.rb -@@ -858,6 +858,9 @@ class UnpackedInstaller < GemInstaller - def write_cache_file - end - -+ def build_extensions -+ end -+ - def shebang(bin_file_name) - path = File.join(gem_dir, spec.bindir, bin_file_name) - first_line = File.open(path, "rb") {|file| file.gets} -@@ -940,13 +943,12 @@ def ensure_writable_dir(dir) - install_default_gem('ext', srcdir, bindir) - end - --def load_gemspec(file, expanded = false) -+def load_gemspec(file, base = nil) - file = File.realpath(file) - code = File.read(file, encoding: "utf-8:-") - code.gsub!(/(?:`git[^\`]*`|%x\[git[^\]]*\])\.split\([^\)]*\)/m) do - files = [] -- if expanded -- base = File.dirname(file) -+ if base - Dir.glob("**/*", File::FNM_DOTMATCH, base: base) do |n| - case File.basename(n); when ".", ".."; next; end - next if File.directory?(File.join(base, n)) -@@ -959,7 +961,7 @@ def load_gemspec(file, expanded = false) - unless Gem::Specification === spec - raise TypeError, "[#{file}] isn't a Gem::Specification (#{spec.class} instead)." - end -- spec.loaded_from = file -+ spec.loaded_from = base ? File.join(base, File.basename(file)) : file - spec.files.reject! {|n| n.end_with?(".gemspec") or n.start_with?(".git")} - - spec -@@ -1014,20 +1016,6 @@ def install_default_gem(dir, srcdir, bindir) - end - - install?(:ext, :comm, :gem, :'bundled-gems') do -- if CONFIG['CROSS_COMPILING'] == 'yes' -- # The following hacky steps set "$ruby = BASERUBY" in tool/fake.rb -- $hdrdir = '' -- $extmk = nil -- $ruby = nil # ... -- ruby_path = $ruby + " -I#{Dir.pwd}" # $baseruby + " -I#{Dir.pwd}" -- else -- # ruby_path = File.expand_path(with_destdir(File.join(bindir, ruby_install_name))) -- ENV['RUBYLIB'] = nil -- ENV['RUBYOPT'] = nil -- ruby_path = File.expand_path(with_destdir(File.join(bindir, ruby_install_name))) + " --disable=gems -I#{with_destdir(archlibdir)}" -- end -- Gem.instance_variable_set(:@ruby, ruby_path) if Gem.ruby != ruby_path -- - gem_dir = Gem.default_dir - install_dir = with_destdir(gem_dir) - prepare "bundled gems", gem_dir -@@ -1047,40 +1035,28 @@ def install_default_gem(dir, srcdir, bindir) - :wrappers => true, - :format_executable => true, - } -- gem_ext_dir = "#$extout/gems/#{CONFIG['arch']}" -- extensions_dir = with_destdir(Gem::StubSpecification.gemspec_stub("", gem_dir, gem_dir).extensions_dir) -+ -+ extensions_dir = Gem::StubSpecification.gemspec_stub("", gem_dir, gem_dir).extensions_dir -+ specifications_dir = File.join(gem_dir, "specifications") -+ build_dir = Gem::StubSpecification.gemspec_stub("", ".bundle", ".bundle").extensions_dir - - File.foreach("#{srcdir}/gems/bundled_gems") do |name| - next if /^\s*(?:#|$)/ =~ name - next unless /^(\S+)\s+(\S+).*/ =~ name - gem_name = "#$1-#$2" -- path = "#{srcdir}/.bundle/gems/#{gem_name}/#{gem_name}.gemspec" -- if File.exist?(path) -- spec = load_gemspec(path) -- else -- path = "#{srcdir}/.bundle/gems/#{gem_name}/#$1.gemspec" -- next unless File.exist?(path) -- spec = load_gemspec(path, true) -- end -+ path = "#{srcdir}/.bundle/specifications/#{gem_name}.gemspec" -+ next unless File.exist?(path) -+ spec = load_gemspec(path, "#{srcdir}/.bundle/gems/#{gem_name}") - next unless spec.platform == Gem::Platform::RUBY - next unless spec.full_name == gem_name -- if !spec.extensions.empty? && CONFIG["EXTSTATIC"] == "static" -- puts "skip installation of #{spec.name} #{spec.version}; bundled gem with an extension library is not supported on --with-static-linked-ext" -- next -- end - spec.extension_dir = "#{extensions_dir}/#{spec.full_name}" -- if File.directory?(ext = "#{gem_ext_dir}/#{spec.full_name}") -- spec.extensions[0] ||= "-" -- end - package = RbInstall::DirPackage.new spec - ins = RbInstall::UnpackedInstaller.new(package, options) - puts "#{INDENT}#{spec.name} #{spec.version}" - ins.install -- unless $dryrun -- File.chmod($data_mode, File.join(install_dir, "specifications", "#{spec.full_name}.gemspec")) -- end -- unless spec.extensions.empty? -- install_recursive(ext, spec.extension_dir) -+ install_recursive("#{build_dir}/#{gem_name}", "#{extensions_dir}/#{gem_name}") do |src, dest| -+ # puts "#{INDENT} #{dest[extensions_dir.size+gem_name.size+2..-1]}" -+ install src, dest, :mode => (File.executable?(src) ? $prog_mode : $data_mode) - end - installed_gems[spec.full_name] = true - end diff --git a/ruby-3.2.0-Detect-compaction-support-during-runtime.patch b/ruby-3.2.0-Detect-compaction-support-during-runtime.patch index fd8162f..64566f5 100644 --- a/ruby-3.2.0-Detect-compaction-support-during-runtime.patch +++ b/ruby-3.2.0-Detect-compaction-support-during-runtime.patch @@ -75,7 +75,6 @@ the line above. Because while the Ruby on the master branch replaced the USE_MMAP_ALIGNED_ALLOC with HEAP_PAGE_ALLOC_USE_MMAP, Ruby 3.1.2 doesn't. See . - ``` + rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1); ``` @@ -87,7 +86,6 @@ the case that GC_COMPACTION_SUPPORTED is true, Ruby 3.1.2 doesn't define it in the gc.rb. See . - ``` + OPT(GC_COMPACTION_SUPPORTED); ``` @@ -141,7 +139,7 @@ diff --git a/gc.c b/gc.c index 1c35856c44..bff0666a17 100644 --- a/gc.c +++ b/gc.c -@@ -4980,6 +4980,23 @@ gc_unprotect_pages(rb_objspace_t *objspace, rb_heap_t *heap) +@@ -4984,6 +4984,23 @@ gc_unprotect_pages(rb_objspace_t *objspace, rb_heap_t *heap) static void gc_update_references(rb_objspace_t * objspace); static void invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page); @@ -165,7 +163,7 @@ index 1c35856c44..bff0666a17 100644 static void read_barrier_handler(uintptr_t address) { -@@ -5000,6 +5017,7 @@ read_barrier_handler(uintptr_t address) +@@ -5004,6 +5021,7 @@ read_barrier_handler(uintptr_t address) } RB_VM_LOCK_LEAVE(); } @@ -173,7 +171,7 @@ index 1c35856c44..bff0666a17 100644 #if defined(_WIN32) static LPTOP_LEVEL_EXCEPTION_FILTER old_handler; -@@ -9250,13 +9268,7 @@ gc_start_internal(rb_execution_context_t *ec, VALUE self, VALUE full_mark, VALUE +@@ -9267,13 +9285,7 @@ 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)) { @@ -188,7 +186,7 @@ index 1c35856c44..bff0666a17 100644 reason |= GPR_FLAG_COMPACT; } -@@ -9421,7 +9433,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t slot_size) +@@ -9438,7 +9450,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t slot_size) return (VALUE)src; } @@ -197,7 +195,7 @@ index 1c35856c44..bff0666a17 100644 static int compare_free_slots(const void *left, const void *right, void *dummy) { -@@ -10149,7 +10161,7 @@ gc_update_references(rb_objspace_t *objspace) +@@ -10166,7 +10178,7 @@ gc_update_references(rb_objspace_t *objspace) gc_update_table_refs(objspace, finalizer_table); } @@ -206,7 +204,7 @@ index 1c35856c44..bff0666a17 100644 /* * call-seq: * GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}} -@@ -10190,7 +10202,7 @@ gc_compact_stats(VALUE self) +@@ -10207,7 +10219,7 @@ gc_compact_stats(VALUE self) # define gc_compact_stats rb_f_notimplement #endif @@ -215,7 +213,7 @@ index 1c35856c44..bff0666a17 100644 static void root_obj_check_moved_i(const char *category, VALUE obj, void *data) { -@@ -10269,7 +10281,7 @@ gc_compact(VALUE self) +@@ -10286,7 +10298,7 @@ gc_compact(VALUE self) # define gc_compact rb_f_notimplement #endif @@ -224,7 +222,7 @@ index 1c35856c44..bff0666a17 100644 /* * call-seq: * GC.verify_compaction_references(toward: nil, double_heap: false) -> hash -@@ -10800,7 +10812,7 @@ gc_disable(rb_execution_context_t *ec, VALUE _) +@@ -10817,7 +10829,7 @@ gc_disable(rb_execution_context_t *ec, VALUE _) return rb_gc_disable(); } @@ -233,7 +231,7 @@ index 1c35856c44..bff0666a17 100644 /* * call-seq: * GC.auto_compact = flag -@@ -10814,8 +10826,7 @@ gc_disable(rb_execution_context_t *ec, VALUE _) +@@ -10831,8 +10843,7 @@ gc_disable(rb_execution_context_t *ec, VALUE _) static VALUE gc_set_auto_compact(VALUE _, VALUE v) { @@ -243,7 +241,7 @@ index 1c35856c44..bff0666a17 100644 ruby_enable_autocompact = RTEST(v); return v; -@@ -10824,7 +10835,8 @@ gc_set_auto_compact(VALUE _, VALUE v) +@@ -10841,7 +10852,8 @@ gc_set_auto_compact(VALUE _, VALUE v) # define gc_set_auto_compact rb_f_notimplement #endif @@ -253,7 +251,7 @@ index 1c35856c44..bff0666a17 100644 /* * call-seq: * GC.auto_compact -> true or false -@@ -13696,11 +13708,21 @@ Init_GC(void) +@@ -13714,11 +13726,21 @@ Init_GC(void) rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0); rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0); #endif @@ -280,7 +278,7 @@ index 1c35856c44..bff0666a17 100644 #if GC_DEBUG_STRESS_TO_CLASS rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1); -@@ -13724,6 +13746,7 @@ Init_GC(void) +@@ -13742,6 +13764,7 @@ Init_GC(void) OPT(MALLOC_ALLOCATED_SIZE); OPT(MALLOC_ALLOCATED_SIZE_CHECK); OPT(GC_PROFILE_DETAIL_MEMORY); diff --git a/ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch b/ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch index 1e34def..1a06227 100644 --- a/ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch +++ b/ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch @@ -1,34 +1,31 @@ -commit 6d1ca6737f31b2e24664a093f1827dd74a121a9f -Author: Jarek Prokop -Date: Thu May 26 11:28:13 2022 +0200 +From 1b3502156a665e2782f366aa5ac8c3bfd7637ab8 Mon Sep 17 00:00:00 2001 +From: Mike Dalessio +Date: Mon, 23 May 2022 15:40:22 -0400 +Subject: [PATCH 1/2] Move compaction-related methods into gc.c - Gc ppc64le fix +These methods are removed from gc.rb and added to gc.c: + +- GC.compact +- GC.auto_compact +- GC.auto_compact= +- GC.latest_compact_info +- GC.verify_compaction_references + +This is a prefactor to allow setting these methods to +`rb_f_notimplement` in a followup commit. +--- + gc.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ + gc.rb | 68 --------------------------------------- + 2 files changed, 91 insertions(+), 78 deletions(-) diff --git a/gc.c b/gc.c index ef9327df1f..1c35856c44 100644 --- a/gc.c +++ b/gc.c -@@ -9421,6 +9421,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t slot_size) - return (VALUE)src; - } - -+#if GC_COMPACTION_SUPPORTED - static int - compare_free_slots(const void *left, const void *right, void *dummy) - { -@@ -9468,6 +9469,7 @@ gc_sort_heap_by_empty_slots(rb_objspace_t *objspace) - free(page_list); - } - } -+#endif - - static void - gc_ref_update_array(rb_objspace_t * objspace, VALUE v) -@@ -10147,8 +10149,21 @@ gc_update_references(rb_objspace_t *objspace) +@@ -10164,8 +10164,20 @@ gc_update_references(rb_objspace_t *objspace) gc_update_table_refs(objspace, finalizer_table); } -+#if GC_COMPACTION_SUPPORTED +/* + * call-seq: + * GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}} @@ -47,19 +44,7 @@ index ef9327df1f..1c35856c44 100644 { size_t i; rb_objspace_t *objspace = &rb_objspace; -@@ -10171,7 +10186,11 @@ gc_compact_stats(rb_execution_context_t *ec, VALUE self) - - return h; - } -+#else -+# define gc_compact_stats rb_f_notimplement -+#endif - -+#if GC_COMPACTION_SUPPORTED - static void - root_obj_check_moved_i(const char *category, VALUE obj, void *data) - { -@@ -10221,22 +10240,78 @@ heap_check_moved_i(void *vstart, void *vend, size_t stride, void *data) +@@ -10238,22 +10250,70 @@ heap_check_moved_i(void *vstart, void *vend, size_t stride, void *data) return 0; } @@ -75,10 +60,6 @@ index ef9327df1f..1c35856c44 100644 + * + * This method is implementation specific and not expected to be implemented + * in any implementation besides MRI. -+ * -+ * To test whether GC compaction is supported, use the idiom: -+ * -+ * GC.respond_to?(:compact) + */ static VALUE -gc_compact(rb_execution_context_t *ec, VALUE self) @@ -91,11 +72,7 @@ index ef9327df1f..1c35856c44 100644 - return gc_compact_stats(ec, self); + return gc_compact_stats(self); } -+#else -+# define gc_compact rb_f_notimplement -+#endif -+#if GC_COMPACTION_SUPPORTED +/* + * call-seq: + * GC.verify_compaction_references(toward: nil, double_heap: false) -> hash @@ -143,7 +120,7 @@ index ef9327df1f..1c35856c44 100644 RB_VM_LOCK_ENTER(); { -@@ -10256,13 +10331,16 @@ gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE do +@@ -10273,12 +10333,12 @@ gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE do } RB_VM_LOCK_LEAVE(); @@ -156,17 +133,12 @@ index ef9327df1f..1c35856c44 100644 - return gc_compact_stats(ec, self); + return gc_compact_stats(self); } -+#else -+# define gc_verify_compaction_references rb_f_notimplement -+#endif VALUE - rb_gc_start(void) -@@ -10722,26 +10800,45 @@ gc_disable(rb_execution_context_t *ec, VALUE _) +@@ -10739,8 +10799,18 @@ gc_disable(rb_execution_context_t *ec, VALUE _) return rb_gc_disable(); } -+#if GC_COMPACTION_SUPPORTED +/* + * call-seq: + * GC.auto_compact = flag @@ -183,6 +155,237 @@ index ef9327df1f..1c35856c44 100644 { /* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for * the read barrier, so we must disable automatic compaction. */ +@@ -10754,8 +10824,14 @@ gc_set_auto_compact(rb_execution_context_t *ec, VALUE _, VALUE v) + return v; + } + ++/* ++ * call-seq: ++ * GC.auto_compact -> true or false ++ * ++ * Returns whether or not automatic compaction has been enabled. ++ */ + static VALUE +-gc_get_auto_compact(rb_execution_context_t *ec, VALUE _) ++gc_get_auto_compact(VALUE _) + { + return RBOOL(ruby_enable_autocompact); + } +@@ -13617,6 +13693,11 @@ Init_GC(void) + rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0); + rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0); + #endif ++ rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0); ++ rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0); ++ rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1); ++ rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0); ++ rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1); + + #if GC_DEBUG_STRESS_TO_CLASS + rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1); +diff --git a/gc.rb b/gc.rb +index 72637f3796..9265dd7b57 100644 +--- a/gc.rb ++++ b/gc.rb +@@ -38,27 +38,6 @@ def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true + Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false + end + +- # call-seq: +- # GC.auto_compact -> true or false +- # +- # Returns whether or not automatic compaction has been enabled. +- # +- def self.auto_compact +- Primitive.gc_get_auto_compact +- end +- +- # call-seq: +- # GC.auto_compact = flag +- # +- # Updates automatic compaction mode. +- # +- # When enabled, the compactor will execute on every major collection. +- # +- # Enabling compaction will degrade performance on major collections. +- def self.auto_compact=(flag) +- Primitive.gc_set_auto_compact(flag) +- end +- + # call-seq: + # GC.enable -> true or false + # +@@ -210,53 +189,6 @@ def self.latest_gc_info hash_or_key = nil + Primitive.gc_latest_gc_info hash_or_key + end + +- # call-seq: +- # GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}} +- # +- # Returns information about object moved in the most recent GC compaction. +- # +- # The returned hash has two keys :considered and :moved. The hash for +- # :considered lists the number of objects that were considered for movement +- # by the compactor, and the :moved hash lists the number of objects that +- # were actually moved. Some objects can't be moved (maybe they were pinned) +- # so these numbers can be used to calculate compaction efficiency. +- def self.latest_compact_info +- Primitive.gc_compact_stats +- end +- +- # call-seq: +- # GC.compact +- # +- # This function compacts objects together in Ruby's heap. It eliminates +- # unused space (or fragmentation) in the heap by moving objects in to that +- # unused space. This function returns a hash which contains statistics about +- # which objects were moved. See `GC.latest_gc_info` for details about +- # compaction statistics. +- # +- # This method is implementation specific and not expected to be implemented +- # in any implementation besides MRI. +- def self.compact +- Primitive.gc_compact +- end +- +- # call-seq: +- # GC.verify_compaction_references(toward: nil, double_heap: false) -> hash +- # +- # Verify compaction reference consistency. +- # +- # This method is implementation specific. During compaction, objects that +- # were moved are replaced with T_MOVED objects. No object should have a +- # reference to a T_MOVED object after compaction. +- # +- # This function doubles the heap to ensure room to move all objects, +- # compacts the heap to make sure everything moves, updates all references, +- # then performs a full GC. If any object contains a reference to a T_MOVED +- # object, that object should be pushed on the mark stack, and will +- # make a SEGV. +- def self.verify_compaction_references(toward: nil, double_heap: false) +- Primitive.gc_verify_compaction_references(double_heap, toward == :empty) +- end +- + # call-seq: + # GC.using_rvargc? -> true or false + # + +From d3273559356db6852d1fd794f0f076fba100e09e Mon Sep 17 00:00:00 2001 +From: Mike Dalessio +Date: Mon, 23 May 2022 17:31:14 -0400 +Subject: [PATCH 2/2] Define unsupported GC compaction methods as + rb_f_notimplement + +Fixes [Bug #18779] + +Define the following methods as `rb_f_notimplement` on unsupported +platforms: + +- GC.compact +- GC.auto_compact +- GC.auto_compact= +- GC.latest_compact_info +- GC.verify_compaction_references + +This change allows users to call `GC.respond_to?(:compact)` to +properly test for compaction support. Previously, it was necessary to +invoke `GC.compact` or `GC.verify_compaction_references` and check if +those methods raised `NotImplementedError` to determine if compaction +was supported. + +This follows the precedent set for other platform-specific +methods. For example, in `process.c` for methods such as +`Process.fork`, `Process.setpgid`, and `Process.getpriority`. +--- + gc.c | 31 +++++++++++++++---- + test/ruby/test_gc_compact.rb | 58 ++++++++++++++++++++++++++---------- + 2 files changed, 69 insertions(+), 20 deletions(-) + +diff --git a/gc.c b/gc.c +index 92ed76cf96..d71924846a 100644 +--- a/gc.c ++++ b/gc.c +@@ -9438,6 +9438,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t slot_size) + return (VALUE)src; + } + ++#if GC_COMPACTION_SUPPORTED + static int + compare_free_slots(const void *left, const void *right, void *dummy) + { +@@ -9485,6 +9486,7 @@ gc_sort_heap_by_empty_slots(rb_objspace_t *objspace) + free(page_list); + } + } ++#endif + + static void + gc_ref_update_array(rb_objspace_t * objspace, VALUE v) +@@ -10164,6 +10166,7 @@ gc_update_references(rb_objspace_t *objspace) + gc_update_table_refs(objspace, finalizer_table); + } + ++#if GC_COMPACTION_SUPPORTED + /* + * call-seq: + * GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}} +@@ -10200,7 +10203,11 @@ gc_compact_stats(VALUE self) + + return h; + } ++#else ++# define gc_compact_stats rb_f_notimplement ++#endif + ++#if GC_COMPACTION_SUPPORTED + static void + root_obj_check_moved_i(const char *category, VALUE obj, void *data) + { +@@ -10262,6 +10269,10 @@ heap_check_moved_i(void *vstart, void *vend, size_t stride, void *data) + * + * This method is implementation specific and not expected to be implemented + * in any implementation besides MRI. ++ * ++ * To test whether GC compaction is supported, use the idiom: ++ * ++ * GC.respond_to?(:compact) + */ + static VALUE + gc_compact(VALUE self) +@@ -10271,7 +10282,11 @@ gc_compact(VALUE self) + + return gc_compact_stats(self); + } ++#else ++# define gc_compact rb_f_notimplement ++#endif + ++#if GC_COMPACTION_SUPPORTED + /* + * call-seq: + * GC.verify_compaction_references(toward: nil, double_heap: false) -> hash +@@ -10340,6 +10355,9 @@ gc_verify_compaction_references(int argc, VALUE *argv, VALUE self) + + return gc_compact_stats(self); + } ++#else ++# define gc_verify_compaction_references rb_f_notimplement ++#endif + + VALUE + rb_gc_start(void) +@@ -10799,6 +10817,7 @@ gc_disable(rb_execution_context_t *ec, VALUE _) + return rb_gc_disable(); + } + ++#if GC_COMPACTION_SUPPORTED + /* + * call-seq: + * GC.auto_compact = flag +@@ -10814,16 +10833,15 @@ gc_set_auto_compact(VALUE _, VALUE v) + { + /* 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"); @@ -197,15 +400,10 @@ index ef9327df1f..1c35856c44 100644 +#endif +#if GC_COMPACTION_SUPPORTED -+/* -+ * call-seq: -+ * GC.auto_compact -> true or false -+ * -+ * Returns whether or not automatic compaction has been enabled. -+ */ - static VALUE --gc_get_auto_compact(rb_execution_context_t *ec, VALUE _) -+gc_get_auto_compact(VALUE _) + /* + * call-seq: + * GC.auto_compact -> true or false +@@ -10835,6 +10853,9 @@ gc_get_auto_compact(VALUE _) { return RBOOL(ruby_enable_autocompact); } @@ -215,18 +413,6 @@ index ef9327df1f..1c35856c44 100644 static int get_envparam_size(const char *name, size_t *default_value, size_t lower_bound) -@@ -13599,6 +13696,11 @@ Init_GC(void) - rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0); - rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0); - #endif -+ rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0); -+ rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0); -+ rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1); -+ rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0); -+ rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1); - - #if GC_DEBUG_STRESS_TO_CLASS - rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1); diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb index 42ad028530..411d5eab69 100644 --- a/test/ruby/test_gc_compact.rb @@ -314,89 +500,3 @@ index 42ad028530..411d5eab69 100644 end def test_gc_compact_stats -diff --git a/gc.rb b/gc.rb -index 72637f3796..9265dd7b57 100644 ---- a/gc.rb -+++ b/gc.rb -@@ -38,27 +38,6 @@ def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true - Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false - end - -- # call-seq: -- # GC.auto_compact -> true or false -- # -- # Returns whether or not automatic compaction has been enabled. -- # -- def self.auto_compact -- Primitive.gc_get_auto_compact -- end -- -- # call-seq: -- # GC.auto_compact = flag -- # -- # Updates automatic compaction mode. -- # -- # When enabled, the compactor will execute on every major collection. -- # -- # Enabling compaction will degrade performance on major collections. -- def self.auto_compact=(flag) -- Primitive.gc_set_auto_compact(flag) -- end -- - # call-seq: - # GC.enable -> true or false - # -@@ -210,53 +189,6 @@ def self.latest_gc_info hash_or_key = nil - Primitive.gc_latest_gc_info hash_or_key - end - -- # call-seq: -- # GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}} -- # -- # Returns information about object moved in the most recent GC compaction. -- # -- # The returned hash has two keys :considered and :moved. The hash for -- # :considered lists the number of objects that were considered for movement -- # by the compactor, and the :moved hash lists the number of objects that -- # were actually moved. Some objects can't be moved (maybe they were pinned) -- # so these numbers can be used to calculate compaction efficiency. -- def self.latest_compact_info -- Primitive.gc_compact_stats -- end -- -- # call-seq: -- # GC.compact -- # -- # This function compacts objects together in Ruby's heap. It eliminates -- # unused space (or fragmentation) in the heap by moving objects in to that -- # unused space. This function returns a hash which contains statistics about -- # which objects were moved. See `GC.latest_gc_info` for details about -- # compaction statistics. -- # -- # This method is implementation specific and not expected to be implemented -- # in any implementation besides MRI. -- def self.compact -- Primitive.gc_compact -- end -- -- # call-seq: -- # GC.verify_compaction_references(toward: nil, double_heap: false) -> hash -- # -- # Verify compaction reference consistency. -- # -- # This method is implementation specific. During compaction, objects that -- # were moved are replaced with T_MOVED objects. No object should have a -- # reference to a T_MOVED object after compaction. -- # -- # This function doubles the heap to ensure room to move all objects, -- # compacts the heap to make sure everything moves, updates all references, -- # then performs a full GC. If any object contains a reference to a T_MOVED -- # object, that object should be pushed on the mark stack, and will -- # make a SEGV. -- def self.verify_compaction_references(toward: nil, double_heap: false) -- Primitive.gc_verify_compaction_references(double_heap, toward == :empty) -- end -- - # call-seq: - # GC.using_rvargc? -> true or false - # diff --git a/ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch b/ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch index 240cc9c..654c54c 100644 --- a/ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch +++ b/ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch @@ -1,5 +1,5 @@ ---- ruby-3.1.2/gc.rbinc 2022-04-12 13:11:17.000000000 +0200 -+++ ruby/gc.rbinc 2022-06-08 12:49:16.288024971 +0200 +--- ruby-3.1.3/gc.rbinc 2022-11-24 11:20:33.000000000 +0100 ++++ ruby/gc.rbinc 2022-11-25 11:50:19.939820992 +0100 @@ -9,27 +9,27 @@ #include "builtin.h" /* for RB_BUILTIN_FUNCTION */ struct rb_execution_context_struct; /* in vm_core.h */ @@ -218,8 +218,8 @@ COMPILER_WARNING_POP // load ---- ruby-3.1.2/miniprelude.c 2022-04-12 13:11:17.000000000 +0200 -+++ ruby/miniprelude.c 2022-06-08 12:49:16.377024871 +0200 +--- ruby-3.1.3/miniprelude.c 2022-11-24 11:20:33.000000000 +0100 ++++ ruby/miniprelude.c 2022-11-25 11:50:20.012820803 +0100 @@ -545,11 +545,10 @@ static const char prelude_name2[] = ""; @@ -446,57 +446,57 @@ }; static const char prelude_name11[] = ""; -@@ -3305,7 +3234,7 @@ +@@ -3309,7 +3238,7 @@ " }\n" " end\n" "end\n" --#line 3309 "miniprelude.c" -+#line 3238 "miniprelude.c" +-#line 3313 "miniprelude.c" ++#line 3242 "miniprelude.c" }; static const char prelude_name12[] = ""; -@@ -3628,7 +3557,7 @@ +@@ -3632,7 +3561,7 @@ " Primitive.time_init_args(year, mon, mday, hour, min, sec, zone)\n" " end\n" "end\n" --#line 3632 "miniprelude.c" -+#line 3561 "miniprelude.c" +-#line 3636 "miniprelude.c" ++#line 3565 "miniprelude.c" }; static const char prelude_name13[] = ""; -@@ -3661,7 +3590,7 @@ +@@ -3665,7 +3594,7 @@ " return 0.0\n" " end\n" "end\n" --#line 3665 "miniprelude.c" -+#line 3594 "miniprelude.c" +-#line 3669 "miniprelude.c" ++#line 3598 "miniprelude.c" }; static const char prelude_name14[] = ""; -@@ -3691,7 +3620,7 @@ +@@ -3695,7 +3624,7 @@ "\n" " private :pp\n" "end\n" --#line 3695 "miniprelude.c" -+#line 3624 "miniprelude.c" +-#line 3699 "miniprelude.c" ++#line 3628 "miniprelude.c" }; static const char prelude_name15[] = ""; -@@ -3718,7 +3647,7 @@ +@@ -3722,7 +3651,7 @@ "rescue LoadError\n" " warn \"`did_you_mean' was not loaded.\"\n" "end if defined?(DidYouMean)\n" --#line 3722 "miniprelude.c" -+#line 3651 "miniprelude.c" +-#line 3726 "miniprelude.c" ++#line 3655 "miniprelude.c" }; static const char prelude_name16[] = ""; -@@ -4059,7 +3988,7 @@ +@@ -4063,7 +3992,7 @@ " end\n" " end\n" "end\n" --#line 4063 "miniprelude.c" -+#line 3992 "miniprelude.c" +-#line 4067 "miniprelude.c" ++#line 3996 "miniprelude.c" }; COMPILER_WARNING_POP diff --git a/ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch b/ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch deleted file mode 100644 index 73f9a02..0000000 --- a/ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch +++ /dev/null @@ -1,27 +0,0 @@ -From dae843f6b7502f921a7e66f39e3714a39d860181 Mon Sep 17 00:00:00 2001 -From: Hiroshi SHIBATA -Date: Wed, 19 Oct 2022 19:40:00 +0900 -Subject: [PATCH] Bypass git submodule add/update with git config - protocol.file.allow=always option. - -Co-authored-by: Nobuyoshi Nakada ---- - test/rubygems/test_gem_source_git.rb | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/test/rubygems/test_gem_source_git.rb b/test/rubygems/test_gem_source_git.rb -index 5702da05974b6..c3b324771fa4d 100644 ---- a/test/rubygems/test_gem_source_git.rb -+++ b/test/rubygems/test_gem_source_git.rb -@@ -63,6 +63,11 @@ def test_checkout_local_cached - end - - def test_checkout_submodules -+ # We need to allow to checkout submodules with file:// protocol -+ # CVE-2022-39253 -+ # https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/ -+ system(@git, *%W"config --global protocol.file.allow always") -+ - source = Gem::Source::Git.new @name, @repository, 'master', true - - git_gem 'b' diff --git a/ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch b/ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch deleted file mode 100644 index b208537..0000000 --- a/ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch +++ /dev/null @@ -1,31 +0,0 @@ -From bfa2f72cfa3bfde34049d26dcb24976316074ad7 Mon Sep 17 00:00:00 2001 -From: Jun Aruga -Date: Mon, 21 Mar 2022 15:36:51 +0100 -Subject: [PATCH] Fix a test for `bin/bundle update --bundler` to pass on - ruby/ruby. - -Consider the case that the latest Bundler version on RubyGems is higher than -the `system_bundler_version` (= `Bundler::VERSION`) in `make test-bundler` on -ruby/ruby. - -See . ---- - spec/bundler/commands/binstubs_spec.rb | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/spec/bundler/commands/binstubs_spec.rb b/spec/bundler/commands/binstubs_spec.rb -index 198226207bc..2634f43417c 100644 ---- a/spec/bundler/commands/binstubs_spec.rb -+++ b/spec/bundler/commands/binstubs_spec.rb -@@ -226,7 +226,10 @@ - - it "calls through to the latest bundler version" do - sys_exec "bin/bundle update --bundler", :env => { "DEBUG" => "1" } -- expect(out).to include %(Using bundler #{system_bundler_version}\n) -+ using_bundler_line = /Using bundler ([\w\.]+)\n/.match(out) -+ expect(using_bundler_line).to_not be_nil -+ latest_version = using_bundler_line[1] -+ expect(Gem::Version.new(latest_version)).to be >= Gem::Version.new(system_bundler_version) - end - - it "calls through to the explicit bundler version" do diff --git a/ruby-irb-1.4.1-set-rdoc-soft-dep.patch b/ruby-irb-1.4.1-set-rdoc-soft-dep.patch index 0156fe0..db8aba7 100644 --- a/ruby-irb-1.4.1-set-rdoc-soft-dep.patch +++ b/ruby-irb-1.4.1-set-rdoc-soft-dep.patch @@ -13,12 +13,6 @@ lib/irb/completion.rb lib/irb/easter-egg.rb lib/irb/input-method.rb ``` - ---- - -Revert "Remove `require` in signal handler to avoid ThreadError" - -This reverts commit 5f749c613c895cf1b11b5e4cbd1205363bc58028. --- lib/irb/input-method.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.patch b/ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.patch deleted file mode 100644 index 66c3382..0000000 --- a/ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 623162ad2bb3b589bddcc32616492a2bc4651726 Mon Sep 17 00:00:00 2001 -From: Hiroshi SHIBATA -Date: Tue, 22 Feb 2022 11:58:54 +0900 -Subject: [PATCH] Resolve cleaned-up error with temporary gemhome - ---- - test/rubygems/test_gem_commands_setup_command.rb | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/test/rubygems/test_gem_commands_setup_command.rb b/test/rubygems/test_gem_commands_setup_command.rb -index 5cf94a1dc99..934c76b1d1a 100644 ---- a/test/rubygems/test_gem_commands_setup_command.rb -+++ b/test/rubygems/test_gem_commands_setup_command.rb -@@ -274,6 +274,8 @@ def test_install_default_bundler_gem_with_destdir_flag - spec.executables.each do |e| - assert_path_exist File.join destdir, @gemhome.gsub(/^[a-zA-Z]:/, ''), 'gems', spec.full_name, spec.bindir, e - end -+ ensure -+ FileUtils.chmod "+w", @gemhome - end - - def test_install_default_bundler_gem_with_destdir_and_prefix_flags diff --git a/ruby-spec-Fix-tests-on-tzdata-2022b.patch b/ruby-spec-Fix-tests-on-tzdata-2022b.patch deleted file mode 100644 index 19386d9..0000000 --- a/ruby-spec-Fix-tests-on-tzdata-2022b.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 7e9ec8a20b0f7469b415283d2ec0c22087f8eb2b Mon Sep 17 00:00:00 2001 -From: Jun Aruga -Date: Wed, 24 Aug 2022 12:02:56 +0200 -Subject: [PATCH] Fix tests with Europe/Amsterdam pre-1970 time on tzdata - version 2022b. - -The Time Zone Database (tzdata) changed the pre-1970 timestamps in some zones -including Europe/Amsterdam on tzdata version 2022b or later. -See . - -The tzdata RPM package maintainer on Fedora project suggested changing the Ruby -test, because the change is intentional. -See . - -We use post-1970 time test data to simplify the test. ---- - core/time/shared/local.rb | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/spec/ruby/core/time/shared/local.rb b/spec/ruby/core/time/shared/local.rb -index 43f331c4c..c4aa7a7ea 100644 ---- a/spec/ruby/core/time/shared/local.rb -+++ b/spec/ruby/core/time/shared/local.rb -@@ -8,10 +8,10 @@ describe :time_local, shared: true do - - platform_is_not :windows do - describe "timezone changes" do -- it "correctly adjusts the timezone change to 'CEST' on 'Europe/Amsterdam'" do -+ it "correctly adjusts the timezone change to 'CET' on 'Europe/Amsterdam'" do - with_timezone("Europe/Amsterdam") do -- Time.send(@method, 1940, 5, 16).to_a.should == -- [0, 40, 1, 16, 5, 1940, 4, 137, true, "CEST"] -+ Time.send(@method, 1970, 5, 16).to_a.should == -+ [0, 0, 0, 16, 5, 1970, 6, 136, false, "CET"] - end - end - end --- -2.36.1 - diff --git a/ruby.spec b/ruby.spec index 3375cc6..1506817 100644 --- a/ruby.spec +++ b/ruby.spec @@ -1,6 +1,6 @@ %global major_version 3 %global minor_version 1 -%global teeny_version 2 +%global teeny_version 3 %global major_minor_version %{major_version}.%{minor_version} %global ruby_version %{major_minor_version}.%{teeny_version} @@ -22,7 +22,7 @@ %endif -%global release 171 +%global release 172 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -30,14 +30,16 @@ %global rubygems_dir %{_datadir}/rubygems # Bundled libraries versions -%global rubygems_version 3.3.7 +%global rubygems_version 3.3.26 %global rubygems_molinillo_version 0.7.0 +%global rubygems_optparse_version 0.2.0 +%global rubygems_tsort_version 0.1.0 # Default gems. -%global bundler_version 2.3.7 +%global bundler_version 2.3.26 %global bundler_connection_pool_version 2.3.0 %global bundler_fileutils_version 1.4.1 -%global bundler_molinillo_version 0.7.0 +%global bundler_molinillo_version 0.8.0 %global bundler_net_http_persistent_version 4.0.0 %global bundler_thor_version 1.2.1 %global bundler_tmpdir_version 0.1.0 @@ -51,8 +53,8 @@ %global io_console_version 0.5.11 %global irb_version 1.4.1 %global json_version 2.6.1 -%global openssl_version 3.0.0 -%global psych_version 4.0.3 +%global openssl_version 3.0.1 +%global psych_version 4.0.4 %global racc_version 1.6.0 %global rdoc_version 6.4.0 %global stringio_version 3.0.1 @@ -70,9 +72,9 @@ %global net_smtp_version 0.3.1 %global matrix_version 0.4.2 %global prime_version 0.1.2 -%global rbs_version 2.1.0 -%global typeprof_version 0.21.2 -%global debug_version 1.4.0 +%global rbs_version 2.7.0 +%global typeprof_version 0.21.3 +%global debug_version 1.6.3 %global tapset_libdir %(echo %{_libdir} | sed 's/64//')* @@ -163,54 +165,33 @@ Patch7: ruby-3.1.0-Don-t-query-RubyVM-FrozenCore-for-class-path.patch # Avoid possible timeout errors in TestBugReporter#test_bug_reporter_add. # https://bugs.ruby-lang.org/issues/16492 Patch19: ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch -# Fix a test for `bin/bundle update --bundler` in `make test-bundler`. -# https://bugs.ruby-lang.org/issues/18643 -# https://github.com/rubygems/rubygems/commit/bfa2f72cfa3bfde34049d26dcb24976316074ad7 -Patch20: ruby-bundler-2.4.0-bundle-update-bundler-test-in-ruby.patch -# Workaround gem binary extensions build and installation issues. -# https://bugs.ruby-lang.org/issues/18373 -# https://github.com/ruby/ruby/pull/5774 -Patch21: ruby-3.2.0-Build-extension-libraries-in-bundled-gems.patch # If GC compaction is not supported on platform, define the # corresponding GC methods as not implemented. # https://bugs.ruby-lang.org/issues/18779 # https://github.com/ruby/ruby/pull/5934 Patch22: ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch # To regenerate the patch you need to have ruby, autoconf, xz, tar and make installed: -# tar -Jxvf ./ruby-3.1.2.tar.xz +# tar -Jxvf ./ruby-3.1.3.tar.xz # git clone https://github.com/ruby/ruby.git -# cd ruby && git checkout v3_1_2 +# cd ruby && git checkout v3_1_3 # patch -p1 < ../ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch # ./autogen.sh && ./configure # make gc.rbinc miniprelude.c # cd .. -# diff -u {ruby-3.1.2,ruby}/gc.rbinc > ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch -# diff -u {ruby-3.1.2,ruby}/miniprelude.c >> ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch +# diff -u {ruby-3.1.3,ruby}/gc.rbinc > ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch +# diff -u {ruby-3.1.3,ruby}/miniprelude.c >> ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch Patch23: ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch # Define the GC compaction support macro at run time. # https://bugs.ruby-lang.org/issues/18829 # https://github.com/ruby/ruby/pull/6019 # https://github.com/ruby/ruby/commit/2c190863239bee3f54cfb74b16bb6ea4cae6ed20 Patch24: ruby-3.2.0-Detect-compaction-support-during-runtime.patch -# RPM 4.18.0-beta1 or later versions remove the build directory automatically -# on successful build, the build then fails on removing temporary directories -# that are missing the 'w' bit. -# https://bugzilla.redhat.com/show_bug.cgi?id=2105393 -# https://github.com/rpm-software-management/rpm/pull/2080 -# https://github.com/rubygems/rubygems/pull/5372 -Patch25: ruby-rubygems-3.3.8-Resolve-cleaned-up-error-with-temporary-gemhome.patch -# Fix tests with Europe/Amsterdam pre-1970 time on tzdata version 2022b. -# https://github.com/ruby/spec/pull/939 -Patch26: ruby-spec-Fix-tests-on-tzdata-2022b.patch # Drop hard dependency on RDoc in IRB. # https://github.com/ruby/irb/pull/393 Patch27: ruby-irb-1.4.1-drop-rdoc-hard-dep.patch # Set soft dependency on RDoc in input-method.rb in IRB. # https://github.com/ruby/irb/pull/395 Patch28: ruby-irb-1.4.1-set-rdoc-soft-dep.patch -# Bypass git submodule test failure on Git >= 2.38.1. -# https://github.com/ruby/ruby/pull/6587 -Patch29: ruby-3.2.0-git-2.38.1-fix-rubygems-test.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} Suggests: rubypick @@ -678,22 +659,11 @@ rm -rf ext/fiddle/libffi* %patch6 -p1 %patch7 -p1 %patch19 -p1 -%patch20 -p1 - -# Once the upstream tarball contains the files on the right place, this code -# won't be necessary. This should happen at the same moment when the patch21 -# is not needed anymore. -mkdir .bundle/specifications -find .bundle/gems -name '*-[0-9]*.gemspec' -exec cp -t .bundle/specifications/ {} + -%patch21 -p1 %patch22 -p1 %patch23 -p1 %patch24 -p1 -%patch25 -p1 -%patch26 -p1 %patch27 -p1 %patch28 -p1 -%patch29 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -910,6 +880,21 @@ checksec --file=libruby.so.%{ruby_version} | \ puts Gem::Resolver::Molinillo::VERSION\\\"\" | tail -1`" \ == '%{rubygems_molinillo_version}' ] +# OptParse. +make runruby TESTRUN_SCRIPT="-e \" \ + module Gem; end; \ + require 'rubygems/optparse/lib/optparse'; \ + puts '%%{rubygems_optparse_version}: %{rubygems_optparse_version}'; \ + puts %Q[Gem::OptionParser::Version: #{Gem::OptionParser::Version}]; \ + exit 1 if Gem::OptionParser::Version != '%{rubygems_optparse_version}'; \ +\"" + +# tsort +# TODO: Provide some real version test if version is available. +make runruby TESTRUN_SCRIPT="-e \" \ + module Gem; end;\ + require 'rubygems/tsort/lib/tsort'\"" + # Check Bundler bundled dependencies versions. # connection_pool. @@ -981,9 +966,6 @@ MSPECOPTS="" # Avoid `hostname' dependency. %{!?with_hostname:MSPECOPTS="-P 'Socket.gethostname returns the host name'"} -# https://bugs.ruby-lang.org/issues/18380 -DISABLE_TESTS="$DISABLE_TESTS -n !/TestAddressResolve#test_socket_getnameinfo_domain_blocking/" - %ifarch armv7hl # TestReadline#test_interrupt_in_other_thread fails on 32 bit arches according # to upstream, but the test is disabled just on Travis, not in test suite. @@ -1255,8 +1237,8 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" %{gem_dir}/specifications/default/abbrev-0.1.0.gemspec %{gem_dir}/specifications/default/base64-0.1.1.gemspec %{gem_dir}/specifications/default/benchmark-0.2.0.gemspec -%{gem_dir}/specifications/default/cgi-0.3.1.gemspec -%{gem_dir}/specifications/default/csv-3.2.2.gemspec +%{gem_dir}/specifications/default/cgi-0.3.5.gemspec +%{gem_dir}/specifications/default/csv-3.2.5.gemspec %{gem_dir}/specifications/default/date-3.2.2.gemspec %{gem_dir}/specifications/default/delegate-0.2.0.gemspec %{gem_dir}/specifications/default/did_you_mean-%{did_you_mean_version}.gemspec @@ -1277,7 +1259,7 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" %{gem_dir}/specifications/default/ipaddr-1.2.4.gemspec %{gem_dir}/specifications/default/logger-1.5.0.gemspec %{gem_dir}/specifications/default/mutex_m-0.1.1.gemspec -%{gem_dir}/specifications/default/net-http-0.2.0.gemspec +%{gem_dir}/specifications/default/net-http-0.3.0.gemspec %{gem_dir}/specifications/default/net-protocol-0.1.2.gemspec %{gem_dir}/specifications/default/nkf-0.1.1.gemspec %{gem_dir}/specifications/default/observer-0.1.1.gemspec @@ -1293,12 +1275,12 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" %{gem_dir}/specifications/default/racc-%{racc_version}.gemspec %{gem_dir}/specifications/default/readline-0.0.3.gemspec %{gem_dir}/specifications/default/readline-ext-0.1.4.gemspec -%{gem_dir}/specifications/default/reline-0.3.0.gemspec +%{gem_dir}/specifications/default/reline-0.3.1.gemspec %{gem_dir}/specifications/default/resolv-0.2.1.gemspec %{gem_dir}/specifications/default/resolv-replace-0.1.0.gemspec %{gem_dir}/specifications/default/rinda-0.1.1.gemspec %{gem_dir}/specifications/default/ruby2_keywords-0.0.5.gemspec -%{gem_dir}/specifications/default/securerandom-0.1.1.gemspec +%{gem_dir}/specifications/default/securerandom-0.2.0.gemspec %{gem_dir}/specifications/default/set-1.0.2.gemspec %{gem_dir}/specifications/default/shellwords-0.1.0.gemspec %{gem_dir}/specifications/default/singleton-0.1.1.gemspec @@ -1397,7 +1379,6 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" %doc %{gem_dir}/gems/debug-%{debug_version}/README.md %{gem_dir}/gems/debug-%{debug_version}/Rakefile %doc %{gem_dir}/gems/debug-%{debug_version}/TODO.md -%{gem_dir}/gems/debug-%{debug_version}/bin %{gem_dir}/gems/debug-%{debug_version}/exe %{gem_dir}/gems/debug-%{debug_version}/lib %{gem_dir}/gems/debug-%{debug_version}/misc @@ -1488,7 +1469,7 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" %license %{gem_dir}/gems/rbs-%{rbs_version}/BSDL %doc %{gem_dir}/gems/rbs-%{rbs_version}/CHANGELOG.md %license %{gem_dir}/gems/rbs-%{rbs_version}/COPYING -%{gem_dir}/gems/rbs-%{rbs_version}/Gemfile +%{gem_dir}/gems/rbs-%{rbs_version}/Gemfile* %doc %{gem_dir}/gems/rbs-%{rbs_version}/README.md %{gem_dir}/gems/rbs-%{rbs_version}/Rakefile %{gem_dir}/gems/rbs-%{rbs_version}/Steepfile @@ -1545,7 +1526,6 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" %{gem_dir}/gems/typeprof-%{typeprof_version}/lib %doc %{gem_dir}/gems/typeprof-%{typeprof_version}/tools %exclude %{gem_dir}/gems/typeprof-%{typeprof_version}/typeprof-lsp -%exclude %{gem_dir}/gems/typeprof-%{typeprof_version}/vscode %{gem_dir}/specifications/typeprof-%{typeprof_version}.gemspec %doc %{gem_dir}/gems/typeprof-%{typeprof_version}/Gemfile* %doc %{gem_dir}/gems/typeprof-%{typeprof_version}/README.md @@ -1553,6 +1533,9 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" %changelog +* Thu Nov 24 2022 Vít Ondruch - 3.1.3-172 +- Upgrade to Ruby 3.1.3. + * Tue Nov 22 2022 Vít Ondruch - 3.1.2-171 - Re-disable package notes. It causes additional issues with installing binary gems. diff --git a/sources b/sources index 9cefc8d..9896d56 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (ruby-3.1.2.tar.xz) = 4a74e9efc6ea4b3eff4fec7534eb1fff4794d021531defc2e9937e53c6668db8ecdc0fff2bc23d5e6602d0df344a2caa85b31c5414309541e3d5313ec82b6e21 +SHA512 (ruby-3.1.3.tar.xz) = 4b0fd334ae56132ba98b8a69adad54bdcf7f7aeabd5eba5b0f0399a3868e2054f9026ca1b1cb2dbb197a9e9b0610b263481949c0623a62071546bc5adff8ca69 From 9819174c8dd5a04f7cc47d50d586cc6f72b8f0b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Fri, 16 Sep 2022 17:09:27 +0200 Subject: [PATCH 053/141] Use --enable-mkmf-verbose configuration opiton instead of patch. https://github.com/ruby/ruby/pull/5879 --- ruby-1.9.3-mkmf-verbose.patch | 25 ------------------------- ruby.spec | 4 +--- 2 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 ruby-1.9.3-mkmf-verbose.patch diff --git a/ruby-1.9.3-mkmf-verbose.patch b/ruby-1.9.3-mkmf-verbose.patch deleted file mode 100644 index 03128be..0000000 --- a/ruby-1.9.3-mkmf-verbose.patch +++ /dev/null @@ -1,25 +0,0 @@ -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 -@@ -1971,7 +1971,7 @@ def configuration(srcdir) - SHELL = /bin/sh - - # V=0 quiet, V=1 verbose. other values don't work. --V = #{CONFIG['MKMF_VERBOSE']} -+V = 1 - V0 = $(V:0=) - Q1 = $(V:1=) - Q = $(Q1:0=@) --- -1.8.3.1 - diff --git a/ruby.spec b/ruby.spec index 1506817..2d281d5 100644 --- a/ruby.spec +++ b/ruby.spec @@ -145,8 +145,6 @@ 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 # The ABRT hook used to be initialized by preludes via following patches: # https://bugs.ruby-lang.org/issues/8566 # https://bugs.ruby-lang.org/issues/15306 @@ -655,7 +653,6 @@ rm -rf ext/fiddle/libffi* %patch2 -p1 %patch3 -p1 %patch4 -p1 -%patch5 -p1 %patch6 -p1 %patch7 -p1 %patch19 -p1 @@ -687,6 +684,7 @@ autoconf --with-ruby-pc='%{name}.pc' \ --with-compress-debug-sections=no \ --disable-rpath \ + --enable-mkmf-verbose \ --enable-shared \ --with-ruby-version='' \ --enable-multiarch \ From 2cdb051166374685a8ebc07eb40a1e1f1d08a1c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Thu, 8 Dec 2022 18:05:18 +0100 Subject: [PATCH 054/141] Disable MJIT test cases on i686 due to issues with PCH. --- ruby.spec | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ruby.spec b/ruby.spec index 2d281d5..39a615a 100644 --- a/ruby.spec +++ b/ruby.spec @@ -22,7 +22,7 @@ %endif -%global release 172 +%global release 173 %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} # The RubyGems library has to stay out of Ruby directory tree, since the @@ -979,6 +979,13 @@ mv test/fiddle/test_closure.rb{,.disable} DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunc#test_qsort1/" DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" +%ifarch i686 +# The MJIT test cases are failing so often, that it is recently impossible +# to get past the test cases :/ +# https://bugzilla.redhat.com/show_bug.cgi?id=2125026 +mv test/ruby/test_jit.rb{,.disable} || : +%endif + # Give an option to increase the timeout in tests. # https://bugs.ruby-lang.org/issues/16921 %{?test_timeout_scale:RUBY_TEST_TIMEOUT_SCALE="%{test_timeout_scale}"} \ @@ -1531,6 +1538,9 @@ DISABLE_TESTS="$DISABLE_TESTS -n !/Fiddle::TestFunction#test_argument_count/" %changelog +* Thu Dec 08 2022 Vít Ondruch - 3.1.3-173 +- Disable MJIT test cases on i686 due to issues with PCH. + * Thu Nov 24 2022 Vít Ondruch - 3.1.3-172 - Upgrade to Ruby 3.1.3. From b1748af87f120b62540c7fd04c0e926dbaf1efd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ondruch?= Date: Thu, 8 Dec 2022 13:12:40 +0100 Subject: [PATCH 055/141] Fix CGI causing issue with leading '.' in domain names. The original issue broke rubygem-actionpack: https://github.com/rails/rails/issues/46578 https://github.com/rails/rails/pull/46595 rubygem-rack: https://github.com/rack/rack/pull/1988 And rack-test (where I have not checked details). --- ...t_cgi_cookie_new_with_domain-to-pass.patch | 38 ++++++++++++++++ ...gi-Loosen-the-domain-regex-to-accept.patch | 44 +++++++++++++++++++ ruby.spec | 10 +++++ 3 files changed, 92 insertions(+) create mode 100644 ruby-3.2.0-ruby-cgi-Fix-test_cgi_cookie_new_with_domain-to-pass.patch create mode 100644 ruby-3.2.0-ruby-cgi-Loosen-the-domain-regex-to-accept.patch diff --git a/ruby-3.2.0-ruby-cgi-Fix-test_cgi_cookie_new_with_domain-to-pass.patch b/ruby-3.2.0-ruby-cgi-Fix-test_cgi_cookie_new_with_domain-to-pass.patch new file mode 100644 index 0000000..21579c5 --- /dev/null +++ b/ruby-3.2.0-ruby-cgi-Fix-test_cgi_cookie_new_with_domain-to-pass.patch @@ -0,0 +1,38 @@ +From 656f25987cf2885104d5b13c8d3f5b7d32f1b333 Mon Sep 17 00:00:00 2001 +From: Jean Boussier +Date: Wed, 23 Nov 2022 12:10:36 +0100 +Subject: [PATCH] [ruby/cgi] Fix test_cgi_cookie_new_with_domain to pass on + older rubies + +https://github.com/ruby/cgi/commit/05f0c58048 +--- + test/cgi/test_cgi_cookie.rb | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/test/cgi/test_cgi_cookie.rb b/test/cgi/test_cgi_cookie.rb +index e3ec4bea5286..6d31932d321a 100644 +--- a/test/cgi/test_cgi_cookie.rb ++++ b/test/cgi/test_cgi_cookie.rb +@@ -62,18 +62,18 @@ def test_cgi_cookie_new_complex + + def test_cgi_cookie_new_with_domain + h = {'name'=>'name1', 'value'=>'value1'} +- cookie = CGI::Cookie.new('domain'=>'a.example.com', **h) ++ cookie = CGI::Cookie.new(h.merge('domain'=>'a.example.com')) + assert_equal('a.example.com', cookie.domain) + +- cookie = CGI::Cookie.new('domain'=>'1.example.com', **h) ++ cookie = CGI::Cookie.new(h.merge('domain'=>'1.example.com')) + assert_equal('1.example.com', cookie.domain, 'enhanced by RFC 1123') + + assert_raise(ArgumentError) { +- CGI::Cookie.new('domain'=>'-a.example.com', **h) ++ CGI::Cookie.new(h.merge('domain'=>'-a.example.com')) + } + + assert_raise(ArgumentError) { +- CGI::Cookie.new('domain'=>'a-.example.com', **h) ++ CGI::Cookie.new(h.merge('domain'=>'a-.example.com')) + } + end + diff --git a/ruby-3.2.0-ruby-cgi-Loosen-the-domain-regex-to-accept.patch b/ruby-3.2.0-ruby-cgi-Loosen-the-domain-regex-to-accept.patch new file mode 100644 index 0000000..f217281 --- /dev/null +++ b/ruby-3.2.0-ruby-cgi-Loosen-the-domain-regex-to-accept.patch @@ -0,0 +1,44 @@ +From 745dcf5326ea2c8e2047a3bddeb0fbb7e7d07649 Mon Sep 17 00:00:00 2001 +From: Xenor Chang +Date: Mon, 28 Nov 2022 12:34:06 +0800 +Subject: [PATCH] [ruby/cgi] Loosen the domain regex to accept '.' + (https://github.com/ruby/cgi/pull/29) + +* Loosen the domain regex to accept '.' + +Co-authored-by: Nobuyoshi Nakada + +https://github.com/ruby/cgi/commit/5e09d632f3 +Co-authored-by: Hiroshi SHIBATA +--- + lib/cgi/cookie.rb | 2 +- + test/cgi/test_cgi_cookie.rb | 3 +++ + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb +index 1a9c1a82c123..9498e2f9faf9 100644 +--- a/lib/cgi/cookie.rb ++++ b/lib/cgi/cookie.rb +@@ -42,7 +42,7 @@ class Cookie < Array + + TOKEN_RE = %r"\A[[!-~]&&[^()<>@,;:\\\"/?=\[\]{}]]+\z" + PATH_VALUE_RE = %r"\A[[ -~]&&[^;]]*\z" +- DOMAIN_VALUE_RE = %r"\A(?