From 26e6c300798fe37b98e05fd3dd0f8afdda18649c Mon Sep 17 00:00:00 2001 From: James Antill Date: Mon, 20 Feb 2023 02:14:24 -0500 Subject: [PATCH] Import rpm: 6841a2fe4f7da03f9b322844763f4ef60d27dcb5 --- .gitignore | 1 + .gitlab/merge_request_templates/default.md | 41 + gating.yaml | 6 + libruby.stp | 303 ++ macros.ruby | 22 + macros.rubygems | 186 ++ operating_system.rb | 148 + ruby-1.9.3-mkmf-verbose.patch | 25 + ...0-Enable-configuration-of-archlibdir.patch | 28 + ...ed-paths-when-empty-version-string-i.patch | 80 + ruby-2.1.0-always-use-i386.patch | 25 + ruby-2.1.0-custom-rubygems-location.patch | 97 + ruby-2.3.0-ruby_version.patch | 288 ++ ruby-2.7.0-Initialize-ABRT-hook.patch | 77 + ..._bug_reporter_add-witout-raising-err.patch | 34 + ...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 + ...ery-RubyVM-FrozenCore-for-class-path.patch | 43 + ...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 +++++++ ...-for-allocating-heap-pages-in-the-GC.patch | 359 +++ ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch | 29 + ...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-3.1.1-ossl_ocsp-use-null.patch | 31 + ruby-3.1.2-ossl-tests-replace-sha1.patch | 647 ++++ ruby-exercise.stp | 39 + ruby.rpmlintrc | 56 + ruby.spec | 2851 +++++++++++++++++ ...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 + rubygems.attr | 6 + rubygems.con | 52 + rubygems.prov | 36 + rubygems.req | 88 + sources | 1 + test_abrt.rb | 7 + test_systemtap.rb | 65 + 56 files changed, 16412 insertions(+) create mode 100644 .gitignore create mode 100644 .gitlab/merge_request_templates/default.md create mode 100644 gating.yaml create mode 100644 libruby.stp create mode 100644 macros.ruby create mode 100644 macros.rubygems create mode 100644 operating_system.rb create mode 100644 ruby-1.9.3-mkmf-verbose.patch create mode 100644 ruby-2.1.0-Enable-configuration-of-archlibdir.patch create mode 100644 ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch create mode 100644 ruby-2.1.0-always-use-i386.patch create mode 100644 ruby-2.1.0-custom-rubygems-location.patch create mode 100644 ruby-2.3.0-ruby_version.patch create mode 100644 ruby-2.7.0-Initialize-ABRT-hook.patch create mode 100644 ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch create mode 100644 ruby-3.0.3-ext-openssl-extconf.rb-require-OpenSSL-version-1.0.1.patch create mode 100644 ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch create mode 100644 ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.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-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-Don-t-query-RubyVM-FrozenCore-for-class-path.patch 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-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.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 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-Support-GCCs-DWARF-5.patch create mode 100644 ruby-3.1.0-Use-EVP-API-in-more-places.patch create mode 100644 ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.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-Use-mmap-for-allocating-heap-pages-in-the-GC.patch create mode 100644 ruby-3.1.0-addr2line-DW_FORM_ref_addr.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 ruby-3.1.1-ossl_ocsp-use-null.patch create mode 100644 ruby-3.1.2-ossl-tests-replace-sha1.patch create mode 100644 ruby-exercise.stp create mode 100644 ruby.rpmlintrc create mode 100644 ruby.spec create mode 100644 rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch create mode 100644 rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch create mode 100644 rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch create mode 100644 rubygems.attr create mode 100644 rubygems.con create mode 100644 rubygems.prov create mode 100644 rubygems.req create mode 100644 sources create mode 100644 test_abrt.rb create mode 100644 test_systemtap.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a915dc1 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/ruby-3.0.4.tar.xz diff --git a/.gitlab/merge_request_templates/default.md b/.gitlab/merge_request_templates/default.md new file mode 100644 index 0000000..25f37cc --- /dev/null +++ b/.gitlab/merge_request_templates/default.md @@ -0,0 +1,41 @@ + + +# Merge Request Required Information + +## Summary of Changes + +**Context of the pull-request:** + + + +**Pull-request or commit in Fedora Rawhide:** + + + +**Select priority:** + +* [ ] urgent +* [ ] high +* [ ] medium +* [ ] low +* [ ] unspecified + +**Do you need someone's review?:** + +* [x] Yes + +* [ ] No, because: + +## Approved Bugzilla Ticket +All submissions to CentOS Stream are required to have an approved [Red Hat Bugzilla](https://bugzilla.redhat.com/) ticket in a commit message, except only changing dot or yaml files. Please follow the CentOS Stream [contribution documentation](https://docs.centos.org/en-US/stream-contrib/quickstart/). diff --git a/gating.yaml b/gating.yaml new file mode 100644 index 0000000..c190bde --- /dev/null +++ b/gating.yaml @@ -0,0 +1,6 @@ +--- !Policy +product_versions: + - rhel-9 +decision_context: osci_compose_gate +rules: + - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tier1.functional} diff --git a/libruby.stp b/libruby.stp new file mode 100644 index 0000000..098b39d --- /dev/null +++ b/libruby.stp @@ -0,0 +1,303 @@ +/* SystemTap tapset to make it easier to trace Ruby 2.0 + * + * All probes provided by Ruby can be listed using following command + * (the path to the library must be adjuste appropriately): + * + * stap -L 'process("@LIBRARY_PATH@").mark("*")' + */ + +/** + * probe ruby.array.create - Allocation of new array. + * + * @size: Number of elements (an int) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.array.create = + process("@LIBRARY_PATH@").mark("array__create") +{ + size = $arg1 + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.cmethod.entry - Fired just before a method implemented in C is entered. + * + * @classname: Name of the class (string) + * @methodname: The method about bo be executed (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.cmethod.entry = + process("@LIBRARY_PATH@").mark("cmethod__entry") +{ + classname = user_string($arg1) + methodname = user_string($arg2) + file = user_string($arg3) + line = $arg4 +} + +/** + * probe ruby.cmethod.return - Fired just after a method implemented in C has returned. + * + * @classname: Name of the class (string) + * @methodname: The executed method (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.cmethod.return = + process("@LIBRARY_PATH@").mark("cmethod__return") +{ + classname = user_string($arg1) + methodname = user_string($arg2) + file = user_string($arg3) + line = $arg4 +} + +/** + * probe ruby.find.require.entry - Fired when require starts to search load + * path for suitable file to require. + * + * @requiredfile: The name of the file to be required (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.find.require.entry = + process("@LIBRARY_PATH@").mark("find__require__entry") +{ + requiredfile = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.find.require.return - Fired just after require has finished + * search of load path for suitable file to require. + * + * @requiredfile: The name of the file to be required (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.find.require.return = + process("@LIBRARY_PATH@").mark("find__require__return") +{ + requiredfile = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.gc.mark.begin - Fired when a GC mark phase is about to start. + * + * It takes no arguments. + */ +probe ruby.gc.mark.begin = + process("@LIBRARY_PATH@").mark("gc__mark__begin") +{ +} + +/** + * probe ruby.gc.mark.end - Fired when a GC mark phase has ended. + * + * It takes no arguments. + */ +probe ruby.gc.mark.end = + process("@LIBRARY_PATH@").mark("gc__mark__end") +{ +} + +/** + * probe ruby.gc.sweep.begin - Fired when a GC sweep phase is about to start. + * + * It takes no arguments. + */ +probe ruby.gc.sweep.begin = + process("@LIBRARY_PATH@").mark("gc__sweep__begin") +{ +} + +/** + * probe ruby.gc.sweep.end - Fired when a GC sweep phase has ended. + * + * It takes no arguments. + */ +probe ruby.gc.sweep.end = + process("@LIBRARY_PATH@").mark("gc__sweep__end") +{ +} + +/** + * probe ruby.hash.create - Allocation of new hash. + * + * @size: Number of elements (int) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.hash.create = + process("@LIBRARY_PATH@").mark("hash__create") +{ + size = $arg1 + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.load.entry - Fired when calls to "load" are made. + * + * @loadedfile: The name of the file to be loaded (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.load.entry = + process("@LIBRARY_PATH@").mark("load__entry") +{ + loadedfile = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.load.return - Fired just after require has finished + * search of load path for suitable file to require. + * + * @loadedfile: The name of the file that was loaded (string) + */ +probe ruby.load.return = + process("@LIBRARY_PATH@").mark("load__return") +{ + loadedfile = user_string($arg1) +} + +/** + * probe ruby.method.entry - Fired just before a method implemented in Ruby is entered. + * + * @classname: Name of the class (string) + * @methodname: The method about bo be executed (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.method.entry = + process("@LIBRARY_PATH@").mark("method__entry") +{ + classname = user_string($arg1) + methodname = user_string($arg2) + file = user_string($arg3) + line = $arg4 +} + +/** + * probe ruby.method.return - Fired just after a method implemented in Ruby has returned. + * + * @classname: Name of the class (string) + * @methodname: The executed method (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.method.return = + process("@LIBRARY_PATH@").mark("method__return") +{ + classname = user_string($arg1) + methodname = user_string($arg2) + file = user_string($arg3) + line = $arg4 +} + +/** + * probe ruby.object.create - Allocation of new object. + * + * @classname: Name of the class (string) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.object.create = + process("@LIBRARY_PATH@").mark("object__create") +{ + classname = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.parse.begin - Fired just before a Ruby source file is parsed. + * + * @parsedfile: The name of the file to be parsed (string) + * @parsedline: The line number of beginning of parsing (int) + */ +probe ruby.parse.begin = + process("@LIBRARY_PATH@").mark("parse__begin") +{ + parsedfile = user_string($arg1) + parsedline = $arg2 +} + +/** + * probe ruby.parse.end - Fired just after a Ruby source file was parsed. + * + * @parsedfile: The name of parsed the file (string) + * @parsedline: The line number of beginning of parsing (int) + */ +probe ruby.parse.end = + process("@LIBRARY_PATH@").mark("parse__end") +{ + parsedfile = user_string($arg1) + parsedline = $arg2 +} + +/** + * probe ruby.raise - Fired when an exception is raised. + * + * @classname: The class name of the raised exception (string) + * @file: The name of the file where the exception was raised (string) + * @line: The line number in the file where the exception was raised (int) + */ +probe ruby.raise = + process("@LIBRARY_PATH@").mark("raise") +{ + classname = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.require.entry - Fired on calls to rb_require_safe (when a file + * is required). + * + * @requiredfile: The name of the file to be required (string) + * @file: The file that called "require" (string) + * @line: The line number where the call to require was made(int) + */ +probe ruby.require.entry = + process("@LIBRARY_PATH@").mark("require__entry") +{ + requiredfile = user_string($arg1) + file = user_string($arg2) + line = $arg3 +} + +/** + * probe ruby.require.return - Fired just after require has finished + * search of load path for suitable file to require. + * + * @requiredfile: The file that was required (string) + */ +probe ruby.require.return = + process("@LIBRARY_PATH@").mark("require__return") +{ + requiredfile = user_string($arg1) +} + +/** + * probe ruby.string.create - Allocation of new string. + * + * @size: Number of elements (an int) + * @file: The file name where the method is being called (string) + * @line: The line number where the method is being called (int) + */ +probe ruby.string.create = + process("@LIBRARY_PATH@").mark("string__create") +{ + size = $arg1 + file = user_string($arg2) + line = $arg3 +} diff --git a/macros.ruby b/macros.ruby new file mode 100644 index 0000000..36f4077 --- /dev/null +++ b/macros.ruby @@ -0,0 +1,22 @@ +%ruby_libdir %{_datadir}/%{name} +%ruby_libarchdir %{_libdir}/%{name} + +# This is the local lib/arch and should not be used for packaging. +%ruby_sitedir site_ruby +%ruby_sitelibdir %{_prefix}/local/share/%{name}/%{ruby_sitedir} +%ruby_sitearchdir %{_prefix}/local/%{_lib}/%{name}/%{ruby_sitedir} + +# This is the general location for libs/archs compatible with all +# or most of the Ruby versions available in the Fedora repositories. +%ruby_vendordir vendor_ruby +%ruby_vendorlibdir %{ruby_libdir}/%{ruby_vendordir} +%ruby_vendorarchdir %{ruby_libarchdir}/%{ruby_vendordir} + +# For ruby packages we want to filter out any provides caused by private +# libs in %%{ruby_vendorarchdir}/%%{ruby_sitearchdir}. +# +# Note that this must be invoked in the spec file, preferably as +# "%{?ruby_default_filter}", before any %description block. +%ruby_default_filter %{expand: \ +%global __provides_exclude_from %{?__provides_exclude_from:%{__provides_exclude_from}|}^(%{ruby_vendorarchdir}|%{ruby_sitearchdir})/.*\\\\.so$ \ +} diff --git a/macros.rubygems b/macros.rubygems new file mode 100644 index 0000000..8c4d067 --- /dev/null +++ b/macros.rubygems @@ -0,0 +1,186 @@ +# The RubyGems root folder. +%gem_dir %{_datadir}/gems +%gem_archdir %{_libdir}/gems + +# Common gem locations and files. +%gem_instdir %{gem_dir}/gems/%{gem_name}-%{version}%{?prerelease} +%gem_extdir_mri %{gem_archdir}/%{name}/%{gem_name}-%{version}%{?prerelease} +%gem_libdir %{gem_instdir}/lib +%gem_cache %{gem_dir}/cache/%{gem_name}-%{version}%{?prerelease}.gem +%gem_spec %{gem_dir}/specifications/%{gem_name}-%{version}%{?prerelease}.gemspec +%gem_docdir %{gem_dir}/doc/%{gem_name}-%{version}%{?prerelease} +%gem_plugin %{gem_dir}/plugins/%{gem_name}_plugin.rb + + +# %gem_install - Install gem into appropriate directory. +# +# Usage: %gem_install [options] +# +# -n Overrides gem file name for installation. +# -d Set installation directory. +# +%gem_install(d:n:) \ +mkdir -p %{-d*}%{!?-d:.%{gem_dir}} \ +\ +CONFIGURE_ARGS="--with-cflags='%{optflags}' --with-cxxflags='%{optflags}' --with-ldflags='%{build_ldflags}' $CONFIGURE_ARGS" \\\ +gem install \\\ + -V \\\ + --local \\\ + --build-root %{-d*}%{!?-d:.} \\\ + --force \\\ + --document=ri,rdoc \\\ + %{-n*}%{!?-n:%{gem_name}-%{version}%{?prerelease}.gem} \ +%{nil} + + +# The 'read' command in %%gemspec_* macros is not essential, but it is usefull +# to make the sript appear in build log. + + +# %gemspec_add_dep - Add dependency into .gemspec. +# +# Usage: %gemspec_add_dep -g [options] [requirements] +# +# Add dependency named to .gemspec file. The macro adds runtime +# dependency by default. The [requirements] argument can be used to specify +# the dependency constraints more precisely. It is expected to be valid Ruby +# code. +# +# -s Overrides the default .gemspec location. +# -d Add development dependecy. +# +%gemspec_add_dep(g:s:d) \ +read -d '' gemspec_add_dep_script << 'EOR' || : \ + gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}%{?prerelease}.gemspec}' \ + \ + name = '%{-g*}' \ + requirements = %{*}%{!?1:nil} \ + \ + type = :%{!?-d:runtime}%{?-d:development} \ + \ + spec = Gem::Specification.load(gemspec_file) \ + abort("#{gemspec_file} is not accessible.") unless spec \ + \ + dep = spec.dependencies.detect { |d| d.type == type && d.name == name } \ + if dep \ + dep.requirement.concat requirements \ + else \ + spec.public_send "add_#{type}_dependency", name, requirements \ + end \ + File.write gemspec_file, spec.to_ruby \ +EOR\ +echo "$gemspec_add_dep_script" | ruby \ +unset -v gemspec_add_dep_script \ +%{nil} + + +# %gemspec_remove_dep - Remove dependency from .gemspec. +# +# Usage: %gemspec_remove_dep -g [options] [requirements] +# +# Remove dependency named from .gemspec file. The macro removes runtime +# dependency by default. The [requirements] argument can be used to specify +# the dependency constraints more precisely. It is expected to be valid Ruby +# code. The macro fails if these specific requirements can't be removed. +# +# -s Overrides the default .gemspec location. +# -d Remove development dependecy. +# +%gemspec_remove_dep(g:s:d) \ +read -d '' gemspec_remove_dep_script << 'EOR' || : \ + gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}%{?prerelease}.gemspec}' \ + \ + name = '%{-g*}' \ + requirements = %{*}%{!?1:nil} \ + \ + type = :%{!?-d:runtime}%{?-d:development} \ + \ + spec = Gem::Specification.load(gemspec_file) \ + abort("#{gemspec_file} is not accessible.") unless spec \ + \ + dep = spec.dependencies.detect { |d| d.type == type && d.name == name } \ + if dep \ + if requirements \ + requirements = Gem::Requirement.create(requirements).requirements \ + requirements.each do |r| \ + unless dep.requirement.requirements.reject! { |dependency_requirements| dependency_requirements == r } \ + abort("Requirement '#{r.first} #{r.last}' was not possible to remove for dependency '#{dep}'!") \ + end \ + end \ + spec.dependencies.delete dep if dep.requirement.requirements.empty? \ + else \ + spec.dependencies.delete dep \ + end \ + else \ + abort("Dependency '#{name}' was not found!") \ + end \ + File.write gemspec_file, spec.to_ruby \ +EOR\ +echo "$gemspec_remove_dep_script" | ruby \ +unset -v gemspec_remove_dep_script \ +%{nil} + + +# %%gemspec_add_file - Add files to various files lists in .gemspec. +# +# Usage: %%gemspec_add_file [options] +# +# Add files to .gemspec file. is expected to be valid Ruby code. +# Path to file is expected. Does not check real files in any way. +# By default, `files` list is edited. +# +# -s Overrides the default .gemspec location. +# -t Edit test_files only. +# -r Edit extra_rdoc_files only. +# +%gemspec_add_file(s:tr) \ +read -d '' gemspec_add_file_script << 'EOR' || : \ + gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}%{?prerelease}.gemspec}' \ + \ + abort("gemspec_add_file: Use only one '-t' or '-r' at a time.") if "%{?-t}%{?-r}" == "-t-r" \ + \ + filenames = %{*}%{!?1:nil} \ + filenames = Array(filenames) \ + \ + spec = Gem::Specification.load(gemspec_file) \ + abort("#{gemspec_file} is not accessible.") unless spec \ + \ + spec.%{?-t:test_}%{?-r:extra_rdoc_}files += filenames \ + File.write gemspec_file, spec.to_ruby \ +EOR\ +echo "$gemspec_add_file_script" | ruby \ +unset -v gemspec_add_file_script \ +%{nil} + + +# %%gemspec_remove_file - Remove files from various files lists in .gemspec. +# +# Usage: %%gemspec_remove_file [options] +# +# Remove files from .gemspec file. is expected to be valid Ruby code. +# Path to file is expected. Does not check/remove real files in any way. +# By default, `files` list is edited. File has to be removed from `test_files` +# first in order to be removable from `files`. +# +# -s Overrides the default .gemspec location. +# -t Edit test_files only. +# -r Edit extra_rdoc_files only. +# +%gemspec_remove_file(s:tr) \ +read -d '' gemspec_remove_file_script << 'EOR' || : \ + gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}%{?prerelease}.gemspec}' \ + \ + abort("gemspec_remove_file: Use only one '-t' or '-r' at a time.") if "%{?-t}%{?-r}" == "-t-r" \ + \ + filenames = %{*}%{!?1:nil} \ + filenames = Array(filenames) \ + \ + spec = Gem::Specification.load(gemspec_file) \ + abort("#{gemspec_file} is not accessible.") unless spec \ + \ + spec.%{?-t:test_}%{?-r:extra_rdoc_}files -= filenames \ + File.write gemspec_file, spec.to_ruby \ +EOR\ +echo "$gemspec_remove_file_script" | ruby \ +unset -v gemspec_remove_file_script \ +%{nil} diff --git a/operating_system.rb b/operating_system.rb new file mode 100644 index 0000000..d95b303 --- /dev/null +++ b/operating_system.rb @@ -0,0 +1,148 @@ +module Gem + class << self + + ## + # Returns full path of previous but one directory of dir in path + # E.g. for '/usr/share/ruby', 'ruby', it returns '/usr' + + def previous_but_one_dir_to(path, dir) + return unless path + + split_path = path.split(File::SEPARATOR) + File.join(split_path.take_while { |one_dir| one_dir !~ /^#{dir}$/ }[0..-2]) + end + private :previous_but_one_dir_to + + ## + # Detects --install-dir option specified on command line. + + def opt_install_dir? + @opt_install_dir ||= ARGV.include?('--install-dir') || ARGV.include?('-i') + end + private :opt_install_dir? + + ## + # Detects --build-root option specified on command line. + + def opt_build_root? + @opt_build_root ||= ARGV.include?('--build-root') + end + private :opt_build_root? + + ## + # Tries to detect, if arguments and environment variables suggest that + # 'gem install' is executed from rpmbuild. + + def rpmbuild? + @rpmbuild ||= ENV['RPM_PACKAGE_NAME'] && (opt_install_dir? || opt_build_root?) + end + private :rpmbuild? + + ## + # Default gems locations allowed on FHS system (/usr, /usr/share). + # The locations are derived from directories specified during build + # configuration. + + def default_locations + @default_locations ||= { + :system => previous_but_one_dir_to(RbConfig::CONFIG['vendordir'], RbConfig::CONFIG['RUBY_INSTALL_NAME']), + :local => previous_but_one_dir_to(RbConfig::CONFIG['sitedir'], RbConfig::CONFIG['RUBY_INSTALL_NAME']) + } + end + + ## + # For each location provides set of directories for binaries (:bin_dir) + # platform independent (:gem_dir) and dependent (:ext_dir) files. + + def default_dirs + @libdir ||= case RUBY_PLATFORM + when 'java' + RbConfig::CONFIG['datadir'] + else + RbConfig::CONFIG['libdir'] + end + + @default_dirs ||= default_locations.inject(Hash.new) do |hash, location| + destination, path = location + + hash[destination] = if path + { + :bin_dir => File.join(path, RbConfig::CONFIG['bindir'].split(File::SEPARATOR).last), + :gem_dir => File.join(path, RbConfig::CONFIG['datadir'].split(File::SEPARATOR).last, 'gems'), + :ext_dir => File.join(path, @libdir.split(File::SEPARATOR).last, 'gems') + } + else + { + :bin_dir => '', + :gem_dir => '', + :ext_dir => '' + } + end + + hash + end + end + + ## + # Remove methods we are going to override. This avoids "method redefined;" + # warnings otherwise issued by Ruby. + + remove_method :operating_system_defaults if method_defined? :operating_system_defaults + remove_method :default_dir if method_defined? :default_dir + remove_method :default_path if method_defined? :default_path + remove_method :default_ext_dir_for if method_defined? :default_ext_dir_for + + ## + # Regular user installs into user directory, root manages /usr/local. + + def operating_system_defaults + unless opt_build_root? + options = if Process.uid == 0 + "--install-dir=#{Gem.default_dirs[:local][:gem_dir]} --bindir #{Gem.default_dirs[:local][:bin_dir]}" + else + "--user-install --bindir #{File.join [Dir.home, 'bin']}" + end + + {"gem" => options} + else + {} + end + end + + ## + # RubyGems default overrides. + + def default_dir + Gem.default_dirs[:system][:gem_dir] + end + + def default_path + path = default_dirs.collect {|location, paths| paths[:gem_dir]} + path.unshift Gem.user_dir if File.exist? Gem.user_home + path + end + + def default_ext_dir_for base_dir + dir = if rpmbuild? + build_dir = base_dir.chomp Gem.default_dirs[:system][:gem_dir] + if build_dir != base_dir + File.join build_dir, Gem.default_dirs[:system][:ext_dir] + end + else + dirs = Gem.default_dirs.detect {|location, paths| paths[:gem_dir] == base_dir} + dirs && dirs.last[:ext_dir] + end + dir && File.join(dir, RbConfig::CONFIG['RUBY_INSTALL_NAME']) + end + + # This method should be available since RubyGems 2.2 until RubyGems 3.0. + # https://github.com/rubygems/rubygems/issues/749 + if method_defined? :install_extension_in_lib + remove_method :install_extension_in_lib + + def install_extension_in_lib + false + end + end + end +end diff --git a/ruby-1.9.3-mkmf-verbose.patch b/ruby-1.9.3-mkmf-verbose.patch new file mode 100644 index 0000000..b9c2c6f --- /dev/null +++ b/ruby-1.9.3-mkmf-verbose.patch @@ -0,0 +1,25 @@ +From 28cc0749d6729aa2444661ee7b411e183fe220b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Mon, 19 Nov 2012 15:14:51 +0100 +Subject: [PATCH] Verbose mkmf. + +--- + lib/mkmf.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/mkmf.rb b/lib/mkmf.rb +index 682eb46..e6b1445 100644 +--- a/lib/mkmf.rb ++++ b/lib/mkmf.rb +@@ -1930,7 +1930,7 @@ def configuration(srcdir) + SHELL = /bin/sh + + # V=0 quiet, V=1 verbose. other values don't work. +-V = 0 ++V = 1 + Q1 = $(V:1=) + Q = $(Q1:0=@) + ECHO1 = $(V:1=@ #{CONFIG['NULLCMD']}) +-- +1.8.3.1 + diff --git a/ruby-2.1.0-Enable-configuration-of-archlibdir.patch b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch new file mode 100644 index 0000000..32806da --- /dev/null +++ b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch @@ -0,0 +1,28 @@ +From 07c666ba5c3360dd6f43605a8ac7c85c99c1721f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Tue, 1 Oct 2013 12:22:40 +0200 +Subject: [PATCH] Allow to configure libruby.so placement. + +--- + configure.ac | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/configure.ac b/configure.ac +index d261ea57b5..3c13076b82 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3240,6 +3240,11 @@ AS_IF([test ${multiarch+set}], [ + ]) + + archlibdir='${libdir}/${arch}' ++AC_ARG_WITH(archlibdir, ++ AS_HELP_STRING([--with-archlibdir=DIR], ++ [prefix for libruby [[LIBDIR/ARCH]]]), ++ [archlibdir="$withval"]) ++ + sitearchlibdir='${libdir}/${sitearch}' + archincludedir='${includedir}/${arch}' + sitearchincludedir='${includedir}/${sitearch}' +-- +2.22.0 + diff --git a/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch b/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch new file mode 100644 index 0000000..437d09f --- /dev/null +++ b/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch @@ -0,0 +1,80 @@ +From e24d97c938c481450ed80ec83e5399595946c1ae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Fri, 8 Feb 2013 22:48:41 +0100 +Subject: [PATCH] Prevent duplicated paths when empty version string is + configured. + +--- + configure.ac | 3 ++- + loadpath.c | 12 ++++++++++++ + tool/mkconfig.rb | 2 +- + 3 files changed, 15 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index c42436c23d..d261ea57b5 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3886,7 +3886,8 @@ AS_CASE(["$ruby_version_dir_name"], + ruby_version_dir=/'${ruby_version_dir_name}' + + if test -z "${ruby_version_dir_name}"; then +- AC_MSG_ERROR([No ruby version, No place for bundled libraries]) ++ unset ruby_version_dir ++ AC_DEFINE(RUBY_LIB_VERSION_BLANK, 1) + fi + + rubylibdir='${rubylibprefix}'${ruby_version_dir} +diff --git a/loadpath.c b/loadpath.c +index 9160031..0d4d953 100644 +--- a/loadpath.c ++++ b/loadpath.c +@@ -65,21 +65,33 @@ const char ruby_initial_load_paths[] = + RUBY_SEARCH_PATH "\0" + #endif + #ifndef NO_RUBY_SITE_LIB ++#ifdef RUBY_LIB_VERSION_BLANK ++ RUBY_SITE_LIB "\0" ++#else + RUBY_SITE_LIB2 "\0" ++#endif + #ifdef RUBY_THINARCH + RUBY_SITE_ARCH_LIB_FOR(RUBY_THINARCH) "\0" + #endif + RUBY_SITE_ARCH_LIB_FOR(RUBY_SITEARCH) "\0" ++#ifndef RUBY_LIB_VERSION_BLANK + RUBY_SITE_LIB "\0" + #endif ++#endif + + #ifndef NO_RUBY_VENDOR_LIB ++#ifdef RUBY_LIB_VERSION_BLANK ++ RUBY_VENDOR_LIB "\0" ++#else + RUBY_VENDOR_LIB2 "\0" ++#endif + #ifdef RUBY_THINARCH + RUBY_VENDOR_ARCH_LIB_FOR(RUBY_THINARCH) "\0" + #endif + RUBY_VENDOR_ARCH_LIB_FOR(RUBY_SITEARCH) "\0" ++#ifndef RUBY_LIB_VERSION_BLANK + RUBY_VENDOR_LIB "\0" ++#endif + #endif + + RUBY_LIB "\0" +diff --git a/tool/mkconfig.rb b/tool/mkconfig.rb +index 07076d4..35e6c3c 100755 +--- a/tool/mkconfig.rb ++++ b/tool/mkconfig.rb +@@ -114,7 +114,7 @@ + val = val.gsub(/\$(?:\$|\{?(\w+)\}?)/) {$1 ? "$(#{$1})" : $&}.dump + case name + when /^prefix$/ +- val = "(TOPDIR || DESTDIR + #{val})" ++ val = "(((TOPDIR && TOPDIR.empty?) ? nil : TOPDIR) || DESTDIR + #{val})" + when /^ARCH_FLAG$/ + val = "arch_flag || #{val}" if universal + when /^UNIVERSAL_ARCHNAMES$/ +-- +1.9.0 + diff --git a/ruby-2.1.0-always-use-i386.patch b/ruby-2.1.0-always-use-i386.patch new file mode 100644 index 0000000..46584d7 --- /dev/null +++ b/ruby-2.1.0-always-use-i386.patch @@ -0,0 +1,25 @@ +From 2089cab72b38d6d5e7ba2b596e41014209acad30 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Mon, 19 Nov 2012 14:37:28 +0100 +Subject: [PATCH] Always use i386. + +--- + configure.ac | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 3c13076b82..93af30321d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3950,6 +3950,8 @@ AC_SUBST(vendorarchdir)dnl + AC_SUBST(CONFIGURE, "`echo $0 | sed 's|.*/||'`")dnl + AC_SUBST(configure_args, "`echo "${ac_configure_args}" | sed 's/\\$/$$/g'`")dnl + ++target_cpu=`echo $target_cpu | sed s/i.86/i386/` ++ + AS_IF([test "${universal_binary-no}" = yes ], [ + arch="universal-${target_os}" + AS_IF([test "${rb_cv_architecture_available}" = yes], [ +-- +1.8.3.1 + diff --git a/ruby-2.1.0-custom-rubygems-location.patch b/ruby-2.1.0-custom-rubygems-location.patch new file mode 100644 index 0000000..6946429 --- /dev/null +++ b/ruby-2.1.0-custom-rubygems-location.patch @@ -0,0 +1,97 @@ +From 94da59aafacc6a9efe829529eb51385588d6f149 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Fri, 11 Nov 2011 13:14:45 +0100 +Subject: [PATCH] Allow to install RubyGems into custom location, outside of + Ruby tree. + +--- + configure.ac | 5 +++++ + loadpath.c | 4 ++++ + template/verconf.h.tmpl | 3 +++ + tool/rbinstall.rb | 10 ++++++++++ + 4 files changed, 22 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 93af30321d..bc13397e0e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3922,6 +3922,10 @@ AC_ARG_WITH(vendorarchdir, + [vendorarchdir=$withval], + [vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby'${ruby_version_dir}}${multiarch-'${vendorlibdir}/${sitearch}'}]) + ++AC_ARG_WITH(rubygemsdir, ++ AS_HELP_STRING([--with-rubygemsdir=DIR], [custom rubygems directory]), ++ [rubygemsdir=$withval]) ++ + AS_IF([test "${LOAD_RELATIVE+set}"], [ + AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) + RUBY_EXEC_PREFIX='' +@@ -3946,6 +3950,7 @@ AC_SUBST(sitearchdir)dnl + AC_SUBST(vendordir)dnl + AC_SUBST(vendorlibdir)dnl + AC_SUBST(vendorarchdir)dnl ++AC_SUBST(rubygemsdir)dnl + + AC_SUBST(CONFIGURE, "`echo $0 | sed 's|.*/||'`")dnl + AC_SUBST(configure_args, "`echo "${ac_configure_args}" | sed 's/\\$/$$/g'`")dnl +diff --git a/loadpath.c b/loadpath.c +index 623dc9d..74c5d9e 100644 +--- a/loadpath.c ++++ b/loadpath.c +@@ -94,6 +94,10 @@ const char ruby_initial_load_paths[] = + #endif + #endif + ++#ifdef RUBYGEMS_DIR ++ RUBYGEMS_DIR "\0" ++#endif ++ + RUBY_LIB "\0" + #ifdef RUBY_THINARCH + RUBY_ARCH_LIB_FOR(RUBY_THINARCH) "\0" +diff --git a/template/verconf.h.tmpl b/template/verconf.h.tmpl +index 79c003e..34f2382 100644 +--- a/template/verconf.h.tmpl ++++ b/template/verconf.h.tmpl +@@ -36,6 +36,9 @@ + % if C["RUBY_SEARCH_PATH"] + #define RUBY_SEARCH_PATH "${RUBY_SEARCH_PATH}" + % end ++% if C["rubygemsdir"] ++#define RUBYGEMS_DIR "${rubygemsdir}" ++% end + % + % R = {} + % R["ruby_version"] = '"RUBY_LIB_VERSION"' +diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb +index e9110a17ca..76a1f0a315 100755 +--- a/tool/rbinstall.rb ++++ b/tool/rbinstall.rb +@@ -349,6 +349,7 @@ def CONFIG.[](name, mandatory = false) + vendorlibdir = CONFIG["vendorlibdir"] + vendorarchlibdir = CONFIG["vendorarchdir"] + end ++rubygemsdir = CONFIG["rubygemsdir"] + mandir = CONFIG["mandir", true] + docdir = CONFIG["docdir", true] + enable_shared = CONFIG["ENABLE_SHARED"] == 'yes' +@@ -581,7 +582,16 @@ def stub + install?(:local, :comm, :lib) do + prepare "library scripts", rubylibdir + noinst = %w[*.txt *.rdoc *.gemspec] ++ # Bundler carries "rubygems.rb" file, so it must be specialcased :/ ++ noinst += %w[rubygems.rb rubygems/ bundler.rb bundler/] if rubygemsdir + install_recursive(File.join(srcdir, "lib"), rubylibdir, :no_install => noinst, :mode => $data_mode) ++ if rubygemsdir ++ noinst = %w[*.txt *.rdoc *.gemspec] ++ install_recursive(File.join(srcdir, "lib", "rubygems"), File.join(rubygemsdir, "rubygems"), :no_install => noinst, :mode => $data_mode) ++ install(File.join(srcdir, "lib", "rubygems.rb"), File.join(rubygemsdir, "rubygems.rb"), :mode => $data_mode) ++ install_recursive(File.join(srcdir, "lib", "bundler"), File.join(rubylibdir, "bundler"), :no_install => noinst, :mode => $data_mode) ++ install(File.join(srcdir, "lib", "bundler.rb"), rubylibdir, :mode => $data_mode) ++ end + end + + install?(:local, :comm, :hdr, :'comm-hdr') do +-- +1.8.3.1 + diff --git a/ruby-2.3.0-ruby_version.patch b/ruby-2.3.0-ruby_version.patch new file mode 100644 index 0000000..fd545e5 --- /dev/null +++ b/ruby-2.3.0-ruby_version.patch @@ -0,0 +1,288 @@ +From 4fc1be3af3f58621bb751c9e63c208b15c0e8d16 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Tue, 31 Mar 2015 16:21:04 +0200 +Subject: [PATCH 1/4] Use ruby_version_dir_name for versioned directories. + +This disallows changing the ruby_version constant by --with-ruby-version +configuration options. The two places version numbers are disallowed as +well, since there are a lot of places which cannot handle this format +properly. + +ruby_version_dir_name now specifies custom version string for versioned +directories, e.g. instead of default X.Y.Z, you can specify whatever +string. +--- + configure.ac | 64 ++++++++++++++++++++++++--------------------- + template/ruby.pc.in | 1 + + 2 files changed, 35 insertions(+), 30 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 80b137e380..63cd3b4f8b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3837,9 +3837,6 @@ AS_CASE(["$target_os"], + rubyw_install_name='$(RUBYW_INSTALL_NAME)' + ]) + +-rubylibdir='${rubylibprefix}/${ruby_version}' +-rubyarchdir=${multiarch+'${rubyarchprefix}/${ruby_version}'}${multiarch-'${rubylibdir}/${arch}'} +- + rubyarchprefix=${multiarch+'${archlibdir}/${RUBY_BASE_NAME}'}${multiarch-'${rubylibprefix}/${arch}'} + AC_ARG_WITH(rubyarchprefix, + AS_HELP_STRING([--with-rubyarchprefix=DIR], +@@ -3862,56 +3859,62 @@ AC_ARG_WITH(ridir, + AC_SUBST(ridir) + AC_SUBST(RI_BASE_NAME) + +-AC_ARG_WITH(ruby-version, +- AS_HELP_STRING([--with-ruby-version=STR], [ruby version string for version specific directories [[full]] (full|minor|STR)]), +- [ruby_version=$withval], +- [ruby_version=full]) + unset RUBY_LIB_VERSION +-unset RUBY_LIB_VERSION_STYLE +-AS_CASE(["$ruby_version"], +- [full], [RUBY_LIB_VERSION_STYLE='3 /* full */'], +- [minor], [RUBY_LIB_VERSION_STYLE='2 /* minor */']) +-AS_IF([test ${RUBY_LIB_VERSION_STYLE+set}], [ +- { +- echo "#define RUBY_LIB_VERSION_STYLE $RUBY_LIB_VERSION_STYLE" +- echo '#define STRINGIZE(x) x' +- test -f revision.h -o -f "${srcdir}/revision.h" || echo '#define RUBY_REVISION 0' +- echo '#include "version.h"' +- echo 'ruby_version=RUBY_LIB_VERSION' +- } > conftest.c +- ruby_version="`$CPP -I. -I"${srcdir}" -I"${srcdir}/include" conftest.c | sed '/^ruby_version=/!d;s/ //g'`" +- eval $ruby_version +-], [test -z "${ruby_version}"], [ +- AC_MSG_ERROR([No ruby version, No place for bundled libraries]) +-], [ +- RUBY_LIB_VERSION="${ruby_version}" +-]) ++RUBY_LIB_VERSION_STYLE='3 /* full */' ++{ ++echo "#define RUBY_LIB_VERSION_STYLE $RUBY_LIB_VERSION_STYLE" ++echo '#define STRINGIZE(x) x' ++test -f revision.h -o -f "${srcdir}/revision.h" || echo '#define RUBY_REVISION 0' ++echo '#include "version.h"' ++echo 'ruby_version=RUBY_LIB_VERSION' ++} > conftest.c ++ruby_version="`$CPP -I. -I"${srcdir}" -I"${srcdir}/include" conftest.c | sed '/^ruby_version=/!d;s/ //g'`" ++eval $ruby_version ++ ++RUBY_LIB_VERSION="${ruby_version}" ++ + AC_SUBST(RUBY_LIB_VERSION_STYLE) + AC_SUBST(RUBY_LIB_VERSION) + ++AC_ARG_WITH(ruby-version, ++ AS_HELP_STRING([--with-ruby-version=STR], [ruby version string for version specific directories [[full]] (full|STR)]), ++ [ruby_version_dir_name=$withval], ++ [ruby_version_dir_name=full]) ++AS_CASE(["$ruby_version_dir_name"], ++ [full], [ruby_version_dir_name='${ruby_version}']) ++ ++ruby_version_dir=/'${ruby_version_dir_name}' ++ ++if test -z "${ruby_version_dir_name}"; then ++ AC_MSG_ERROR([No ruby version, No place for bundled libraries]) ++fi ++ ++rubylibdir='${rubylibprefix}'${ruby_version_dir} ++rubyarchdir=${multiarch+'${rubyarchprefix}'${ruby_version_dir}}${multiarch-'${rubylibdir}/${arch}'} ++ + AC_ARG_WITH(sitedir, + AS_HELP_STRING([--with-sitedir=DIR], [site libraries in DIR [[RUBY_LIB_PREFIX/site_ruby]], "no" to disable site directory]), + [sitedir=$withval], + [sitedir='${rubylibprefix}/site_ruby']) +-sitelibdir='${sitedir}/${ruby_version}' ++sitelibdir='${sitedir}'${ruby_version_dir} + + AC_ARG_WITH(sitearchdir, + AS_HELP_STRING([--with-sitearchdir=DIR], + [architecture dependent site libraries in DIR [[SITEDIR/SITEARCH]], "no" to disable site directory]), + [sitearchdir=$withval], +- [sitearchdir=${multiarch+'${rubysitearchprefix}/site_ruby/${ruby_version}'}${multiarch-'${sitelibdir}/${sitearch}'}]) ++ [sitearchdir=${multiarch+'${rubysitearchprefix}/site_ruby'${ruby_version_dir}}${multiarch-'${sitelibdir}/${sitearch}'}]) + + AC_ARG_WITH(vendordir, + AS_HELP_STRING([--with-vendordir=DIR], [vendor libraries in DIR [[RUBY_LIB_PREFIX/vendor_ruby]], "no" to disable vendor directory]), + [vendordir=$withval], + [vendordir='${rubylibprefix}/vendor_ruby']) +-vendorlibdir='${vendordir}/${ruby_version}' ++vendorlibdir='${vendordir}'${ruby_version_dir} + + AC_ARG_WITH(vendorarchdir, + AS_HELP_STRING([--with-vendorarchdir=DIR], + [architecture dependent vendor libraries in DIR [[VENDORDIR/SITEARCH]], "no" to disable vendor directory]), + [vendorarchdir=$withval], +- [vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby/${ruby_version}'}${multiarch-'${vendorlibdir}/${sitearch}'}]) ++ [vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby'${ruby_version_dir}}${multiarch-'${vendorlibdir}/${sitearch}'}]) + + AS_IF([test "${LOAD_RELATIVE+set}"], [ + AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) +@@ -3928,6 +3931,7 @@ AC_SUBST(sitearchincludedir)dnl + AC_SUBST(arch)dnl + AC_SUBST(sitearch)dnl + AC_SUBST(ruby_version)dnl ++AC_SUBST(ruby_version_dir_name)dnl + AC_SUBST(rubylibdir)dnl + AC_SUBST(rubyarchdir)dnl + AC_SUBST(sitedir)dnl +diff --git a/template/ruby.pc.in b/template/ruby.pc.in +index 8a2c066..c81b211 100644 +--- a/template/ruby.pc.in ++++ b/template/ruby.pc.in +@@ -9,6 +9,7 @@ MAJOR=@MAJOR@ + MINOR=@MINOR@ + TEENY=@TEENY@ + ruby_version=@ruby_version@ ++ruby_version_dir_name=@ruby_version_dir_name@ + RUBY_API_VERSION=@RUBY_API_VERSION@ + RUBY_PROGRAM_VERSION=@RUBY_PROGRAM_VERSION@ + RUBY_BASE_NAME=@RUBY_BASE_NAME@ +-- +2.1.0 + + +From 518850aba6eee76de7715aae8d37330e34b01983 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Tue, 31 Mar 2015 16:37:26 +0200 +Subject: [PATCH 2/4] Add ruby_version_dir_name support for RDoc. + +--- + lib/rdoc/ri/paths.rb | 2 +- + tool/rbinstall.rb | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/rdoc/ri/paths.rb b/lib/rdoc/ri/paths.rb +index 970cb91..5bf8230 100644 +--- a/lib/rdoc/ri/paths.rb ++++ b/lib/rdoc/ri/paths.rb +@@ -10,7 +10,7 @@ module RDoc::RI::Paths + #:stopdoc: + require 'rbconfig' + +- version = RbConfig::CONFIG['ruby_version'] ++ version = RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] + + BASE = File.join RbConfig::CONFIG['ridir'], version + +diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb +index d4c110e..d39c9a6 100755 +--- a/tool/rbinstall.rb ++++ b/tool/rbinstall.rb +@@ -439,7 +439,7 @@ def CONFIG.[](name, mandatory = false) + + install?(:doc, :rdoc) do + if $rdocdir +- ridatadir = File.join(CONFIG['ridir'], CONFIG['ruby_version'], "system") ++ ridatadir = File.join(CONFIG['ridir'], CONFIG['ruby_version_dir_name'] || CONFIG['ruby_version'], "system") + prepare "rdoc", ridatadir + install_recursive($rdocdir, ridatadir, :no_install => rdoc_noinst, :mode => $data_mode) + end +-- +2.23.0 + + +From 9f0ec0233f618cbb862629816b22491c3df79578 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Tue, 31 Mar 2015 16:37:44 +0200 +Subject: [PATCH 3/4] Add ruby_version_dir_name support for RubyGems. + +--- + lib/rubygems/defaults.rb | 9 +++++---- + test/rubygems/test_gem.rb | 5 +++-- + 2 files changed, 8 insertions(+), 6 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 + +@@ -117,7 +117,8 @@ def self.user_dir + gem_dir = File.join(Gem.user_home, ".gem") + gem_dir = File.join(Gem.data_home, "gem") unless File.exist?(gem_dir) + parts = [gem_dir, ruby_engine] +- parts << RbConfig::CONFIG['ruby_version'] unless RbConfig::CONFIG['ruby_version'].empty? ++ ruby_version_dir_name = RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] ++ parts << ruby_version_dir_name unless ruby_version_dir_name.empty? + File.join parts + end + +@@ -252,7 +253,7 @@ def self.vendor_dir # :nodoc: + return nil unless RbConfig::CONFIG.key? 'vendordir' + + File.join RbConfig::CONFIG['vendordir'], 'gems', +- RbConfig::CONFIG['ruby_version'] ++ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] + end + + ## +diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb +index b25068405d..e9fef4a311 100644 +--- a/test/rubygems/test_gem.rb ++++ b/test/rubygems/test_gem.rb +@@ -1440,7 +1440,8 @@ def test_self_use_paths + + def test_self_user_dir + parts = [@userhome, '.gem', Gem.ruby_engine] +- parts << RbConfig::CONFIG['ruby_version'] unless RbConfig::CONFIG['ruby_version'].empty? ++ ruby_version_dir_name = RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] ++ parts << ruby_version_dir_name unless ruby_version_dir_name.empty? + + FileUtils.mkdir_p File.join(parts) + +@@ -1516,7 +1517,7 @@ def test_self_vendor_dir + vendordir(File.join(@tempdir, 'vendor')) do + expected = + File.join RbConfig::CONFIG['vendordir'], 'gems', +- RbConfig::CONFIG['ruby_version'] ++ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] + + assert_equal expected, Gem.vendor_dir + end +-- +2.1.0 + + +From 88c38a030c22dbf9422ece847bdfbf87d6659313 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Wed, 1 Apr 2015 14:55:37 +0200 +Subject: [PATCH 4/4] Let headers directories follow the configured version + name. + +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index a00f2b6776..999e2d6d5d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -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) +-AC_SUBST(RUBY_VERSION_NAME, '${RUBY_BASE_NAME}-${ruby_version}') ++AC_SUBST(RUBY_VERSION_NAME, '${RUBY_BASE_NAME}-${ruby_version_dir_name}') + + dnl checks for alternative programs + AC_CANONICAL_BUILD +-- +2.1.0 + diff --git a/ruby-2.7.0-Initialize-ABRT-hook.patch b/ruby-2.7.0-Initialize-ABRT-hook.patch new file mode 100644 index 0000000..2b90d9e --- /dev/null +++ b/ruby-2.7.0-Initialize-ABRT-hook.patch @@ -0,0 +1,77 @@ +From eca084e4079c77c061045df9c21b219175b05228 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Mon, 6 Jan 2020 13:56:04 +0100 +Subject: [PATCH] Initialize ABRT hook. + +The ABRT hook used to be initialized by preludes via patches [[1], [2]]. +Unfortunately, due to [[3]] and especially since [[4]], this would +require boostrapping [[5]]. + +To keep the things simple for now, load the ABRT hook via C. + +[1]: https://bugs.ruby-lang.org/issues/8566 +[2]: https://bugs.ruby-lang.org/issues/15306 +[3]: https://bugs.ruby-lang.org/issues/16254 +[4]: https://github.com/ruby/ruby/pull/2735 +[5]: https://lists.fedoraproject.org/archives/list/ruby-sig@lists.fedoraproject.org/message/LH6L6YJOYQT4Y5ZNOO4SLIPTUWZ5V45Q/ +--- + abrt.c | 12 ++++++++++++ + common.mk | 3 ++- + ruby.c | 4 ++++ + 3 files changed, 18 insertions(+), 1 deletion(-) + create mode 100644 abrt.c + +diff --git a/abrt.c b/abrt.c +new file mode 100644 +index 0000000000..74b0bd5c0f +--- /dev/null ++++ b/abrt.c +@@ -0,0 +1,12 @@ ++#include "internal.h" ++ ++void ++Init_abrt(void) ++{ ++ rb_eval_string( ++ " begin\n" ++ " require 'abrt'\n" ++ " rescue LoadError\n" ++ " end\n" ++ ); ++} +diff --git a/common.mk b/common.mk +index b2e5b2b6d0..f39f81da5c 100644 +--- a/common.mk ++++ b/common.mk +@@ -81,7 +81,8 @@ ENC_MK = enc.mk + MAKE_ENC = -f $(ENC_MK) V="$(V)" UNICODE_HDR_DIR="$(UNICODE_HDR_DIR)" \ + RUBY="$(MINIRUBY)" MINIRUBY="$(MINIRUBY)" $(mflags) + +-COMMONOBJS = array.$(OBJEXT) \ ++COMMONOBJS = abrt.$(OBJEXT) \ ++ array.$(OBJEXT) \ + ast.$(OBJEXT) \ + bignum.$(OBJEXT) \ + class.$(OBJEXT) \ +diff --git a/ruby.c b/ruby.c +index 60c57d6259..1eec16f2c8 100644 +--- a/ruby.c ++++ b/ruby.c +@@ -1489,10 +1489,14 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt) + + void Init_builtin_features(void); + ++/* abrt.c */ ++void Init_abrt(void); ++ + static void + ruby_init_prelude(void) + { + Init_builtin_features(); ++ Init_abrt(); + rb_const_remove(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX")); + } + +-- +2.24.1 + diff --git a/ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch b/ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch new file mode 100644 index 0000000..64e2114 --- /dev/null +++ b/ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch @@ -0,0 +1,34 @@ +From 9b42fce32bff25e0569581f76f532b9d57865aef Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Mon, 27 Jul 2020 14:56:05 +0200 +Subject: [PATCH] Timeout the test_bug_reporter_add witout raising error. + +While timeouting the threads might be still good idea, it does not seems +the timeout impacts the TestBugReporter#test_bug_reporter_add result, +because the output of the child process has been already collected +earlier. + +It seems that when the system is under heavy load, the thread might not +be sheduled to finish its processing. Even finishing the child process +might take tens of seconds and therefore the test case finish might take +a while. +--- + test/-ext-/bug_reporter/test_bug_reporter.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/-ext-/bug_reporter/test_bug_reporter.rb b/test/-ext-/bug_reporter/test_bug_reporter.rb +index 628fcd0340..2c677cc8a7 100644 +--- a/test/-ext-/bug_reporter/test_bug_reporter.rb ++++ b/test/-ext-/bug_reporter/test_bug_reporter.rb +@@ -21,7 +21,7 @@ def test_bug_reporter_add + args = ["--disable-gems", "-r-test-/bug_reporter", + "-C", tmpdir] + stdin = "register_sample_bug_reporter(12345); Process.kill :SEGV, $$" +- assert_in_out_err(args, stdin, [], expected_stderr, encoding: "ASCII-8BIT") ++ assert_in_out_err(args, stdin, [], expected_stderr, encoding: "ASCII-8BIT", timeout_error: nil) + ensure + FileUtils.rm_rf(tmpdir) if tmpdir + end +-- +2.27.0 + diff --git a/ruby-3.0.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-Add-more-support-for-generic-pkey-types.patch b/ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch new file mode 100644 index 0000000..cede1aa --- /dev/null +++ b/ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch @@ -0,0 +1,1004 @@ +From 6bbdaef1a578fdbfc6a5bf82402ba4d3fd733d4a Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 21 Mar 2017 18:23:53 +0900 +Subject: [PATCH 1/6] pkey: assume generic PKeys contain private components + +The EVP interface cannot tell whether if a pkey contains the private +components or not. Assume it does if it does not respond to #private?. +This fixes the NoMethodError on calling #sign on a generic PKey. +--- + ext/openssl/ossl_pkey.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 610a83fd2d..8d41623e80 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -252,12 +252,19 @@ GetPrivPKeyPtr(VALUE obj) + { + EVP_PKEY *pkey; + +- if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) { +- ossl_raise(rb_eArgError, "Private key is needed."); +- } + GetPKey(obj, pkey); ++ if (OSSL_PKEY_IS_PRIVATE(obj)) ++ return pkey; ++ /* ++ * The EVP API does not provide a way to check if the EVP_PKEY has private ++ * components. Assuming it does... ++ */ ++ if (!rb_respond_to(obj, id_private_q)) ++ return pkey; ++ if (RTEST(rb_funcallv(obj, id_private_q, 0, NULL))) ++ return pkey; + +- return pkey; ++ rb_raise(rb_eArgError, "private key is needed"); + } + + EVP_PKEY * +-- +2.32.0 + + +From 86508f74b3d41166ed6091b7b31f18a26478c347 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 20 Mar 2017 23:18:26 +0900 +Subject: [PATCH 2/6] pkey: add PKey.generate_parameters and .generate_key + +Add two methods to create a PKey using the generic EVP interface. This +is useful for the PKey types we don't have a dedicated class. +--- + ext/openssl/ossl_pkey.c | 222 ++++++++++++++++++++++++++++++++++++++ + test/openssl/test_pkey.rb | 43 ++++++++ + 2 files changed, 265 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 8d41623e80..1f3dd39b9b 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -197,6 +197,226 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) + return ossl_pkey_new(pkey); + } + ++static VALUE ++pkey_gen_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) ++{ ++ VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1); ++ EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v; ++ ++ if (SYMBOL_P(key)) ++ key = rb_sym2str(key); ++ value = rb_String(value); ++ ++ if (EVP_PKEY_CTX_ctrl_str(ctx, StringValueCStr(key), StringValueCStr(value)) <= 0) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_ctrl_str(ctx, %+"PRIsVALUE", %+"PRIsVALUE")", ++ key, value); ++ return Qnil; ++} ++ ++static VALUE ++pkey_gen_apply_options0(VALUE args_v) ++{ ++ VALUE *args = (VALUE *)args_v; ++ ++ rb_block_call(args[1], rb_intern("each"), 0, NULL, ++ pkey_gen_apply_options_i, args[0]); ++ return Qnil; ++} ++ ++struct pkey_blocking_generate_arg { ++ EVP_PKEY_CTX *ctx; ++ EVP_PKEY *pkey; ++ int state; ++ int yield: 1; ++ int genparam: 1; ++ int stop: 1; ++}; ++ ++static VALUE ++pkey_gen_cb_yield(VALUE ctx_v) ++{ ++ EVP_PKEY_CTX *ctx = (void *)ctx_v; ++ int i, info_num; ++ VALUE *argv; ++ ++ info_num = EVP_PKEY_CTX_get_keygen_info(ctx, -1); ++ argv = ALLOCA_N(VALUE, info_num); ++ for (i = 0; i < info_num; i++) ++ argv[i] = INT2NUM(EVP_PKEY_CTX_get_keygen_info(ctx, i)); ++ ++ return rb_yield_values2(info_num, argv); ++} ++ ++static int ++pkey_gen_cb(EVP_PKEY_CTX *ctx) ++{ ++ struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx); ++ ++ if (arg->yield) { ++ int state; ++ rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state); ++ if (state) { ++ arg->stop = 1; ++ arg->state = state; ++ } ++ } ++ return !arg->stop; ++} ++ ++static void ++pkey_blocking_gen_stop(void *ptr) ++{ ++ struct pkey_blocking_generate_arg *arg = ptr; ++ arg->stop = 1; ++} ++ ++static void * ++pkey_blocking_gen(void *ptr) ++{ ++ struct pkey_blocking_generate_arg *arg = ptr; ++ ++ if (arg->genparam && EVP_PKEY_paramgen(arg->ctx, &arg->pkey) <= 0) ++ return NULL; ++ if (!arg->genparam && EVP_PKEY_keygen(arg->ctx, &arg->pkey) <= 0) ++ return NULL; ++ return arg->pkey; ++} ++ ++static VALUE ++pkey_generate(int argc, VALUE *argv, VALUE self, int genparam) ++{ ++ EVP_PKEY_CTX *ctx; ++ VALUE alg, options; ++ struct pkey_blocking_generate_arg gen_arg = { 0 }; ++ int state; ++ ++ rb_scan_args(argc, argv, "11", &alg, &options); ++ if (rb_obj_is_kind_of(alg, cPKey)) { ++ EVP_PKEY *base_pkey; ++ ++ GetPKey(alg, base_pkey); ++ ctx = EVP_PKEY_CTX_new(base_pkey, NULL/* engine */); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ } ++ else { ++ const EVP_PKEY_ASN1_METHOD *ameth; ++ ENGINE *tmpeng; ++ int pkey_id; ++ ++ StringValue(alg); ++ ameth = EVP_PKEY_asn1_find_str(&tmpeng, RSTRING_PTR(alg), ++ RSTRING_LENINT(alg)); ++ if (!ameth) ++ ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", alg); ++ EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); ++#if !defined(OPENSSL_NO_ENGINE) ++ if (tmpeng) ++ ENGINE_finish(tmpeng); ++#endif ++ ++ ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id"); ++ } ++ ++ if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_paramgen_init"); ++ } ++ if (!genparam && EVP_PKEY_keygen_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_keygen_init"); ++ } ++ ++ if (!NIL_P(options)) { ++ VALUE args[2]; ++ ++ args[0] = (VALUE)ctx; ++ args[1] = options; ++ rb_protect(pkey_gen_apply_options0, (VALUE)args, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ ++ gen_arg.genparam = genparam; ++ gen_arg.ctx = ctx; ++ gen_arg.yield = rb_block_given_p(); ++ EVP_PKEY_CTX_set_app_data(ctx, &gen_arg); ++ EVP_PKEY_CTX_set_cb(ctx, pkey_gen_cb); ++ if (gen_arg.yield) ++ pkey_blocking_gen(&gen_arg); ++ else ++ rb_thread_call_without_gvl(pkey_blocking_gen, &gen_arg, ++ pkey_blocking_gen_stop, &gen_arg); ++ EVP_PKEY_CTX_free(ctx); ++ if (!gen_arg.pkey) { ++ if (gen_arg.state) { ++ ossl_clear_error(); ++ rb_jump_tag(gen_arg.state); ++ } ++ else { ++ ossl_raise(ePKeyError, genparam ? "EVP_PKEY_paramgen" : "EVP_PKEY_keygen"); ++ } ++ } ++ ++ return ossl_pkey_new(gen_arg.pkey); ++} ++ ++/* ++ * call-seq: ++ * OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey ++ * ++ * Generates new parameters for the algorithm. _algo_name_ is a String that ++ * represents the algorithm. The optional argument _options_ is a Hash that ++ * specifies the options specific to the algorithm. The order of the options ++ * can be important. ++ * ++ * A block can be passed optionally. The meaning of the arguments passed to ++ * the block varies depending on the implementation of the algorithm. The block ++ * may be called once or multiple times, or may not even be called. ++ * ++ * For the supported options, see the documentation for the 'openssl genpkey' ++ * utility command. ++ * ++ * == Example ++ * pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048) ++ * p pkey.p.num_bits #=> 2048 ++ */ ++static VALUE ++ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self) ++{ ++ return pkey_generate(argc, argv, self, 1); ++} ++ ++/* ++ * call-seq: ++ * OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey ++ * OpenSSL::PKey.generate_key(pkey [, options]) -> pkey ++ * ++ * Generates a new key (pair). ++ * ++ * If a String is given as the first argument, it generates a new random key ++ * for the algorithm specified by the name just as ::generate_parameters does. ++ * If an OpenSSL::PKey::PKey is given instead, it generates a new random key ++ * for the same algorithm as the key, using the parameters the key contains. ++ * ++ * See ::generate_parameters for the details of _options_ and the given block. ++ * ++ * == Example ++ * pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048) ++ * pkey_params.priv_key #=> nil ++ * pkey = OpenSSL::PKey.generate_key(pkey_params) ++ * pkey.priv_key #=> # 512, ++ "dsa_paramgen_q_bits" => 256, ++ }) ++ assert_instance_of OpenSSL::PKey::DSA, pkey ++ assert_equal 512, pkey.p.num_bits ++ assert_equal 256, pkey.q.num_bits ++ assert_equal nil, pkey.priv_key ++ ++ # Invalid options are checked ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ OpenSSL::PKey.generate_parameters("DSA", "invalid" => "option") ++ } ++ ++ # Parameter generation callback is called ++ cb_called = [] ++ assert_raise(RuntimeError) { ++ OpenSSL::PKey.generate_parameters("DSA") { |*args| ++ cb_called << args ++ raise "exit!" if cb_called.size == 3 ++ } ++ } ++ assert_not_empty cb_called ++ end ++ ++ def test_s_generate_key ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ # DSA key pair cannot be generated without parameters ++ OpenSSL::PKey.generate_key("DSA") ++ } ++ pkey_params = OpenSSL::PKey.generate_parameters("DSA", { ++ "dsa_paramgen_bits" => 512, ++ "dsa_paramgen_q_bits" => 256, ++ }) ++ pkey = OpenSSL::PKey.generate_key(pkey_params) ++ assert_instance_of OpenSSL::PKey::DSA, pkey ++ assert_equal 512, pkey.p.num_bits ++ assert_not_equal nil, pkey.priv_key ++ end + end +-- +2.32.0 + + +From 5713605e70c96e3215aab0e0341548af29b5088e Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 15 May 2017 23:47:47 +0900 +Subject: [PATCH 3/6] pkey: port PKey::PKey#sign and #verify to the EVP_Digest* + interface + +Use EVP_DigestSign*() and EVP_DigestVerify*() interface instead of the +old EVP_Sign*() and EVP_Verify*() functions. They were added in OpenSSL +1.0.0. + +Also, allow the digest to be specified as nil, as certain EVP_PKEY types +don't expect a digest algorithm. +--- + ext/openssl/ossl_pkey.c | 90 ++++++++++++++++++++++----------------- + test/openssl/test_pkey.rb | 12 ++++++ + 2 files changed, 63 insertions(+), 39 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 1f3dd39b9b..a0d73f5821 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -753,35 +753,47 @@ static VALUE + ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + { + EVP_PKEY *pkey; +- const EVP_MD *md; ++ const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; +- unsigned int buf_len; +- VALUE str; +- int result; ++ size_t siglen; ++ int state; ++ VALUE sig; + + pkey = GetPrivPKeyPtr(self); +- md = ossl_evp_get_digestbyname(digest); ++ if (!NIL_P(digest)) ++ md = ossl_evp_get_digestbyname(digest); + StringValue(data); +- str = rb_str_new(0, EVP_PKEY_size(pkey)); + + ctx = EVP_MD_CTX_new(); + if (!ctx) +- ossl_raise(ePKeyError, "EVP_MD_CTX_new"); +- if (!EVP_SignInit_ex(ctx, md, NULL)) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_SignInit_ex"); ++ ossl_raise(ePKeyError, "EVP_MD_CTX_new"); ++ if (EVP_DigestSignInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignInit"); ++ } ++ if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignUpdate"); ++ } ++ if (EVP_DigestSignFinal(ctx, NULL, &siglen) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignFinal"); + } +- if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_SignUpdate"); ++ if (siglen > LONG_MAX) ++ rb_raise(ePKeyError, "signature would be too large"); ++ sig = ossl_str_new(NULL, (long)siglen, &state); ++ if (state) { ++ EVP_MD_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(sig), ++ &siglen) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignFinal"); + } +- result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey); + EVP_MD_CTX_free(ctx); +- if (!result) +- ossl_raise(ePKeyError, "EVP_SignFinal"); +- rb_str_set_len(str, buf_len); +- +- return str; ++ rb_str_set_len(sig, siglen); ++ return sig; + } + + /* +@@ -809,38 +821,38 @@ static VALUE + ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + { + EVP_PKEY *pkey; +- const EVP_MD *md; ++ const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; +- int siglen, result; ++ int ret; + + GetPKey(self, pkey); + ossl_pkey_check_public_key(pkey); +- md = ossl_evp_get_digestbyname(digest); ++ if (!NIL_P(digest)) ++ md = ossl_evp_get_digestbyname(digest); + StringValue(sig); +- siglen = RSTRING_LENINT(sig); + StringValue(data); + + ctx = EVP_MD_CTX_new(); + if (!ctx) +- ossl_raise(ePKeyError, "EVP_MD_CTX_new"); +- if (!EVP_VerifyInit_ex(ctx, md, NULL)) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_VerifyInit_ex"); ++ ossl_raise(ePKeyError, "EVP_MD_CTX_new"); ++ if (EVP_DigestVerifyInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestVerifyInit"); + } +- if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_VerifyUpdate"); ++ if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate"); + } +- result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey); ++ ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), ++ RSTRING_LEN(sig)); + EVP_MD_CTX_free(ctx); +- switch (result) { +- case 0: +- ossl_clear_error(); +- return Qfalse; +- case 1: +- return Qtrue; +- default: +- ossl_raise(ePKeyError, "EVP_VerifyFinal"); ++ if (ret < 0) ++ ossl_raise(ePKeyError, "EVP_DigestVerifyFinal"); ++ if (ret) ++ return Qtrue; ++ else { ++ ossl_clear_error(); ++ return Qfalse; + } + } + +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index a325a1ea2b..247ba84f83 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -68,4 +68,16 @@ def test_s_generate_key + assert_equal 512, pkey.p.num_bits + assert_not_equal nil, pkey.priv_key + end ++ ++ def test_hmac_sign_verify ++ pkey = OpenSSL::PKey.generate_key("HMAC", { "key" => "abcd" }) ++ ++ hmac = OpenSSL::HMAC.new("abcd", "SHA256").update("data").digest ++ assert_equal hmac, pkey.sign("SHA256", "data") ++ ++ # EVP_PKEY_HMAC does not support verify ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ pkey.verify("SHA256", "data", hmac) ++ } ++ end + end +-- +2.32.0 + + +From 76566a2e1bab42a2e1587ecbec23779ee00020fc Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 15 May 2017 23:47:47 +0900 +Subject: [PATCH 4/6] pkey: support 'one-shot' signing and verification + +OpenSSL 1.1.1 added EVP_DigestSign() and EVP_DigestVerify() functions +to the interface. Some EVP_PKEY methods such as PureEdDSA algorithms +do not support the streaming mechanism and require us to use them. +--- + ext/openssl/ossl_pkey.c | 30 ++++++++++++++++++++++++++ + test/openssl/test_pkey.rb | 45 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 75 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index a0d73f5821..19544ec7f0 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -771,6 +771,26 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignInit"); + } ++#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER) ++ if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSign"); ++ } ++ if (siglen > LONG_MAX) ++ rb_raise(ePKeyError, "signature would be too large"); ++ sig = ossl_str_new(NULL, (long)siglen, &state); ++ if (state) { ++ EVP_MD_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSign"); ++ } ++#else + if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignUpdate"); +@@ -791,6 +811,7 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignFinal"); + } ++#endif + EVP_MD_CTX_free(ctx); + rb_str_set_len(sig, siglen); + return sig; +@@ -839,6 +860,14 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestVerifyInit"); + } ++#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER) ++ ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig), ++ RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)); ++ EVP_MD_CTX_free(ctx); ++ if (ret < 0) ++ ossl_raise(ePKeyError, "EVP_DigestVerify"); ++#else + if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate"); +@@ -848,6 +877,7 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + EVP_MD_CTX_free(ctx); + if (ret < 0) + ossl_raise(ePKeyError, "EVP_DigestVerifyFinal"); ++#endif + if (ret) + return Qtrue; + else { +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index 247ba84f83..d811b9c75f 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -80,4 +80,49 @@ def test_hmac_sign_verify + pkey.verify("SHA256", "data", hmac) + } + end ++ ++ def test_ed25519 ++ # Test vector from RFC 8032 Section 7.1 TEST 2 ++ priv_pem = <<~EOF ++ -----BEGIN PRIVATE KEY----- ++ MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 ++ -----END PRIVATE KEY----- ++ EOF ++ pub_pem = <<~EOF ++ -----BEGIN PUBLIC KEY----- ++ MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= ++ -----END PUBLIC KEY----- ++ EOF ++ begin ++ priv = OpenSSL::PKey.read(priv_pem) ++ pub = OpenSSL::PKey.read(pub_pem) ++ rescue OpenSSL::PKey::PKeyError ++ # OpenSSL < 1.1.1 ++ pend "Ed25519 is not implemented" ++ end ++ assert_instance_of OpenSSL::PKey::PKey, priv ++ assert_instance_of OpenSSL::PKey::PKey, pub ++ assert_equal priv_pem, priv.private_to_pem ++ assert_equal pub_pem, priv.public_to_pem ++ assert_equal pub_pem, pub.public_to_pem ++ ++ sig = [<<~EOF.gsub(/[^0-9a-f]/, "")].pack("H*") ++ 92a009a9f0d4cab8720e820b5f642540 ++ a2b27b5416503f8fb3762223ebdb69da ++ 085ac1e43e15996e458f3613d0f11d8c ++ 387b2eaeb4302aeeb00d291612bb0c00 ++ EOF ++ data = ["72"].pack("H*") ++ assert_equal sig, priv.sign(nil, data) ++ assert_equal true, priv.verify(nil, sig, data) ++ assert_equal true, pub.verify(nil, sig, data) ++ assert_equal false, pub.verify(nil, sig, data.succ) ++ ++ # PureEdDSA wants nil as the message digest ++ assert_raise(OpenSSL::PKey::PKeyError) { priv.sign("SHA512", data) } ++ assert_raise(OpenSSL::PKey::PKeyError) { pub.verify("SHA512", sig, data) } ++ ++ # Ed25519 pkey type does not support key derivation ++ assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) } ++ end + end +-- +2.32.0 + + +From fabdd22bddc572ba3342ec0b09e3fef8ed6245b8 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 18 Mar 2017 21:58:46 +0900 +Subject: [PATCH 5/6] pkey: add PKey::PKey#derive + +Add OpenSSL::PKey::PKey#derive as the wrapper for EVP_PKEY_CTX_derive(). +This is useful for pkey types that we don't have dedicated classes, such +as X25519. +--- + ext/openssl/ossl_pkey.c | 52 ++++++++++++++++++++++++++++++++++++ + test/openssl/test_pkey.rb | 26 ++++++++++++++++++ + test/openssl/test_pkey_dh.rb | 13 +++++++++ + test/openssl/test_pkey_ec.rb | 16 +++++++++++ + 4 files changed, 107 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 19544ec7f0..df8b425a0f 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -886,6 +886,57 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + } + } + ++/* ++ * call-seq: ++ * pkey.derive(peer_pkey) -> string ++ * ++ * Derives a shared secret from _pkey_ and _peer_pkey_. _pkey_ must contain ++ * the private components, _peer_pkey_ must contain the public components. ++ */ ++static VALUE ++ossl_pkey_derive(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey, *peer_pkey; ++ EVP_PKEY_CTX *ctx; ++ VALUE peer_pkey_obj, str; ++ size_t keylen; ++ int state; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "1", &peer_pkey_obj); ++ GetPKey(peer_pkey_obj, peer_pkey); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_derive_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive_init"); ++ } ++ if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer"); ++ } ++ if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive"); ++ } ++ if (keylen > LONG_MAX) ++ rb_raise(ePKeyError, "derived key would be too large"); ++ str = ossl_str_new(NULL, (long)keylen, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive"); ++ } ++ EVP_PKEY_CTX_free(ctx); ++ rb_str_set_len(str, keylen); ++ return str; ++} ++ + /* + * INIT + */ +@@ -983,6 +1034,7 @@ Init_ossl_pkey(void) + + rb_define_method(cPKey, "sign", ossl_pkey_sign, 2); + rb_define_method(cPKey, "verify", ossl_pkey_verify, 3); ++ rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); + + id_private_q = rb_intern("private?"); + +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index d811b9c75f..5307fe5b08 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -125,4 +125,30 @@ def test_ed25519 + # Ed25519 pkey type does not support key derivation + assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) } + end ++ ++ def test_x25519 ++ # Test vector from RFC 7748 Section 6.1 ++ alice_pem = <<~EOF ++ -----BEGIN PRIVATE KEY----- ++ MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq ++ -----END PRIVATE KEY----- ++ EOF ++ bob_pem = <<~EOF ++ -----BEGIN PUBLIC KEY----- ++ MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08= ++ -----END PUBLIC KEY----- ++ EOF ++ shared_secret = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" ++ begin ++ alice = OpenSSL::PKey.read(alice_pem) ++ bob = OpenSSL::PKey.read(bob_pem) ++ rescue OpenSSL::PKey::PKeyError ++ # OpenSSL < 1.1.0 ++ pend "X25519 is not implemented" ++ end ++ assert_instance_of OpenSSL::PKey::PKey, alice ++ assert_equal alice_pem, alice.private_to_pem ++ assert_equal bob_pem, bob.public_to_pem ++ assert_equal [shared_secret].pack("H*"), alice.derive(bob) ++ end + end +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index 4a05626a12..9efc3ba68d 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -18,6 +18,19 @@ def test_new_break + end + end + ++ def test_derive_key ++ dh1 = Fixtures.pkey("dh1024").generate_key! ++ dh2 = Fixtures.pkey("dh1024").generate_key! ++ dh1_pub = OpenSSL::PKey.read(dh1.public_to_der) ++ dh2_pub = OpenSSL::PKey.read(dh2.public_to_der) ++ z = dh1.g.mod_exp(dh1.priv_key, dh1.p).mod_exp(dh2.priv_key, dh1.p).to_s(2) ++ assert_equal z, dh1.derive(dh2_pub) ++ assert_equal z, dh2.derive(dh1_pub) ++ ++ assert_equal z, dh1.compute_key(dh2.pub_key) ++ assert_equal z, dh2.compute_key(dh1.pub_key) ++ end ++ + def test_DHparams + dh1024 = Fixtures.pkey("dh1024") + asn1 = OpenSSL::ASN1::Sequence([ +diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb +index a0e6a23ff8..95d4338a51 100644 +--- a/test/openssl/test_pkey_ec.rb ++++ b/test/openssl/test_pkey_ec.rb +@@ -93,6 +93,22 @@ def test_sign_verify + assert_equal false, p256.verify("SHA256", signature1, data) + end + ++ def test_derive_key ++ # NIST CAVP, KAS_ECC_CDH_PrimitiveTest.txt, P-256 COUNT = 0 ++ qCAVSx = "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" ++ qCAVSy = "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac" ++ dIUT = "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534" ++ zIUT = "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b" ++ a = OpenSSL::PKey::EC.new("prime256v1") ++ a.private_key = OpenSSL::BN.new(dIUT, 16) ++ b = OpenSSL::PKey::EC.new("prime256v1") ++ uncompressed = OpenSSL::BN.new("04" + qCAVSx + qCAVSy, 16) ++ b.public_key = OpenSSL::PKey::EC::Point.new(b.group, uncompressed) ++ assert_equal [zIUT].pack("H*"), a.derive(b) ++ ++ assert_equal a.derive(b), a.dh_compute_key(b.public_key) ++ end ++ + def test_dsa_sign_verify + data1 = "foo" + data2 = "bar" +-- +2.32.0 + + +From 97078c7fa8a724c7c71f9850d31fc401239da228 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 18 Mar 2017 22:34:19 +0900 +Subject: [PATCH 6/6] pkey: reimplement PKey::DH#compute_key and + PKey::EC#dh_compute_key + +Use the new OpenSSL::PKey::PKey#derive instead of the raw +{EC,}DH_compute_key(), mainly to reduce amount of the C code. +--- + ext/openssl/lib/openssl/pkey.rb | 33 +++++++++++++++++++++++++++++++ + ext/openssl/ossl_pkey_dh.c | 35 --------------------------------- + ext/openssl/ossl_pkey_ec.c | 32 ------------------------------ + 3 files changed, 33 insertions(+), 67 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 9cc3276356..be60ac2beb 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -9,6 +9,24 @@ + module OpenSSL::PKey + class DH + include OpenSSL::Marshal ++ ++ # :call-seq: ++ # dh.compute_key(pub_bn) -> string ++ # ++ # Returns a String containing a shared secret computed from the other ++ # party's public value. ++ # ++ # This method is provided for backwards compatibility, and calls #derive ++ # internally. ++ # ++ # === Parameters ++ # * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by ++ # DH#public_key as that contains the DH parameters only. ++ def compute_key(pub_bn) ++ peer = dup ++ peer.set_key(pub_bn, nil) ++ derive(peer) ++ end + end + + class DSA +@@ -18,7 +36,22 @@ class DSA + if defined?(EC) + class EC + include OpenSSL::Marshal ++ ++ # :call-seq: ++ # ec.dh_compute_key(pubkey) -> string ++ # ++ # Derives a shared secret by ECDH. _pubkey_ must be an instance of ++ # OpenSSL::PKey::EC::Point and must belong to the same group. ++ # ++ # This method is provided for backwards compatibility, and calls #derive ++ # internally. ++ def dh_compute_key(pubkey) ++ peer = OpenSSL::PKey::EC.new(group) ++ peer.public_key = pubkey ++ derive(peer) ++ end + end ++ + class EC::Point + # :call-seq: + # point.to_bn([conversion_form]) -> OpenSSL::BN +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index bc50e5566b..5bc1c49ca1 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -476,40 +476,6 @@ ossl_dh_generate_key(VALUE self) + return self; + } + +-/* +- * call-seq: +- * dh.compute_key(pub_bn) -> aString +- * +- * Returns a String containing a shared secret computed from the other party's public value. +- * See DH_compute_key() for further information. +- * +- * === Parameters +- * * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by +- * DH#public_key as that contains the DH parameters only. +- */ +-static VALUE +-ossl_dh_compute_key(VALUE self, VALUE pub) +-{ +- DH *dh; +- const BIGNUM *pub_key, *dh_p; +- VALUE str; +- int len; +- +- GetDH(self, dh); +- DH_get0_pqg(dh, &dh_p, NULL, NULL); +- if (!dh_p) +- ossl_raise(eDHError, "incomplete DH"); +- pub_key = GetBNPtr(pub); +- len = DH_size(dh); +- str = rb_str_new(0, len); +- if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) { +- ossl_raise(eDHError, NULL); +- } +- rb_str_set_len(str, len); +- +- return str; +-} +- + /* + * Document-method: OpenSSL::PKey::DH#set_pqg + * call-seq: +@@ -587,7 +553,6 @@ Init_ossl_dh(void) + rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0); + rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0); + rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0); +- rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1); + + DEF_OSSL_PKEY_BN(cDH, dh, p); + DEF_OSSL_PKEY_BN(cDH, dh, q); +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index 6fe2533e2a..c2534251c3 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -487,37 +487,6 @@ static VALUE ossl_ec_key_check_key(VALUE self) + return Qtrue; + } + +-/* +- * call-seq: +- * key.dh_compute_key(pubkey) => String +- * +- * See the OpenSSL documentation for ECDH_compute_key() +- */ +-static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey) +-{ +- EC_KEY *ec; +- EC_POINT *point; +- int buf_len; +- VALUE str; +- +- GetEC(self, ec); +- GetECPoint(pubkey, point); +- +-/* BUG: need a way to figure out the maximum string size */ +- buf_len = 1024; +- str = rb_str_new(0, buf_len); +-/* BUG: take KDF as a block */ +- buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL); +- if (buf_len < 0) +- ossl_raise(eECError, "ECDH_compute_key"); +- +- rb_str_resize(str, buf_len); +- +- return str; +-} +- +-/* sign_setup */ +- + /* + * call-seq: + * key.dsa_sign_asn1(data) => String +@@ -1657,7 +1626,6 @@ void Init_ossl_ec(void) + rb_define_alias(cEC, "generate_key", "generate_key!"); + rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0); + +- rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1); + rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1); + rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2); + /* do_sign/do_verify */ +-- +2.32.0 + diff --git a/ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.patch b/ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.patch new file mode 100644 index 0000000..33789b4 --- /dev/null +++ b/ruby-3.1.0-Allocate-EVP_PKEY-on-initialize.patch @@ -0,0 +1,630 @@ +From 316cb2a41f154e4663d7e7fead60cfc0bfa86af9 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 12 Apr 2021 13:55:10 +0900 +Subject: [PATCH 1/2] pkey: do not check NULL argument in ossl_pkey_new() + +Passing NULL to ossl_pkey_new() makes no sense in the first place, and +in fact it is ensured not to be NULL in all cases. +--- + ext/openssl/ossl_pkey.c | 6 +----- + ext/openssl/ossl_pkey.h | 1 + + 2 files changed, 2 insertions(+), 5 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index f9f5162e..820e4a2c 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -38,12 +38,8 @@ static VALUE + pkey_new0(EVP_PKEY *pkey) + { + VALUE klass, obj; +- int type; + +- if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE) +- ossl_raise(rb_eRuntimeError, "pkey is empty"); +- +- switch (type) { ++ switch (EVP_PKEY_base_id(pkey)) { + #if !defined(OPENSSL_NO_RSA) + case EVP_PKEY_RSA: klass = cRSA; break; + #endif +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index 4beede22..f0476780 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -35,6 +35,7 @@ extern const rb_data_type_t ossl_evp_pkey_type; + } \ + } while (0) + ++/* Takes ownership of the EVP_PKEY */ + VALUE ossl_pkey_new(EVP_PKEY *); + void ossl_pkey_check_public_key(const EVP_PKEY *); + EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE); + +From 74f6c6175688502a5bf27ae35367616858630c0f Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 12 Apr 2021 18:32:40 +0900 +Subject: [PATCH 2/2] pkey: allocate EVP_PKEY on #initialize + +Allocate an EVP_PKEY when the content is ready: when #initialize +or #initialize_copy is called, rather than when a T_DATA is allocated. +This is more natural because the lower level API has been deprecated +and an EVP_PKEY is becoming the minimum unit of handling keys. +--- + ext/openssl/ossl_pkey.c | 15 ++---- + ext/openssl/ossl_pkey.h | 15 ++---- + ext/openssl/ossl_pkey_dh.c | 71 +++++++++++++++++++-------- + ext/openssl/ossl_pkey_dsa.c | 93 ++++++++++++++++++++--------------- + ext/openssl/ossl_pkey_ec.c | 91 +++++++++++++++++++---------------- + ext/openssl/ossl_pkey_rsa.c | 96 ++++++++++++++++++++++--------------- + 6 files changed, 218 insertions(+), 163 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 820e4a2c..ea75d63f 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -54,8 +54,8 @@ pkey_new0(EVP_PKEY *pkey) + #endif + default: klass = cPKey; break; + } +- obj = NewPKey(klass); +- SetPKey(obj, pkey); ++ obj = rb_obj_alloc(klass); ++ RTYPEDDATA_DATA(obj) = pkey; + return obj; + } + +@@ -511,16 +511,7 @@ DupPKeyPtr(VALUE obj) + static VALUE + ossl_pkey_alloc(VALUE klass) + { +- EVP_PKEY *pkey; +- VALUE obj; +- +- obj = NewPKey(klass); +- if (!(pkey = EVP_PKEY_new())) { +- ossl_raise(ePKeyError, NULL); +- } +- SetPKey(obj, pkey); +- +- return obj; ++ return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL); + } + + /* +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index f0476780..ed18bc69 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -15,19 +15,10 @@ extern VALUE cPKey; + extern VALUE ePKeyError; + extern const rb_data_type_t ossl_evp_pkey_type; + +-#define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue) +-#define OSSL_PKEY_SET_PUBLIC(obj) rb_iv_set((obj), "private", Qfalse) +-#define OSSL_PKEY_IS_PRIVATE(obj) (rb_iv_get((obj), "private") == Qtrue) ++/* For ENGINE */ ++#define OSSL_PKEY_SET_PRIVATE(obj) rb_ivar_set((obj), rb_intern("private"), Qtrue) ++#define OSSL_PKEY_IS_PRIVATE(obj) (rb_attr_get((obj), rb_intern("private")) == Qtrue) + +-#define NewPKey(klass) \ +- TypedData_Wrap_Struct((klass), &ossl_evp_pkey_type, 0) +-#define SetPKey(obj, pkey) do { \ +- if (!(pkey)) { \ +- rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \ +- } \ +- RTYPEDDATA_DATA(obj) = (pkey); \ +- OSSL_PKEY_SET_PUBLIC(obj); \ +-} while (0) + #define GetPKey(obj, pkey) do {\ + TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \ + if (!(pkey)) { \ +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index ca782bbe..04c11b21 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -72,34 +72,57 @@ static VALUE + ossl_dh_initialize(int argc, VALUE *argv, VALUE self) + { + EVP_PKEY *pkey; ++ int type; + DH *dh; +- BIO *in; ++ BIO *in = NULL; + VALUE arg; + +- GetPKey(self, pkey); ++ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); ++ + /* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */ + if (rb_scan_args(argc, argv, "01", &arg) == 0) { + dh = DH_new(); + if (!dh) + ossl_raise(eDHError, "DH_new"); ++ goto legacy; + } +- else { +- arg = ossl_to_der_if_possible(arg); +- in = ossl_obj2bio(&arg); +- dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); +- if (!dh){ +- OSSL_BIO_reset(in); +- dh = d2i_DHparams_bio(in, NULL); +- } +- BIO_free(in); +- if (!dh) { +- ossl_raise(eDHError, NULL); +- } ++ ++ arg = ossl_to_der_if_possible(arg); ++ in = ossl_obj2bio(&arg); ++ ++ /* ++ * On OpenSSL <= 1.1.1 and current versions of LibreSSL, the generic ++ * routine does not support DER-encoded parameters ++ */ ++ dh = d2i_DHparams_bio(in, NULL); ++ if (dh) ++ goto legacy; ++ OSSL_BIO_reset(in); ++ ++ pkey = ossl_pkey_read_generic(in, Qnil); ++ BIO_free(in); ++ if (!pkey) ++ ossl_raise(eDHError, "could not parse pkey"); ++ ++ type = EVP_PKEY_base_id(pkey); ++ if (type != EVP_PKEY_DH) { ++ EVP_PKEY_free(pkey); ++ rb_raise(eDHError, "incorrect pkey type: %s", OBJ_nid2sn(type)); + } +- if (!EVP_PKEY_assign_DH(pkey, dh)) { +- DH_free(dh); +- ossl_raise(eDHError, NULL); ++ RTYPEDDATA_DATA(self) = pkey; ++ return self; ++ ++ legacy: ++ BIO_free(in); ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) { ++ EVP_PKEY_free(pkey); ++ DH_free(dh); ++ ossl_raise(eDHError, "EVP_PKEY_assign_DH"); + } ++ RTYPEDDATA_DATA(self) = pkey; + return self; + } + +@@ -110,15 +133,14 @@ ossl_dh_initialize_copy(VALUE self, VALUE other) + DH *dh, *dh_other; + const BIGNUM *pub, *priv; + +- GetPKey(self, pkey); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) +- ossl_raise(eDHError, "DH already initialized"); ++ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + GetDH(other, dh_other); + + dh = DHparams_dup(dh_other); + if (!dh) + ossl_raise(eDHError, "DHparams_dup"); +- EVP_PKEY_assign_DH(pkey, dh); + + DH_get0_key(dh_other, &pub, &priv); + if (pub) { +@@ -133,6 +155,13 @@ ossl_dh_initialize_copy(VALUE self, VALUE other) + DH_set0_key(dh, pub2, priv2); + } + ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) { ++ EVP_PKEY_free(pkey); ++ DH_free(dh); ++ ossl_raise(eDHError, "EVP_PKEY_assign_DH"); ++ } ++ RTYPEDDATA_DATA(self) = pkey; + return self; + } + +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index 7af00eeb..15724548 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -83,50 +83,59 @@ VALUE eDSAError; + static VALUE + ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) + { +- EVP_PKEY *pkey, *tmp; +- DSA *dsa = NULL; +- BIO *in; ++ EVP_PKEY *pkey; ++ DSA *dsa; ++ BIO *in = NULL; + VALUE arg, pass; ++ int type; ++ ++ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + +- GetPKey(self, pkey); + /* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ + rb_scan_args(argc, argv, "02", &arg, &pass); + if (argc == 0) { + dsa = DSA_new(); + if (!dsa) + ossl_raise(eDSAError, "DSA_new"); ++ goto legacy; + } +- else { +- pass = ossl_pem_passwd_value(pass); +- arg = ossl_to_der_if_possible(arg); +- in = ossl_obj2bio(&arg); +- +- tmp = ossl_pkey_read_generic(in, pass); +- if (tmp) { +- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_DSA) +- rb_raise(eDSAError, "incorrect pkey type: %s", +- OBJ_nid2sn(EVP_PKEY_base_id(tmp))); +- dsa = EVP_PKEY_get1_DSA(tmp); +- EVP_PKEY_free(tmp); +- } +- if (!dsa) { +- OSSL_BIO_reset(in); +-#define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \ +- (d2i_of_void *)d2i_DSAPublicKey, PEM_STRING_DSA_PUBLIC, (bp), (void **)(x), (cb), (u)) +- dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL); +-#undef PEM_read_bio_DSAPublicKey +- } +- BIO_free(in); +- if (!dsa) { +- ossl_clear_error(); +- ossl_raise(eDSAError, "Neither PUB key nor PRIV key"); +- } +- } +- if (!EVP_PKEY_assign_DSA(pkey, dsa)) { +- DSA_free(dsa); +- ossl_raise(eDSAError, NULL); ++ ++ pass = ossl_pem_passwd_value(pass); ++ arg = ossl_to_der_if_possible(arg); ++ in = ossl_obj2bio(&arg); ++ ++ /* DER-encoded DSAPublicKey format isn't supported by the generic routine */ ++ dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey, ++ PEM_STRING_DSA_PUBLIC, ++ in, NULL, NULL, NULL); ++ if (dsa) ++ goto legacy; ++ OSSL_BIO_reset(in); ++ ++ pkey = ossl_pkey_read_generic(in, pass); ++ BIO_free(in); ++ if (!pkey) ++ ossl_raise(eDSAError, "Neither PUB key nor PRIV key"); ++ ++ type = EVP_PKEY_base_id(pkey); ++ if (type != EVP_PKEY_DSA) { ++ EVP_PKEY_free(pkey); ++ rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type)); + } ++ RTYPEDDATA_DATA(self) = pkey; ++ return self; + ++ legacy: ++ BIO_free(in); ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) { ++ EVP_PKEY_free(pkey); ++ DSA_free(dsa); ++ ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); ++ } ++ RTYPEDDATA_DATA(self) = pkey; + return self; + } + +@@ -136,16 +145,24 @@ ossl_dsa_initialize_copy(VALUE self, VALUE other) + EVP_PKEY *pkey; + DSA *dsa, *dsa_new; + +- GetPKey(self, pkey); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) +- ossl_raise(eDSAError, "DSA already initialized"); ++ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + GetDSA(other, dsa); + +- dsa_new = ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, (d2i_of_void *)d2i_DSAPrivateKey, (char *)dsa); ++ dsa_new = (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, ++ (d2i_of_void *)d2i_DSAPrivateKey, ++ (char *)dsa); + if (!dsa_new) + ossl_raise(eDSAError, "ASN1_dup"); + +- EVP_PKEY_assign_DSA(pkey, dsa_new); ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) { ++ EVP_PKEY_free(pkey); ++ DSA_free(dsa_new); ++ ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); ++ } ++ RTYPEDDATA_DATA(self) = pkey; + + return self; + } +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index db80d112..71e63969 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -114,13 +114,16 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg) + VALUE obj; + + obj = rb_obj_alloc(klass); +- GetPKey(obj, pkey); + + ec = ec_key_new_from_group(arg); +- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) { ++ EVP_PKEY_free(pkey); + EC_KEY_free(ec); + ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); + } ++ RTYPEDDATA_DATA(obj) = pkey; ++ + if (!EC_KEY_generate_key(ec)) + ossl_raise(eECError, "EC_KEY_generate_key"); + +@@ -141,51 +144,54 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg) + static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) + { + EVP_PKEY *pkey; +- EC_KEY *ec = NULL; ++ EC_KEY *ec; ++ BIO *in; + VALUE arg, pass; ++ int type; + +- GetPKey(self, pkey); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) +- ossl_raise(eECError, "EC_KEY already initialized"); ++ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + + rb_scan_args(argc, argv, "02", &arg, &pass); +- + if (NIL_P(arg)) { + if (!(ec = EC_KEY_new())) +- ossl_raise(eECError, NULL); +- } else if (rb_obj_is_kind_of(arg, cEC)) { +- EC_KEY *other_ec = NULL; ++ ossl_raise(eECError, "EC_KEY_new"); ++ goto legacy; ++ } ++ else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { ++ ec = ec_key_new_from_group(arg); ++ goto legacy; ++ } + +- GetEC(arg, other_ec); +- if (!(ec = EC_KEY_dup(other_ec))) +- ossl_raise(eECError, NULL); +- } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { +- ec = ec_key_new_from_group(arg); +- } else { +- BIO *in = ossl_obj2bio(&arg); +- EVP_PKEY *tmp; +- pass = ossl_pem_passwd_value(pass); +- tmp = ossl_pkey_read_generic(in, pass); +- if (tmp) { +- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_EC) +- rb_raise(eECError, "incorrect pkey type: %s", +- OBJ_nid2sn(EVP_PKEY_base_id(tmp))); +- ec = EVP_PKEY_get1_EC_KEY(tmp); +- EVP_PKEY_free(tmp); +- } +- BIO_free(in); ++ pass = ossl_pem_passwd_value(pass); ++ arg = ossl_to_der_if_possible(arg); ++ in = ossl_obj2bio(&arg); + +- if (!ec) { +- ossl_clear_error(); +- ec = ec_key_new_from_group(arg); +- } ++ pkey = ossl_pkey_read_generic(in, pass); ++ BIO_free(in); ++ if (!pkey) { ++ ossl_clear_error(); ++ ec = ec_key_new_from_group(arg); ++ goto legacy; + } + +- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { +- EC_KEY_free(ec); +- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); ++ type = EVP_PKEY_base_id(pkey); ++ if (type != EVP_PKEY_EC) { ++ EVP_PKEY_free(pkey); ++ rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type)); + } ++ RTYPEDDATA_DATA(self) = pkey; ++ return self; + ++ legacy: ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) { ++ EVP_PKEY_free(pkey); ++ EC_KEY_free(ec); ++ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); ++ } ++ RTYPEDDATA_DATA(self) = pkey; + return self; + } + +@@ -195,18 +201,21 @@ ossl_ec_key_initialize_copy(VALUE self, VALUE other) + EVP_PKEY *pkey; + EC_KEY *ec, *ec_new; + +- GetPKey(self, pkey); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) +- ossl_raise(eECError, "EC already initialized"); ++ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + GetEC(other, ec); + + ec_new = EC_KEY_dup(ec); + if (!ec_new) + ossl_raise(eECError, "EC_KEY_dup"); +- if (!EVP_PKEY_assign_EC_KEY(pkey, ec_new)) { +- EC_KEY_free(ec_new); +- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); ++ ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_new) != 1) { ++ EC_KEY_free(ec_new); ++ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); + } ++ RTYPEDDATA_DATA(self) = pkey; + + return self; + } +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 8ebd3ec5..b8dbc0e1 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -76,51 +76,62 @@ VALUE eRSAError; + static VALUE + ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + { +- EVP_PKEY *pkey, *tmp; +- RSA *rsa = NULL; +- BIO *in; ++ EVP_PKEY *pkey; ++ RSA *rsa; ++ BIO *in = NULL; + VALUE arg, pass; ++ int type; ++ ++ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + +- GetPKey(self, pkey); + /* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ + rb_scan_args(argc, argv, "02", &arg, &pass); + if (argc == 0) { + rsa = RSA_new(); + if (!rsa) + ossl_raise(eRSAError, "RSA_new"); ++ goto legacy; + } +- else { +- pass = ossl_pem_passwd_value(pass); +- arg = ossl_to_der_if_possible(arg); +- in = ossl_obj2bio(&arg); +- +- tmp = ossl_pkey_read_generic(in, pass); +- if (tmp) { +- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_RSA) +- rb_raise(eRSAError, "incorrect pkey type: %s", +- OBJ_nid2sn(EVP_PKEY_base_id(tmp))); +- rsa = EVP_PKEY_get1_RSA(tmp); +- EVP_PKEY_free(tmp); +- } +- if (!rsa) { +- OSSL_BIO_reset(in); +- rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); +- } +- if (!rsa) { +- OSSL_BIO_reset(in); +- rsa = d2i_RSAPublicKey_bio(in, NULL); +- } +- BIO_free(in); +- if (!rsa) { +- ossl_clear_error(); +- ossl_raise(eRSAError, "Neither PUB key nor PRIV key"); +- } +- } +- if (!EVP_PKEY_assign_RSA(pkey, rsa)) { +- RSA_free(rsa); +- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); ++ ++ pass = ossl_pem_passwd_value(pass); ++ arg = ossl_to_der_if_possible(arg); ++ in = ossl_obj2bio(&arg); ++ ++ /* First try RSAPublicKey format */ ++ rsa = d2i_RSAPublicKey_bio(in, NULL); ++ if (rsa) ++ goto legacy; ++ OSSL_BIO_reset(in); ++ rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); ++ if (rsa) ++ goto legacy; ++ OSSL_BIO_reset(in); ++ ++ /* Use the generic routine */ ++ pkey = ossl_pkey_read_generic(in, pass); ++ BIO_free(in); ++ if (!pkey) ++ ossl_raise(eRSAError, "Neither PUB key nor PRIV key"); ++ ++ type = EVP_PKEY_base_id(pkey); ++ if (type != EVP_PKEY_RSA) { ++ EVP_PKEY_free(pkey); ++ rb_raise(eRSAError, "incorrect pkey type: %s", OBJ_nid2sn(type)); + } ++ RTYPEDDATA_DATA(self) = pkey; ++ return self; + ++ legacy: ++ BIO_free(in); ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa) != 1) { ++ EVP_PKEY_free(pkey); ++ RSA_free(rsa); ++ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); ++ } ++ RTYPEDDATA_DATA(self) = pkey; + return self; + } + +@@ -130,16 +141,23 @@ ossl_rsa_initialize_copy(VALUE self, VALUE other) + EVP_PKEY *pkey; + RSA *rsa, *rsa_new; + +- GetPKey(self, pkey); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) +- ossl_raise(eRSAError, "RSA already initialized"); ++ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + GetRSA(other, rsa); + +- rsa_new = ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey, (d2i_of_void *)d2i_RSAPrivateKey, (char *)rsa); ++ rsa_new = (RSA *)ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey, ++ (d2i_of_void *)d2i_RSAPrivateKey, ++ (char *)rsa); + if (!rsa_new) + ossl_raise(eRSAError, "ASN1_dup"); + +- EVP_PKEY_assign_RSA(pkey, rsa_new); ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa_new) != 1) { ++ RSA_free(rsa_new); ++ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); ++ } ++ RTYPEDDATA_DATA(self) = pkey; + + return self; + } + diff --git a/ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch b/ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch new file mode 100644 index 0000000..679411a --- /dev/null +++ b/ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch @@ -0,0 +1,358 @@ +From f2cf3afc6fa1e13e960f732c0bc658ad408ee219 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 12 Jun 2020 14:12:59 +0900 +Subject: [PATCH 1/3] pkey: fix potential memory leak in PKey#sign + +Fix potential leak of EVP_MD_CTX object in an error path. This path is +normally unreachable, since the size of a signature generated by any +supported algorithms would not be larger than LONG_MAX. +--- + ext/openssl/ossl_pkey.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index df8b425a0f..7488190e0e 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -777,8 +777,10 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSign"); + } +- if (siglen > LONG_MAX) ++ if (siglen > LONG_MAX) { ++ EVP_MD_CTX_free(ctx); + rb_raise(ePKeyError, "signature would be too large"); ++ } + sig = ossl_str_new(NULL, (long)siglen, &state); + if (state) { + EVP_MD_CTX_free(ctx); +@@ -799,8 +801,10 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignFinal"); + } +- if (siglen > LONG_MAX) ++ if (siglen > LONG_MAX) { ++ EVP_MD_CTX_free(ctx); + rb_raise(ePKeyError, "signature would be too large"); ++ } + sig = ossl_str_new(NULL, (long)siglen, &state); + if (state) { + EVP_MD_CTX_free(ctx); +-- +2.32.0 + + +From 8b30ce20eb9e03180c28288e29a96308e594f860 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 2 Apr 2021 23:58:48 +0900 +Subject: [PATCH 2/3] pkey: prepare pkey_ctx_apply_options() for usage by other + operations + +The routine to apply Hash to EVP_PKEY_CTX_ctrl_str() is currently used +by key generation, but it is useful for other operations too. Let's +change it to a slightly more generic name. +--- + ext/openssl/ossl_pkey.c | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 7488190e0e..fed4a2b81f 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -198,7 +198,7 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) + } + + static VALUE +-pkey_gen_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) ++pkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) + { + VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1); + EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v; +@@ -214,15 +214,25 @@ pkey_gen_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) + } + + static VALUE +-pkey_gen_apply_options0(VALUE args_v) ++pkey_ctx_apply_options0(VALUE args_v) + { + VALUE *args = (VALUE *)args_v; + + rb_block_call(args[1], rb_intern("each"), 0, NULL, +- pkey_gen_apply_options_i, args[0]); ++ pkey_ctx_apply_options_i, args[0]); + return Qnil; + } + ++static void ++pkey_ctx_apply_options(EVP_PKEY_CTX *ctx, VALUE options, int *state) ++{ ++ VALUE args[2]; ++ args[0] = (VALUE)ctx; ++ args[1] = options; ++ ++ rb_protect(pkey_ctx_apply_options0, (VALUE)args, state); ++} ++ + struct pkey_blocking_generate_arg { + EVP_PKEY_CTX *ctx; + EVP_PKEY *pkey; +@@ -330,11 +340,7 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam) + } + + if (!NIL_P(options)) { +- VALUE args[2]; +- +- args[0] = (VALUE)ctx; +- args[1] = options; +- rb_protect(pkey_gen_apply_options0, (VALUE)args, &state); ++ pkey_ctx_apply_options(ctx, options, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); +-- +2.32.0 + + +From 4c7b0f91da666961d11908b94520db4e09ce4e67 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 18 Jul 2020 20:40:39 +0900 +Subject: [PATCH 3/3] pkey: allow setting algorithm-specific options in #sign + and #verify + +Similarly to OpenSSL::PKey.generate_key and .generate_parameters, let +OpenSSL::PKey::PKey#sign and #verify take an optional parameter for +specifying control strings for EVP_PKEY_CTX_ctrl_str(). +--- + ext/openssl/ossl_pkey.c | 113 ++++++++++++++++++++++------------ + test/openssl/test_pkey_rsa.rb | 34 +++++----- + 2 files changed, 89 insertions(+), 58 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index fed4a2b81f..22e9f19982 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -739,33 +739,51 @@ ossl_pkey_public_to_pem(VALUE self) + } + + /* +- * call-seq: +- * pkey.sign(digest, data) -> String ++ * call-seq: ++ * pkey.sign(digest, data [, options]) -> string + * +- * To sign the String _data_, _digest_, an instance of OpenSSL::Digest, must +- * be provided. The return value is again a String containing the signature. +- * A PKeyError is raised should errors occur. +- * Any previous state of the Digest instance is irrelevant to the signature +- * outcome, the digest instance is reset to its initial state during the +- * operation. ++ * Hashes and signs the +data+ using a message digest algorithm +digest+ and ++ * a private key +pkey+. + * +- * == Example +- * data = 'Sign me!' +- * digest = OpenSSL::Digest.new('SHA256') +- * pkey = OpenSSL::PKey::RSA.new(2048) +- * signature = pkey.sign(digest, data) ++ * See #verify for the verification operation. ++ * ++ * See also the man page EVP_DigestSign(3). ++ * ++ * +digest+:: ++ * A String that represents the message digest algorithm name, or +nil+ ++ * if the PKey type requires no digest algorithm. ++ * For backwards compatibility, this can be an instance of OpenSSL::Digest. ++ * Its state will not affect the signature. ++ * +data+:: ++ * A String. The data to be hashed and signed. ++ * +options+:: ++ * A Hash that contains algorithm specific control operations to \OpenSSL. ++ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. ++ * +options+ parameter was added in version 2.3. ++ * ++ * Example: ++ * data = "Sign me!" ++ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) ++ * signopts = { rsa_padding_mode: "pss" } ++ * signature = pkey.sign("SHA256", data, signopts) ++ * ++ * # Creates a copy of the RSA key pkey, but without the private components ++ * pub_key = pkey.public_key ++ * puts pub_key.verify("SHA256", signature, data, signopts) # => true + */ + static VALUE +-ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) ++ossl_pkey_sign(int argc, VALUE *argv, VALUE self) + { + EVP_PKEY *pkey; ++ VALUE digest, data, options, sig; + const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; ++ EVP_PKEY_CTX *pctx; + size_t siglen; + int state; +- VALUE sig; + + pkey = GetPrivPKeyPtr(self); ++ rb_scan_args(argc, argv, "21", &digest, &data, &options); + if (!NIL_P(digest)) + md = ossl_evp_get_digestbyname(digest); + StringValue(data); +@@ -773,10 +791,17 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + ctx = EVP_MD_CTX_new(); + if (!ctx) + ossl_raise(ePKeyError, "EVP_MD_CTX_new"); +- if (EVP_DigestSignInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) { ++ if (EVP_DigestSignInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignInit"); + } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(pctx, options, &state); ++ if (state) { ++ EVP_MD_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } + #if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER) + if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)) < 1) { +@@ -828,35 +853,40 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + } + + /* +- * call-seq: +- * pkey.verify(digest, signature, data) -> String ++ * call-seq: ++ * pkey.verify(digest, signature, data [, options]) -> true or false + * +- * To verify the String _signature_, _digest_, an instance of +- * OpenSSL::Digest, must be provided to re-compute the message digest of the +- * original _data_, also a String. The return value is +true+ if the +- * signature is valid, +false+ otherwise. A PKeyError is raised should errors +- * occur. +- * Any previous state of the Digest instance is irrelevant to the validation +- * outcome, the digest instance is reset to its initial state during the +- * operation. ++ * Verifies the +signature+ for the +data+ using a message digest algorithm ++ * +digest+ and a public key +pkey+. + * +- * == Example +- * data = 'Sign me!' +- * digest = OpenSSL::Digest.new('SHA256') +- * pkey = OpenSSL::PKey::RSA.new(2048) +- * signature = pkey.sign(digest, data) +- * pub_key = pkey.public_key +- * puts pub_key.verify(digest, signature, data) # => true ++ * Returns +true+ if the signature is successfully verified, +false+ otherwise. ++ * The caller must check the return value. ++ * ++ * See #sign for the signing operation and an example. ++ * ++ * See also the man page EVP_DigestVerify(3). ++ * ++ * +digest+:: ++ * See #sign. ++ * +signature+:: ++ * A String containing the signature to be verified. ++ * +data+:: ++ * See #sign. ++ * +options+:: ++ * See #sign. +options+ parameter was added in version 2.3. + */ + static VALUE +-ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) ++ossl_pkey_verify(int argc, VALUE *argv, VALUE self) + { + EVP_PKEY *pkey; ++ VALUE digest, sig, data, options; + const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; +- int ret; ++ EVP_PKEY_CTX *pctx; ++ int state, ret; + + GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options); + ossl_pkey_check_public_key(pkey); + if (!NIL_P(digest)) + md = ossl_evp_get_digestbyname(digest); +@@ -866,10 +896,17 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + ctx = EVP_MD_CTX_new(); + if (!ctx) + ossl_raise(ePKeyError, "EVP_MD_CTX_new"); +- if (EVP_DigestVerifyInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) { ++ if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestVerifyInit"); + } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(pctx, options, &state); ++ if (state) { ++ EVP_MD_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } + #if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER) + ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig), + RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data), +@@ -1042,8 +1079,8 @@ Init_ossl_pkey(void) + rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0); + rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0); + +- rb_define_method(cPKey, "sign", ossl_pkey_sign, 2); +- rb_define_method(cPKey, "verify", ossl_pkey_verify, 3); ++ rb_define_method(cPKey, "sign", ossl_pkey_sign, -1); ++ rb_define_method(cPKey, "verify", ossl_pkey_verify, -1); + rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); + + id_private_q = rb_intern("private?"); +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index 88164c3b52..d1e68dbc9f 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -117,27 +117,21 @@ def test_sign_verify + assert_equal false, rsa1024.verify("SHA256", signature1, data) + end + +- def test_digest_state_irrelevant_sign ++ def test_sign_verify_options + key = Fixtures.pkey("rsa1024") +- digest1 = OpenSSL::Digest.new('SHA1') +- digest2 = OpenSSL::Digest.new('SHA1') +- data = 'Sign me!' +- digest1 << 'Change state of digest1' +- sig1 = key.sign(digest1, data) +- sig2 = key.sign(digest2, data) +- assert_equal(sig1, sig2) +- end +- +- def test_digest_state_irrelevant_verify +- key = Fixtures.pkey("rsa1024") +- digest1 = OpenSSL::Digest.new('SHA1') +- digest2 = OpenSSL::Digest.new('SHA1') +- data = 'Sign me!' +- sig = key.sign(digest1, data) +- digest1.reset +- digest1 << 'Change state of digest1' +- assert(key.verify(digest1, sig, data)) +- assert(key.verify(digest2, sig, data)) ++ data = "Sign me!" ++ pssopts = { ++ "rsa_padding_mode" => "pss", ++ "rsa_pss_saltlen" => 20, ++ "rsa_mgf1_md" => "SHA1" ++ } ++ sig_pss = key.sign("SHA256", data, pssopts) ++ assert_equal 128, sig_pss.bytesize ++ assert_equal true, key.verify("SHA256", sig_pss, data, pssopts) ++ assert_equal true, key.verify_pss("SHA256", sig_pss, data, ++ salt_length: 20, mgf1_hash: "SHA1") ++ # Defaults to PKCS #1 v1.5 padding => verification failure ++ assert_equal false, key.verify("SHA256", sig_pss, data) + end + + def test_verify_empty_rsa +-- +2.32.0 + diff --git a/ruby-3.1.0-Deprecate-PKey-set_-and-PKey-DH-EC-generate_key.patch b/ruby-3.1.0-Deprecate-PKey-set_-and-PKey-DH-EC-generate_key.patch new file mode 100644 index 0000000..d8f936e --- /dev/null +++ b/ruby-3.1.0-Deprecate-PKey-set_-and-PKey-DH-EC-generate_key.patch @@ -0,0 +1,719 @@ +From 46ca47060ca8ef3419ec36c2326a81b442d9b43b Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 12 Dec 2021 01:25:20 +0900 +Subject: [PATCH 1/5] pkey/dh: avoid using DH#set_key in DH#compute_key + +DH#set_key will not work on OpenSSL 3.0 because keys are immutable. +For now, let's reimplement DH#compute_key by manually constructing a +DER-encoded SubjectPublicKeyInfo structure and feeding it to +OpenSSL::PKey.read. + +Eventually, we should implement a new method around EVP_PKEY_fromdata() +and use it instead. +--- + ext/openssl/lib/openssl/pkey.rb | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index f6bf5892..5864faa9 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -47,9 +47,19 @@ def public_key + # * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by + # DH#public_key as that contains the DH parameters only. + def compute_key(pub_bn) +- peer = dup +- peer.set_key(pub_bn, nil) +- derive(peer) ++ # FIXME: This is constructing an X.509 SubjectPublicKeyInfo and is very ++ # inefficient ++ obj = OpenSSL::ASN1.Sequence([ ++ OpenSSL::ASN1.Sequence([ ++ OpenSSL::ASN1.ObjectId("dhKeyAgreement"), ++ OpenSSL::ASN1.Sequence([ ++ OpenSSL::ASN1.Integer(p), ++ OpenSSL::ASN1.Integer(g), ++ ]), ++ ]), ++ OpenSSL::ASN1.BitString(OpenSSL::ASN1.Integer(pub_bn).to_der), ++ ]) ++ derive(OpenSSL::PKey.read(obj.to_der)) + end + + # :call-seq: + +From fc9aabc18df3c189cc6a76a1470ca908c4f16480 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 17 Dec 2021 02:22:25 +0900 +Subject: [PATCH 2/5] pkey/ec: avoid using EC#public_key= in EC#dh_compute_key + +Similarly to DH#compute_key, work around it by constructing a +SubjectPublicKeyInfo. This should be considered as a temporary +implementation. +--- + ext/openssl/lib/openssl/pkey.rb | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 5864faa9..ba04cf4b 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -259,9 +259,14 @@ def dsa_verify_asn1(data, sig) + # This method is provided for backwards compatibility, and calls #derive + # internally. + def dh_compute_key(pubkey) +- peer = OpenSSL::PKey::EC.new(group) +- peer.public_key = pubkey +- derive(peer) ++ obj = OpenSSL::ASN1.Sequence([ ++ OpenSSL::ASN1.Sequence([ ++ OpenSSL::ASN1.ObjectId("id-ecPublicKey"), ++ group.to_der, ++ ]), ++ OpenSSL::ASN1.BitString(pubkey.to_octet_string(:uncompressed)), ++ ]) ++ derive(OpenSSL::PKey.read(obj.to_der)) + end + end + + +From 8ee6a582c7e4614eec4f5ca5ab59898fbcb50d2a Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 22 Oct 2021 16:24:07 +0900 +Subject: [PATCH 3/5] pkey/dh: deprecate OpenSSL::PKey::DH#generate_key! + +OpenSSL::PKey::DH#generate_key! will not work on OpenSSL 3.0 because +keys are made immutable. Users should use OpenSSL::PKey.generate_key +instead. +--- + ext/openssl/lib/openssl/pkey.rb | 23 +++++++++++++++++++---- + ext/openssl/ossl_pkey_dh.c | 9 +++++---- + test/openssl/test_pkey_dh.rb | 18 ++++++++++-------- + 3 files changed, 34 insertions(+), 16 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index ba04cf4b..c3e06290 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -71,14 +71,29 @@ def compute_key(pub_bn) + # called first in order to generate the per-session keys before performing + # the actual key exchange. + # ++ # Deprecated in version 3.0. This method is incompatible with ++ # OpenSSL 3.0.0 or later. ++ # + # See also OpenSSL::PKey.generate_key. + # + # Example: +- # dh = OpenSSL::PKey::DH.new(2048) +- # public_key = dh.public_key #contains no private/public key yet +- # public_key.generate_key! +- # puts public_key.private? # => true ++ # # DEPRECATED USAGE: This will not work on OpenSSL 3.0 or later ++ # dh0 = OpenSSL::PKey::DH.new(2048) ++ # dh = dh0.public_key # #public_key only copies the DH parameters (contrary to the name) ++ # dh.generate_key! ++ # puts dh.private? # => true ++ # puts dh0.pub_key == dh.pub_key #=> false ++ # ++ # # With OpenSSL::PKey.generate_key ++ # dh0 = OpenSSL::PKey::DH.new(2048) ++ # dh = OpenSSL::PKey.generate_key(dh0) ++ # puts dh0.pub_key == dh.pub_key #=> false + def generate_key! ++ if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000 ++ raise DHError, "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \ ++ "use OpenSSL::PKey.generate_key instead" ++ end ++ + unless priv_key + tmp = OpenSSL::PKey.generate_key(self) + set_key(tmp.pub_key, tmp.priv_key) +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index 04c11b2157..e70d60ed19 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -58,15 +58,16 @@ VALUE eDHError; + * + * Examples: + * # Creating an instance from scratch +- * dh = DH.new ++ * # Note that this is deprecated and will not work on OpenSSL 3.0 or later. ++ * dh = OpenSSL::PKey::DH.new + * dh.set_pqg(bn_p, nil, bn_g) + * + * # Generating a parameters and a key pair +- * dh = DH.new(2048) # An alias of DH.generate(2048) ++ * dh = OpenSSL::PKey::DH.new(2048) # An alias of OpenSSL::PKey::DH.generate(2048) + * + * # Reading DH parameters +- * dh = DH.new(File.read('parameters.pem')) # -> dh, but no public/private key yet +- * dh.generate_key! # -> dh with public and private key ++ * dh_params = OpenSSL::PKey::DH.new(File.read('parameters.pem')) # loads parameters only ++ * dh = OpenSSL::PKey.generate_key(dh_params) # generates a key pair + */ + static VALUE + ossl_dh_initialize(int argc, VALUE *argv, VALUE self) +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index 757704ca..ac11af38 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -26,14 +26,19 @@ def test_new_break + end + + def test_derive_key +- dh1 = Fixtures.pkey("dh1024").generate_key! +- dh2 = Fixtures.pkey("dh1024").generate_key! ++ params = Fixtures.pkey("dh1024") ++ dh1 = OpenSSL::PKey.generate_key(params) ++ dh2 = OpenSSL::PKey.generate_key(params) + dh1_pub = OpenSSL::PKey.read(dh1.public_to_der) + dh2_pub = OpenSSL::PKey.read(dh2.public_to_der) ++ + z = dh1.g.mod_exp(dh1.priv_key, dh1.p).mod_exp(dh2.priv_key, dh1.p).to_s(2) + assert_equal z, dh1.derive(dh2_pub) + assert_equal z, dh2.derive(dh1_pub) + ++ assert_raise(OpenSSL::PKey::PKeyError) { params.derive(dh1_pub) } ++ assert_raise(OpenSSL::PKey::PKeyError) { dh1_pub.derive(params) } ++ + assert_equal z, dh1.compute_key(dh2.pub_key) + assert_equal z, dh2.compute_key(dh1.pub_key) + end +@@ -74,19 +79,16 @@ def test_public_key + end + + def test_generate_key +- dh = Fixtures.pkey("dh1024").public_key # creates a copy ++ # Deprecated in v3.0.0; incompatible with OpenSSL 3.0 ++ dh = Fixtures.pkey("dh1024").public_key # creates a copy with params only + assert_no_key(dh) + dh.generate_key! + assert_key(dh) +- end + +- def test_key_exchange +- dh = Fixtures.pkey("dh1024") + dh2 = dh.public_key +- dh.generate_key! + dh2.generate_key! + assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key)) +- end ++ end if !openssl?(3, 0, 0) + + def test_params_ok? + dh0 = Fixtures.pkey("dh1024") + +From 5e2e66cce870ea86001dbb0eaa3092badfd37994 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 17 Dec 2021 02:21:42 +0900 +Subject: [PATCH 4/5] pkey/ec: deprecate OpenSSL::PKey::EC#generate_key! + +OpenSSL::PKey::EC#generate_key! will not work on OpenSSL 3.0 because +keys are made immutable. Users should use OpenSSL::PKey.generate_key +instead. +--- + ext/openssl/ossl_pkey_ec.c | 4 ++++ + test/openssl/test_pkey_ec.rb | 21 +++++++++++++-------- + 2 files changed, 17 insertions(+), 8 deletions(-) + +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index db80d112..398a550a 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -442,6 +442,9 @@ ossl_ec_key_to_der(VALUE self) + */ + static VALUE ossl_ec_key_generate_key(VALUE self) + { ++#if OSSL_OPENSSL_PREREQ(3, 0, 0) ++ rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0"); ++#else + EC_KEY *ec; + + GetEC(self, ec); +@@ -449,6 +452,7 @@ static VALUE ossl_ec_key_generate_key(VALUE self) + ossl_raise(eECError, "EC_KEY_generate_key"); + + return self; ++#endif + } + + /* +diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb +index 3f5958af..33f78a4c 100644 +--- a/test/openssl/test_pkey_ec.rb ++++ b/test/openssl/test_pkey_ec.rb +@@ -13,15 +13,13 @@ def test_ec_key + # FIPS-selftest failure on some environment, so skip for now. + next if ["Oakley", "X25519"].any? { |n| curve_name.start_with?(n) } + +- key = OpenSSL::PKey::EC.new(curve_name) +- key.generate_key! +- ++ key = OpenSSL::PKey::EC.generate(curve_name) + assert_predicate key, :private? + assert_predicate key, :public? + assert_nothing_raised { key.check_key } + end + +- key1 = OpenSSL::PKey::EC.new("prime256v1").generate_key! ++ key1 = OpenSSL::PKey::EC.generate("prime256v1") + + key2 = OpenSSL::PKey::EC.new + key2.group = key1.group +@@ -52,6 +50,13 @@ def test_generate + assert_equal(true, ec.private?) + end + ++ def test_generate_key ++ ec = OpenSSL::PKey::EC.new("prime256v1") ++ assert_equal false, ec.private? ++ ec.generate_key! ++ assert_equal true, ec.private? ++ end if !openssl?(3, 0, 0) ++ + def test_marshal + key = Fixtures.pkey("p256") + deserialized = Marshal.load(Marshal.dump(key)) +@@ -136,7 +141,7 @@ def test_sign_verify_raw + end + + def test_dsa_sign_asn1_FIPS186_3 +- key = OpenSSL::PKey::EC.new("prime256v1").generate_key! ++ key = OpenSSL::PKey::EC.generate("prime256v1") + size = key.group.order.num_bits / 8 + 1 + dgst = (1..size).to_a.pack('C*') + sig = key.dsa_sign_asn1(dgst) +@@ -145,8 +150,8 @@ def test_dsa_sign_asn1_FIPS186_3 + end + + def test_dh_compute_key +- key_a = OpenSSL::PKey::EC.new("prime256v1").generate_key! +- key_b = OpenSSL::PKey::EC.new(key_a.group).generate_key! ++ key_a = OpenSSL::PKey::EC.generate("prime256v1") ++ key_b = OpenSSL::PKey::EC.generate(key_a.group) + + pub_a = key_a.public_key + pub_b = key_b.public_key +@@ -276,7 +281,7 @@ def test_ec_group + + def test_ec_point + group = OpenSSL::PKey::EC::Group.new("prime256v1") +- key = OpenSSL::PKey::EC.new(group).generate_key! ++ key = OpenSSL::PKey::EC.generate(group) + point = key.public_key + + point2 = OpenSSL::PKey::EC::Point.new(group, point.to_bn) + +From 6848d2d969d90e6a400d89848ecec21076b87888 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 21 Sep 2021 18:29:59 +0900 +Subject: [PATCH 5/5] pkey: deprecate PKey#set_* methods + +OpenSSL 3.0 made EVP_PKEY immutable. This means we can only have a const +pointer of the low level struct and the following methods can no longer +be provided when linked against OpenSSL 3.0: + + - OpenSSL::PKey::RSA#set_key + - OpenSSL::PKey::RSA#set_factors + - OpenSSL::PKey::RSA#set_crt_params + - OpenSSL::PKey::DSA#set_pqg + - OpenSSL::PKey::DSA#set_key + - OpenSSL::PKey::DH#set_pqg + - OpenSSL::PKey::DH#set_key + - OpenSSL::PKey::EC#group= + - OpenSSL::PKey::EC#private_key= + - OpenSSL::PKey::EC#public_key= + +There is no direct replacement for this functionality at the moment. +I plan to introduce a wrapper around EVP_PKEY_fromdata(), which takes +all key components at once to construct an EVP_PKEY. +--- + ext/openssl/ossl_pkey.h | 16 +++++++ + ext/openssl/ossl_pkey_ec.c | 12 +++++ + test/openssl/test_pkey_dh.rb | 38 +++++++++++----- + test/openssl/test_pkey_dsa.rb | 8 +++- + test/openssl/test_pkey_ec.rb | 58 ++++++++++++++---------- + test/openssl/test_pkey_rsa.rb | 85 ++++++++++++++++++++++------------- + 6 files changed, 149 insertions(+), 68 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index 4beede22..4536e58e 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -116,6 +116,7 @@ static VALUE ossl_##_keytype##_get_##_name(VALUE self) \ + OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \ + _type##_get0_##_group(obj, NULL, &bn)) + ++#if !OSSL_OPENSSL_PREREQ(3, 0, 0) + #define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \ + /* \ + * call-seq: \ +@@ -173,6 +174,21 @@ static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \ + } \ + return self; \ + } ++#else ++#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \ ++static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \ ++{ \ ++ rb_raise(ePKeyError, \ ++ #_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \ ++} ++ ++#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \ ++static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \ ++{ \ ++ rb_raise(ePKeyError, \ ++ #_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \ ++} ++#endif + + #define OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, _name) \ + /* \ +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index 398a550a..7a6ed1c9 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -251,6 +251,9 @@ ossl_ec_key_get_group(VALUE self) + static VALUE + ossl_ec_key_set_group(VALUE self, VALUE group_v) + { ++#if OSSL_OPENSSL_PREREQ(3, 0, 0) ++ rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0"); ++#else + EC_KEY *ec; + EC_GROUP *group; + +@@ -261,6 +264,7 @@ ossl_ec_key_set_group(VALUE self, VALUE group_v) + ossl_raise(eECError, "EC_KEY_set_group"); + + return group_v; ++#endif + } + + /* +@@ -289,6 +293,9 @@ static VALUE ossl_ec_key_get_private_key(VALUE self) + */ + static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key) + { ++#if OSSL_OPENSSL_PREREQ(3, 0, 0) ++ rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0"); ++#else + EC_KEY *ec; + BIGNUM *bn = NULL; + +@@ -307,6 +314,7 @@ static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key) + } + + return private_key; ++#endif + } + + /* +@@ -335,6 +343,9 @@ static VALUE ossl_ec_key_get_public_key(VALUE self) + */ + static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key) + { ++#if OSSL_OPENSSL_PREREQ(3, 0, 0) ++ rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0"); ++#else + EC_KEY *ec; + EC_POINT *point = NULL; + +@@ -353,6 +364,7 @@ static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key) + } + + return public_key; ++#endif + } + + /* +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index ac11af38..161af189 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -107,13 +107,32 @@ def test_params_ok? + end + + def test_dup +- dh = Fixtures.pkey("dh1024") +- dh2 = dh.dup +- assert_equal dh.to_der, dh2.to_der # params +- assert_equal_params dh, dh2 # keys +- dh2.set_pqg(dh2.p + 1, nil, dh2.g) +- assert_not_equal dh2.p, dh.p +- assert_equal dh2.g, dh.g ++ # Parameters only ++ dh1 = Fixtures.pkey("dh1024") ++ dh2 = dh1.dup ++ assert_equal dh1.to_der, dh2.to_der ++ assert_not_equal nil, dh1.p ++ assert_not_equal nil, dh1.g ++ assert_equal [dh1.p, dh1.g], [dh2.p, dh2.g] ++ assert_equal nil, dh1.pub_key ++ assert_equal nil, dh1.priv_key ++ assert_equal [dh1.pub_key, dh1.priv_key], [dh2.pub_key, dh2.priv_key] ++ ++ # PKey is immutable in OpenSSL >= 3.0 ++ if !openssl?(3, 0, 0) ++ dh2.set_pqg(dh2.p + 1, nil, dh2.g) ++ assert_not_equal dh2.p, dh1.p ++ end ++ ++ # With a key pair ++ dh3 = OpenSSL::PKey.generate_key(Fixtures.pkey("dh1024")) ++ dh4 = dh3.dup ++ assert_equal dh3.to_der, dh4.to_der ++ assert_equal dh1.to_der, dh4.to_der # encodes parameters only ++ assert_equal [dh1.p, dh1.g], [dh4.p, dh4.g] ++ assert_not_equal nil, dh3.pub_key ++ assert_not_equal nil, dh3.priv_key ++ assert_equal [dh3.pub_key, dh3.priv_key], [dh4.pub_key, dh4.priv_key] + end + + def test_marshal +@@ -125,11 +144,6 @@ def test_marshal + + private + +- def assert_equal_params(dh1, dh2) +- assert_equal(dh1.g, dh2.g) +- assert_equal(dh1.p, dh2.p) +- end +- + def assert_no_key(dh) + assert_equal(false, dh.public?) + assert_equal(false, dh.private?) +diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb +index 0994607f..726b7dbf 100644 +--- a/test/openssl/test_pkey_dsa.rb ++++ b/test/openssl/test_pkey_dsa.rb +@@ -208,8 +208,12 @@ def test_dup + key = Fixtures.pkey("dsa1024") + key2 = key.dup + assert_equal key.params, key2.params +- key2.set_pqg(key2.p + 1, key2.q, key2.g) +- assert_not_equal key.params, key2.params ++ ++ # PKey is immutable in OpenSSL >= 3.0 ++ if !openssl?(3, 0, 0) ++ key2.set_pqg(key2.p + 1, key2.q, key2.g) ++ assert_not_equal key.params, key2.params ++ end + end + + def test_marshal +diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb +index 33f78a4c..ffe5a94e 100644 +--- a/test/openssl/test_pkey_ec.rb ++++ b/test/openssl/test_pkey_ec.rb +@@ -21,11 +21,15 @@ def test_ec_key + + key1 = OpenSSL::PKey::EC.generate("prime256v1") + +- key2 = OpenSSL::PKey::EC.new +- key2.group = key1.group +- key2.private_key = key1.private_key +- key2.public_key = key1.public_key +- assert_equal key1.to_der, key2.to_der ++ # PKey is immutable in OpenSSL >= 3.0; constructing an empty EC object is ++ # deprecated ++ if !openssl?(3, 0, 0) ++ key2 = OpenSSL::PKey::EC.new ++ key2.group = key1.group ++ key2.private_key = key1.private_key ++ key2.public_key = key1.public_key ++ assert_equal key1.to_der, key2.to_der ++ end + + key3 = OpenSSL::PKey::EC.new(key1) + assert_equal key1.to_der, key3.to_der +@@ -35,10 +39,14 @@ def test_ec_key + + key5 = key1.dup + assert_equal key1.to_der, key5.to_der +- key_tmp = OpenSSL::PKey::EC.new("prime256v1").generate_key! +- key5.private_key = key_tmp.private_key +- key5.public_key = key_tmp.public_key +- assert_not_equal key1.to_der, key5.to_der ++ ++ # PKey is immutable in OpenSSL >= 3.0; EC object should not be modified ++ if !openssl?(3, 0, 0) ++ key_tmp = OpenSSL::PKey::EC.generate("prime256v1") ++ key5.private_key = key_tmp.private_key ++ key5.public_key = key_tmp.public_key ++ assert_not_equal key1.to_der, key5.to_der ++ end + end + + def test_generate +@@ -65,22 +73,26 @@ def test_marshal + end + + def test_check_key +- key = OpenSSL::PKey::EC.new("prime256v1").generate_key! +- assert_equal(true, key.check_key) +- assert_equal(true, key.private?) +- assert_equal(true, key.public?) +- key2 = OpenSSL::PKey::EC.new(key.group) +- assert_equal(false, key2.private?) +- assert_equal(false, key2.public?) +- key2.public_key = key.public_key +- assert_equal(false, key2.private?) +- assert_equal(true, key2.public?) +- key2.private_key = key.private_key ++ key0 = Fixtures.pkey("p256") ++ assert_equal(true, key0.check_key) ++ assert_equal(true, key0.private?) ++ assert_equal(true, key0.public?) ++ ++ key1 = OpenSSL::PKey.read(key0.public_to_der) ++ assert_equal(true, key1.check_key) ++ assert_equal(false, key1.private?) ++ assert_equal(true, key1.public?) ++ ++ key2 = OpenSSL::PKey.read(key0.private_to_der) + assert_equal(true, key2.private?) + assert_equal(true, key2.public?) + assert_equal(true, key2.check_key) +- key2.private_key += 1 +- assert_raise(OpenSSL::PKey::ECError) { key2.check_key } ++ ++ # EC#private_key= is deprecated in 3.0 and won't work on OpenSSL 3.0 ++ if !openssl?(3, 0, 0) ++ key2.private_key += 1 ++ assert_raise(OpenSSL::PKey::ECError) { key2.check_key } ++ end + end + + def test_sign_verify +@@ -112,7 +124,7 @@ def test_derive_key + assert_equal [zIUT].pack("H*"), a.derive(b) + + assert_equal a.derive(b), a.dh_compute_key(b.public_key) +- end ++ end if !openssl?(3, 0, 0) # TODO: Test it without using #private_key= + + def test_sign_verify_raw + key = Fixtures.pkey("p256") +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index dbe87ba4..1c7f9ccf 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -31,15 +31,18 @@ def test_private + assert(!key4.private?) + rsa1024 = Fixtures.pkey("rsa1024") + +- # Generated by RSA#set_key +- key5 = OpenSSL::PKey::RSA.new +- key5.set_key(rsa1024.n, rsa1024.e, rsa1024.d) +- assert(key5.private?) +- +- # Generated by RSA#set_key, without d +- key6 = OpenSSL::PKey::RSA.new +- key6.set_key(rsa1024.n, rsa1024.e, nil) +- assert(!key6.private?) ++ if !openssl?(3, 0, 0) ++ key = OpenSSL::PKey::RSA.new ++ # Generated by RSA#set_key ++ key5 = OpenSSL::PKey::RSA.new ++ key5.set_key(rsa1024.n, rsa1024.e, rsa1024.d) ++ assert(key5.private?) ++ ++ # Generated by RSA#set_key, without d ++ key6 = OpenSSL::PKey::RSA.new ++ key6.set_key(rsa1024.n, rsa1024.e, nil) ++ assert(!key6.private?) ++ end + end + + def test_new +@@ -235,36 +238,52 @@ def test_encrypt_decrypt_legacy + + def test_export + rsa1024 = Fixtures.pkey("rsa1024") +- key = OpenSSL::PKey::RSA.new + +- # key has only n, e and d +- key.set_key(rsa1024.n, rsa1024.e, rsa1024.d) +- assert_equal rsa1024.public_key.export, key.export ++ pub = OpenSSL::PKey.read(rsa1024.public_to_der) ++ assert_not_equal rsa1024.export, pub.export ++ assert_equal rsa1024.public_to_pem, pub.export ++ ++ # PKey is immutable in OpenSSL >= 3.0 ++ if !openssl?(3, 0, 0) ++ key = OpenSSL::PKey::RSA.new + +- # key has only n, e, d, p and q +- key.set_factors(rsa1024.p, rsa1024.q) +- assert_equal rsa1024.public_key.export, key.export ++ # key has only n, e and d ++ key.set_key(rsa1024.n, rsa1024.e, rsa1024.d) ++ assert_equal rsa1024.public_key.export, key.export + +- # key has n, e, d, p, q, dmp1, dmq1 and iqmp +- key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp) +- assert_equal rsa1024.export, key.export ++ # key has only n, e, d, p and q ++ key.set_factors(rsa1024.p, rsa1024.q) ++ assert_equal rsa1024.public_key.export, key.export ++ ++ # key has n, e, d, p, q, dmp1, dmq1 and iqmp ++ key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp) ++ assert_equal rsa1024.export, key.export ++ end + end + + def test_to_der + rsa1024 = Fixtures.pkey("rsa1024") +- key = OpenSSL::PKey::RSA.new + +- # key has only n, e and d +- key.set_key(rsa1024.n, rsa1024.e, rsa1024.d) +- assert_equal rsa1024.public_key.to_der, key.to_der ++ pub = OpenSSL::PKey.read(rsa1024.public_to_der) ++ assert_not_equal rsa1024.to_der, pub.to_der ++ assert_equal rsa1024.public_to_der, pub.to_der + +- # key has only n, e, d, p and q +- key.set_factors(rsa1024.p, rsa1024.q) +- assert_equal rsa1024.public_key.to_der, key.to_der ++ # PKey is immutable in OpenSSL >= 3.0 ++ if !openssl?(3, 0, 0) ++ key = OpenSSL::PKey::RSA.new + +- # key has n, e, d, p, q, dmp1, dmq1 and iqmp +- key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp) +- assert_equal rsa1024.to_der, key.to_der ++ # key has only n, e and d ++ key.set_key(rsa1024.n, rsa1024.e, rsa1024.d) ++ assert_equal rsa1024.public_key.to_der, key.to_der ++ ++ # key has only n, e, d, p and q ++ key.set_factors(rsa1024.p, rsa1024.q) ++ assert_equal rsa1024.public_key.to_der, key.to_der ++ ++ # key has n, e, d, p, q, dmp1, dmq1 and iqmp ++ key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp) ++ assert_equal rsa1024.to_der, key.to_der ++ end + end + + def test_RSAPrivateKey +@@ -501,8 +520,12 @@ def test_dup + key = Fixtures.pkey("rsa1024") + key2 = key.dup + assert_equal key.params, key2.params +- key2.set_key(key2.n, 3, key2.d) +- assert_not_equal key.params, key2.params ++ ++ # PKey is immutable in OpenSSL >= 3.0 ++ if !openssl?(3, 0, 0) ++ key2.set_key(key2.n, 3, key2.d) ++ assert_not_equal key.params, key2.params ++ end + end + + def test_marshal diff --git a/ruby-3.1.0-Disable-test_no_private_exp-on-OpenSSL-3.0.patch b/ruby-3.1.0-Disable-test_no_private_exp-on-OpenSSL-3.0.patch new file mode 100644 index 0000000..2b640ea --- /dev/null +++ b/ruby-3.1.0-Disable-test_no_private_exp-on-OpenSSL-3.0.patch @@ -0,0 +1,27 @@ +From 47975ece4096cdab16b3f200f93ea2377dfb41ac Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 31 May 2021 14:17:21 +0900 +Subject: [PATCH] test/openssl/test_pkey_rsa: disable test_no_private_exp on + OpenSSL 3.0 + +OpenSSL::PKey::RSA#set_key does not exist when built with OpenSSL 3.0, +so it is not possible to create an RSA object with incomplete state. + +https://github.com/ruby/openssl/commit/ca03c9c070 +--- + test/openssl/test_pkey_rsa.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index 4548bdb2cfa6..dbe87ba4c1b0 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -11,7 +11,7 @@ def test_no_private_exp + key.set_factors(rsa.p, rsa.q) + assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt("foo") } + assert_raise(OpenSSL::PKey::RSAError){ key.private_decrypt("foo") } +- end ++ end if !openssl?(3, 0, 0) # Impossible state in OpenSSL 3.0 + + def test_private + # Generated by key size and public exponent diff --git a/ruby-3.1.0-Don-t-query-RubyVM-FrozenCore-for-class-path.patch b/ruby-3.1.0-Don-t-query-RubyVM-FrozenCore-for-class-path.patch new file mode 100644 index 0000000..f32f306 --- /dev/null +++ b/ruby-3.1.0-Don-t-query-RubyVM-FrozenCore-for-class-path.patch @@ -0,0 +1,43 @@ +From 0ade5611df9f981005eed32b369d1e699e520221 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Thu, 10 Feb 2022 13:26:44 +0100 +Subject: [PATCH] Don't query `RubyVM::FrozenCore` for class path. + +The `RubyVM::FrozenCore` class path is corrupted during GC cycle and +returns random garbage, which might result in segfault. + +But since it is easy to detect the `RubyVM::FrozenCore`, just provide +the class path explicitly as a workaround. + +Other possibility would be to ignore `RubyVM::FrozenCore` simlarly as +TracePoint API does: + +https://github.com/ruby/ruby/blob/46f6575157d4c2f6bbd5693896e26a65037e5552/vm_trace.c#L411 +--- + vm.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/vm.c b/vm.c +index 8ce8b279d4..3d189fa63a 100644 +--- a/vm.c ++++ b/vm.c +@@ -446,7 +446,15 @@ rb_dtrace_setup(rb_execution_context_t *ec, VALUE klass, ID id, + } + type = BUILTIN_TYPE(klass); + if (type == T_CLASS || type == T_ICLASS || type == T_MODULE) { +- VALUE name = rb_class_path(klass); ++ VALUE name = Qnil; ++ /* ++ * Special treatment for rb_mRubyVMFrozenCore wchi is broken by GC. ++ * https://bugs.ruby-lang.org/issues/18257 ++ */ ++ if (klass == rb_mRubyVMFrozenCore) ++ name = rb_str_new_cstr("RubyVM::FrozenCore"); ++ else ++ name = rb_class_path(klass); + const char *classname, *filename; + const char *methodname = rb_id2name(id); + if (methodname && (filename = rb_source_location_cstr(&args->line_no)) != 0) { +-- +2.34.1 + diff --git a/ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch b/ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch new file mode 100644 index 0000000..ae8f722 --- /dev/null +++ b/ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch @@ -0,0 +1,186 @@ +From 104b009e26c050584e4d186c8cc4e1496a14061b Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Thu, 5 Aug 2021 20:09:25 +0900 +Subject: [PATCH] Get rid of type-punning pointer casts [Bug #18062] + +--- + vm_eval.c | 4 +++- + vm_insnhelper.c | 7 +++++-- + vm_method.c | 41 ++++++++++++++++++++++++++--------------- + 3 files changed, 34 insertions(+), 18 deletions(-) + +diff --git a/vm_eval.c b/vm_eval.c +index 6d4b5c3c0b28..7ce9f157e671 100644 +--- a/vm_eval.c ++++ b/vm_eval.c +@@ -350,9 +350,11 @@ cc_new(VALUE klass, ID mid, int argc, const rb_callable_method_entry_t *cme) + { + struct rb_class_cc_entries *ccs; + struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); ++ VALUE ccs_data; + +- if (rb_id_table_lookup(cc_tbl, mid, (VALUE*)&ccs)) { ++ if (rb_id_table_lookup(cc_tbl, mid, &ccs_data)) { + // ok ++ ccs = (struct rb_class_cc_entries *)ccs_data; + } + else { + ccs = vm_ccs_create(klass, cme); +diff --git a/vm_insnhelper.c b/vm_insnhelper.c +index 14928b2afe8e..e186376b24d7 100644 +--- a/vm_insnhelper.c ++++ b/vm_insnhelper.c +@@ -1637,9 +1637,11 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci) + const ID mid = vm_ci_mid(ci); + struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); + struct rb_class_cc_entries *ccs = NULL; ++ VALUE ccs_data; + + if (cc_tbl) { +- if (rb_id_table_lookup(cc_tbl, mid, (VALUE *)&ccs)) { ++ if (rb_id_table_lookup(cc_tbl, mid, &ccs_data)) { ++ ccs = (struct rb_class_cc_entries *)ccs_data; + const int ccs_len = ccs->len; + VM_ASSERT(vm_ccs_verify(ccs, mid, klass)); + +@@ -1706,8 +1708,9 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci) + if (ccs == NULL) { + VM_ASSERT(cc_tbl != NULL); + +- if (LIKELY(rb_id_table_lookup(cc_tbl, mid, (VALUE*)&ccs))) { ++ if (LIKELY(rb_id_table_lookup(cc_tbl, mid, &ccs_data))) { + // rb_callable_method_entry() prepares ccs. ++ ccs = (struct rb_class_cc_entries *)ccs_data; + } + else { + // TODO: required? +diff --git a/vm_method.c b/vm_method.c +index 016dba1dbb18..1fd0bd57f7ca 100644 +--- a/vm_method.c ++++ b/vm_method.c +@@ -42,11 +42,11 @@ vm_ccs_dump(VALUE klass, ID target_mid) + { + struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); + if (cc_tbl) { +- const struct rb_class_cc_entries *ccs; ++ VALUE ccs; + if (target_mid) { +- if (rb_id_table_lookup(cc_tbl, target_mid, (VALUE *)&ccs)) { ++ if (rb_id_table_lookup(cc_tbl, target_mid, &ccs)) { + fprintf(stderr, " [CCTB] %p\n", (void *)cc_tbl); +- vm_ccs_dump_i(target_mid, (VALUE)ccs, NULL); ++ vm_ccs_dump_i(target_mid, ccs, NULL); + } + } + else { +@@ -72,11 +72,11 @@ vm_mtbl_dump(VALUE klass, ID target_mid) + fprintf(stderr, "# vm_mtbl\n"); + while (klass) { + rp_m(" -> ", klass); +- rb_method_entry_t *me; ++ VALUE me; + + if (RCLASS_M_TBL(klass)) { + if (target_mid != 0) { +- if (rb_id_table_lookup(RCLASS_M_TBL(klass), target_mid, (VALUE *)&me)) { ++ if (rb_id_table_lookup(RCLASS_M_TBL(klass), target_mid, &me)) { + rp_m(" [MTBL] ", me); + } + } +@@ -90,7 +90,7 @@ vm_mtbl_dump(VALUE klass, ID target_mid) + } + if (RCLASS_CALLABLE_M_TBL(klass)) { + if (target_mid != 0) { +- if (rb_id_table_lookup(RCLASS_CALLABLE_M_TBL(klass), target_mid, (VALUE *)&me)) { ++ if (rb_id_table_lookup(RCLASS_CALLABLE_M_TBL(klass), target_mid, &me)) { + rp_m(" [CM**] ", me); + } + } +@@ -144,10 +144,11 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid) + // check only current class + + struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); +- struct rb_class_cc_entries *ccs; ++ VALUE ccs_data; + + // invalidate CCs +- if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, (VALUE *)&ccs)) { ++ if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, &ccs_data)) { ++ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data; + rb_vm_ccs_free(ccs); + rb_id_table_delete(cc_tbl, mid); + RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_ccs); +@@ -205,9 +206,10 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid) + } + else { + rb_vm_t *vm = GET_VM(); +- if (rb_id_table_lookup(vm->negative_cme_table, mid, (VALUE *)&cme)) { ++ VALUE cme_data = (VALUE) cme; ++ if (rb_id_table_lookup(vm->negative_cme_table, mid, &cme_data)) { + rb_id_table_delete(vm->negative_cme_table, mid); +- vm_me_invalidate_cache((rb_callable_method_entry_t *)cme); ++ vm_me_invalidate_cache((rb_callable_method_entry_t *)cme_data); + + RB_DEBUG_COUNTER_INC(cc_invalidate_negative); + } +@@ -1023,6 +1025,7 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_ + { + struct rb_id_table *mtbl; + const rb_callable_method_entry_t *cme; ++ VALUE cme_data; + + if (me) { + if (me->defined_class == 0) { +@@ -1032,7 +1035,8 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_ + + mtbl = RCLASS_CALLABLE_M_TBL(defined_class); + +- if (mtbl && rb_id_table_lookup(mtbl, id, (VALUE *)&cme)) { ++ if (mtbl && rb_id_table_lookup(mtbl, id, &cme_data)) { ++ cme = (rb_callable_method_entry_t *)cme_data; + RB_DEBUG_COUNTER_INC(mc_cme_complement_hit); + VM_ASSERT(callable_method_entry_p(cme)); + VM_ASSERT(!METHOD_ENTRY_INVALIDATED(cme)); +@@ -1076,9 +1080,10 @@ cached_callable_method_entry(VALUE klass, ID mid) + ASSERT_vm_locking(); + + struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); +- struct rb_class_cc_entries *ccs; ++ VALUE ccs_data; + +- if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, (VALUE *)&ccs)) { ++ if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, &ccs_data)) { ++ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data; + VM_ASSERT(vm_ccs_p(ccs)); + + if (LIKELY(!METHOD_ENTRY_INVALIDATED(ccs->cme))) { +@@ -1104,12 +1109,14 @@ cache_callable_method_entry(VALUE klass, ID mid, const rb_callable_method_entry_ + + struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); + struct rb_class_cc_entries *ccs; ++ VALUE ccs_data; + + if (!cc_tbl) { + cc_tbl = RCLASS_CC_TBL(klass) = rb_id_table_create(2); + } + +- if (rb_id_table_lookup(cc_tbl, mid, (VALUE *)&ccs)) { ++ if (rb_id_table_lookup(cc_tbl, mid, &ccs_data)) { ++ ccs = (struct rb_class_cc_entries *)ccs_data; + VM_ASSERT(ccs->cme == cme); + } + else { +@@ -1123,8 +1130,12 @@ negative_cme(ID mid) + { + rb_vm_t *vm = GET_VM(); + const rb_callable_method_entry_t *cme; ++ VALUE cme_data; + +- if (!rb_id_table_lookup(vm->negative_cme_table, mid, (VALUE *)&cme)) { ++ if (rb_id_table_lookup(vm->negative_cme_table, mid, &cme_data)) { ++ cme = (rb_callable_method_entry_t *)cme_data; ++ } ++ else { + cme = (rb_callable_method_entry_t *)rb_method_entry_alloc(mid, Qnil, Qnil, NULL); + rb_id_table_insert(vm->negative_cme_table, mid, (VALUE)cme); + } diff --git a/ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch b/ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch new file mode 100644 index 0000000..86f534d --- /dev/null +++ b/ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch @@ -0,0 +1,58 @@ +From 72317b333b85eed483ad00bcd4f40944019a7c13 Mon Sep 17 00:00:00 2001 +From: "xtkoba+ruby@gmail.com" +Date: Fri, 13 Aug 2021 13:45:53 +0000 +Subject: [PATCH] Ignore `DW_FORM_ref_addr` [Bug #17052] + +Ignore `DW_FORM_ref_addr` form and other forms that are not supposed +to be used currently. +--- + addr2line.c | 23 ++++++++++++++++++++--- + 1 file changed, 20 insertions(+), 3 deletions(-) + +diff --git a/addr2line.c b/addr2line.c +index fed1a8da84e5..92c6da5e3bea 100644 +--- a/addr2line.c ++++ b/addr2line.c +@@ -1593,14 +1593,31 @@ di_read_cu(DebugInfoReader *reader) + } + + static void +-read_abstract_origin(DebugInfoReader *reader, uint64_t abstract_origin, line_info_t *line) ++read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_origin, line_info_t *line) + { + char *p = reader->p; + char *q = reader->q; + int level = reader->level; + DIE die; + +- reader->p = reader->current_cu + abstract_origin; ++ switch (form) { ++ case DW_FORM_ref1: ++ case DW_FORM_ref2: ++ case DW_FORM_ref4: ++ case DW_FORM_ref8: ++ case DW_FORM_ref_udata: ++ reader->p = reader->current_cu + abstract_origin; ++ break; ++ case DW_FORM_ref_addr: ++ goto finish; /* not supported yet */ ++ case DW_FORM_ref_sig8: ++ goto finish; /* not supported yet */ ++ case DW_FORM_ref_sup4: ++ case DW_FORM_ref_sup8: ++ goto finish; /* not supported yet */ ++ default: ++ goto finish; ++ } + if (!di_read_die(reader, &die)) goto finish; + + /* enumerate abbrev */ +@@ -1665,7 +1682,7 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces, + /* 1 or 3 */ + break; /* goto skip_die; */ + case DW_AT_abstract_origin: +- read_abstract_origin(reader, v.as.uint64, &line); ++ read_abstract_origin(reader, v.form, v.as.uint64, &line); + break; /* goto skip_die; */ + } + } diff --git a/ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch b/ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch new file mode 100644 index 0000000..a558cec --- /dev/null +++ b/ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch @@ -0,0 +1,1319 @@ +From 3e6cd88c621d8834712d2279f925b9af83c2bb34 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 18 May 2020 20:06:16 +0900 +Subject: [PATCH 1/6] pkey: implement PKey#encrypt and #decrypt + +Support public key encryption and decryption operations using the EVP +API. +--- + ext/openssl/ossl_pkey.c | 141 ++++++++++++++++++++++++++++++++++ + test/openssl/test_pkey_rsa.rb | 34 ++++++++ + 2 files changed, 175 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 21cd4b2cda..baf8ce9f20 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -986,6 +986,145 @@ ossl_pkey_derive(int argc, VALUE *argv, VALUE self) + return str; + } + ++/* ++ * call-seq: ++ * pkey.encrypt(data [, options]) -> string ++ * ++ * Performs a public key encryption operation using +pkey+. ++ * ++ * See #decrypt for the reverse operation. ++ * ++ * Added in version 3.0. See also the man page EVP_PKEY_encrypt(3). ++ * ++ * +data+:: ++ * A String to be encrypted. ++ * +options+:: ++ * A Hash that contains algorithm specific control operations to \OpenSSL. ++ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. ++ * ++ * Example: ++ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) ++ * data = "secret data" ++ * encrypted = pkey.encrypt(data, rsa_padding_mode: "oaep") ++ * decrypted = pkey.decrypt(data, rsa_padding_mode: "oaep") ++ * p decrypted #=> "secret data" ++ */ ++static VALUE ++ossl_pkey_encrypt(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey; ++ EVP_PKEY_CTX *ctx; ++ VALUE data, options, str; ++ size_t outlen; ++ int state; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "11", &data, &options); ++ StringValue(data); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_encrypt_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_encrypt_init"); ++ } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(ctx, options, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ if (EVP_PKEY_encrypt(ctx, NULL, &outlen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_encrypt"); ++ } ++ if (outlen > LONG_MAX) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_raise(ePKeyError, "encrypted data would be too large"); ++ } ++ str = ossl_str_new(NULL, (long)outlen, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_PKEY_encrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_encrypt"); ++ } ++ EVP_PKEY_CTX_free(ctx); ++ rb_str_set_len(str, outlen); ++ return str; ++} ++ ++/* ++ * call-seq: ++ * pkey.decrypt(data [, options]) -> string ++ * ++ * Performs a public key decryption operation using +pkey+. ++ * ++ * See #encrypt for a description of the parameters and an example. ++ * ++ * Added in version 3.0. See also the man page EVP_PKEY_decrypt(3). ++ */ ++static VALUE ++ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey; ++ EVP_PKEY_CTX *ctx; ++ VALUE data, options, str; ++ size_t outlen; ++ int state; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "11", &data, &options); ++ StringValue(data); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_decrypt_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_decrypt_init"); ++ } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(ctx, options, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ if (EVP_PKEY_decrypt(ctx, NULL, &outlen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_decrypt"); ++ } ++ if (outlen > LONG_MAX) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_raise(ePKeyError, "decrypted data would be too large"); ++ } ++ str = ossl_str_new(NULL, (long)outlen, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_PKEY_decrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_decrypt"); ++ } ++ EVP_PKEY_CTX_free(ctx); ++ rb_str_set_len(str, outlen); ++ return str; ++} ++ + /* + * INIT + */ +@@ -1085,6 +1224,8 @@ Init_ossl_pkey(void) + rb_define_method(cPKey, "sign", ossl_pkey_sign, -1); + rb_define_method(cPKey, "verify", ossl_pkey_verify, -1); + rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); ++ rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1); ++ rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1); + + id_private_q = rb_intern("private?"); + +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index 5f8d04e754..d6bfca3ac5 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -173,6 +173,40 @@ def test_sign_verify_pss + } + end + ++ def test_encrypt_decrypt ++ rsapriv = Fixtures.pkey("rsa-1") ++ rsapub = dup_public(rsapriv) ++ ++ # Defaults to PKCS #1 v1.5 ++ raw = "data" ++ enc = rsapub.encrypt(raw) ++ assert_equal raw, rsapriv.decrypt(enc) ++ ++ # Invalid options ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ rsapub.encrypt(raw, { "nonexistent" => "option" }) ++ } ++ end ++ ++ def test_encrypt_decrypt_legacy ++ rsapriv = Fixtures.pkey("rsa-1") ++ rsapub = dup_public(rsapriv) ++ ++ # Defaults to PKCS #1 v1.5 ++ raw = "data" ++ enc_legacy = rsapub.public_encrypt(raw) ++ assert_equal raw, rsapriv.decrypt(enc_legacy) ++ enc_new = rsapub.encrypt(raw) ++ assert_equal raw, rsapriv.private_decrypt(enc_new) ++ ++ # OAEP with default parameters ++ raw = "data" ++ enc_legacy = rsapub.public_encrypt(raw, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING) ++ assert_equal raw, rsapriv.decrypt(enc_legacy, { "rsa_padding_mode" => "oaep" }) ++ enc_new = rsapub.encrypt(raw, { "rsa_padding_mode" => "oaep" }) ++ assert_equal raw, rsapriv.private_decrypt(enc_legacy, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING) ++ end ++ + def test_export + rsa1024 = Fixtures.pkey("rsa1024") + key = OpenSSL::PKey::RSA.new +-- +2.32.0 + + +From 6f5c75b06967b5b2db1d13646d74310e1cdc563e Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 25 May 2021 18:43:29 +0900 +Subject: [PATCH 2/6] pkey: update version reference in #sign and #verify + documentation + +The next release is decided to be 3.0 rather than 2.3. +--- + ext/openssl/ossl_pkey.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index baf8ce9f20..d08f6f7e60 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -761,7 +761,7 @@ ossl_pkey_public_to_pem(VALUE self) + * +options+:: + * A Hash that contains algorithm specific control operations to \OpenSSL. + * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. +- * +options+ parameter was added in version 2.3. ++ * +options+ parameter was added in version 3.0. + * + * Example: + * data = "Sign me!" +@@ -875,7 +875,7 @@ ossl_pkey_sign(int argc, VALUE *argv, VALUE self) + * +data+:: + * See #sign. + * +options+:: +- * See #sign. +options+ parameter was added in version 2.3. ++ * See #sign. +options+ parameter was added in version 3.0. + */ + static VALUE + ossl_pkey_verify(int argc, VALUE *argv, VALUE self) +-- +2.32.0 + + +From 99fc31a9b4843b7f8923b5ce8b36115b2c66f4db Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 22 May 2020 16:10:35 +0900 +Subject: [PATCH 3/6] pkey: implement PKey#sign_raw, #verify_raw, and + #verify_recover + +Add a variant of PKey#sign and #verify that do not hash the data +automatically. + +Sometimes the caller has the hashed data only, but not the plaintext +to be signed. In that case, users would have to use the low-level API +such as RSA#private_encrypt or #public_decrypt directly. + +OpenSSL 1.0.0 and later supports EVP_PKEY_sign() and EVP_PKEY_verify() +which provide the same functionality as part of the EVP API. This patch +adds wrappers for them. +--- + ext/openssl/ossl_pkey.c | 232 ++++++++++++++++++++++++++++++++++ + test/openssl/test_pkey_dsa.rb | 25 +++- + test/openssl/test_pkey_ec.rb | 21 ++- + test/openssl/test_pkey_rsa.rb | 78 ++++++++---- + 4 files changed, 325 insertions(+), 31 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index d08f6f7e60..ba909c7632 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -935,6 +935,235 @@ ossl_pkey_verify(int argc, VALUE *argv, VALUE self) + } + } + ++/* ++ * call-seq: ++ * pkey.sign_raw(digest, data [, options]) -> string ++ * ++ * Signs +data+ using a private key +pkey+. Unlike #sign, +data+ will not be ++ * hashed by +digest+ automatically. ++ * ++ * See #verify_raw for the verification operation. ++ * ++ * Added in version 3.0. See also the man page EVP_PKEY_sign(3). ++ * ++ * +digest+:: ++ * A String that represents the message digest algorithm name, or +nil+ ++ * if the PKey type requires no digest algorithm. ++ * Although this method will not hash +data+ with it, this parameter may still ++ * be required depending on the signature algorithm. ++ * +data+:: ++ * A String. The data to be signed. ++ * +options+:: ++ * A Hash that contains algorithm specific control operations to \OpenSSL. ++ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. ++ * ++ * Example: ++ * data = "Sign me!" ++ * hash = OpenSSL::Digest.digest("SHA256", data) ++ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) ++ * signopts = { rsa_padding_mode: "pss" } ++ * signature = pkey.sign_raw("SHA256", hash, signopts) ++ * ++ * # Creates a copy of the RSA key pkey, but without the private components ++ * pub_key = pkey.public_key ++ * puts pub_key.verify_raw("SHA256", signature, hash, signopts) # => true ++ */ ++static VALUE ++ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey; ++ VALUE digest, data, options, sig; ++ const EVP_MD *md = NULL; ++ EVP_PKEY_CTX *ctx; ++ size_t outlen; ++ int state; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "21", &digest, &data, &options); ++ if (!NIL_P(digest)) ++ md = ossl_evp_get_digestbyname(digest); ++ StringValue(data); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_sign_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_sign_init"); ++ } ++ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); ++ } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(ctx, options, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ if (EVP_PKEY_sign(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_sign"); ++ } ++ if (outlen > LONG_MAX) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_raise(ePKeyError, "signature would be too large"); ++ } ++ sig = ossl_str_new(NULL, (long)outlen, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_PKEY_sign(ctx, (unsigned char *)RSTRING_PTR(sig), &outlen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_sign"); ++ } ++ EVP_PKEY_CTX_free(ctx); ++ rb_str_set_len(sig, outlen); ++ return sig; ++} ++ ++/* ++ * call-seq: ++ * pkey.verify_raw(digest, signature, data [, options]) -> true or false ++ * ++ * Verifies the +signature+ for the +data+ using a public key +pkey+. Unlike ++ * #verify, this method will not hash +data+ with +digest+ automatically. ++ * ++ * Returns +true+ if the signature is successfully verified, +false+ otherwise. ++ * The caller must check the return value. ++ * ++ * See #sign_raw for the signing operation and an example code. ++ * ++ * Added in version 3.0. See also the man page EVP_PKEY_verify(3). ++ * ++ * +signature+:: ++ * A String containing the signature to be verified. ++ */ ++static VALUE ++ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey; ++ VALUE digest, sig, data, options; ++ const EVP_MD *md = NULL; ++ EVP_PKEY_CTX *ctx; ++ int state, ret; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options); ++ ossl_pkey_check_public_key(pkey); ++ if (!NIL_P(digest)) ++ md = ossl_evp_get_digestbyname(digest); ++ StringValue(sig); ++ StringValue(data); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_verify_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_verify_init"); ++ } ++ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); ++ } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(ctx, options, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ ret = EVP_PKEY_verify(ctx, (unsigned char *)RSTRING_PTR(sig), ++ RSTRING_LEN(sig), ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)); ++ EVP_PKEY_CTX_free(ctx); ++ if (ret < 0) ++ ossl_raise(ePKeyError, "EVP_PKEY_verify"); ++ ++ if (ret) ++ return Qtrue; ++ else { ++ ossl_clear_error(); ++ return Qfalse; ++ } ++} ++ ++/* ++ * call-seq: ++ * pkey.verify_recover(digest, signature [, options]) -> string ++ * ++ * Recovers the signed data from +signature+ using a public key +pkey+. Not all ++ * signature algorithms support this operation. ++ * ++ * Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3). ++ * ++ * +signature+:: ++ * A String containing the signature to be verified. ++ */ ++static VALUE ++ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey; ++ VALUE digest, sig, options, out; ++ const EVP_MD *md = NULL; ++ EVP_PKEY_CTX *ctx; ++ int state; ++ size_t outlen; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "21", &digest, &sig, &options); ++ ossl_pkey_check_public_key(pkey); ++ if (!NIL_P(digest)) ++ md = ossl_evp_get_digestbyname(digest); ++ StringValue(sig); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_verify_recover_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover_init"); ++ } ++ if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); ++ } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(ctx, options, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ if (EVP_PKEY_verify_recover(ctx, NULL, &outlen, ++ (unsigned char *)RSTRING_PTR(sig), ++ RSTRING_LEN(sig)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover"); ++ } ++ out = ossl_str_new(NULL, (long)outlen, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_PKEY_verify_recover(ctx, (unsigned char *)RSTRING_PTR(out), &outlen, ++ (unsigned char *)RSTRING_PTR(sig), ++ RSTRING_LEN(sig)) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_verify_recover"); ++ } ++ EVP_PKEY_CTX_free(ctx); ++ rb_str_set_len(out, outlen); ++ return out; ++} ++ + /* + * call-seq: + * pkey.derive(peer_pkey) -> string +@@ -1223,6 +1452,9 @@ Init_ossl_pkey(void) + + rb_define_method(cPKey, "sign", ossl_pkey_sign, -1); + rb_define_method(cPKey, "verify", ossl_pkey_verify, -1); ++ rb_define_method(cPKey, "sign_raw", ossl_pkey_sign_raw, -1); ++ rb_define_method(cPKey, "verify_raw", ossl_pkey_verify_raw, -1); ++ rb_define_method(cPKey, "verify_recover", ossl_pkey_verify_recover, -1); + rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); + rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1); + rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1); +diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb +index 85bb6ec0ae..147e50176b 100644 +--- a/test/openssl/test_pkey_dsa.rb ++++ b/test/openssl/test_pkey_dsa.rb +@@ -48,12 +48,31 @@ def test_sign_verify + assert_equal false, dsa512.verify("SHA256", signature1, data) + end + +- def test_sys_sign_verify +- key = Fixtures.pkey("dsa256") ++ def test_sign_verify_raw ++ key = Fixtures.pkey("dsa512") + data = 'Sign me!' + digest = OpenSSL::Digest.digest('SHA1', data) ++ ++ invalid_sig = key.sign_raw(nil, digest.succ) ++ malformed_sig = "*" * invalid_sig.bytesize ++ ++ # Sign by #syssign + sig = key.syssign(digest) +- assert(key.sysverify(digest, sig)) ++ assert_equal true, key.sysverify(digest, sig) ++ assert_equal false, key.sysverify(digest, invalid_sig) ++ assert_raise(OpenSSL::PKey::DSAError) { key.sysverify(digest, malformed_sig) } ++ assert_equal true, key.verify_raw(nil, sig, digest) ++ assert_equal false, key.verify_raw(nil, invalid_sig, digest) ++ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, digest) } ++ ++ # Sign by #sign_raw ++ sig = key.sign_raw(nil, digest) ++ assert_equal true, key.sysverify(digest, sig) ++ assert_equal false, key.sysverify(digest, invalid_sig) ++ assert_raise(OpenSSL::PKey::DSAError) { key.sysverify(digest, malformed_sig) } ++ assert_equal true, key.verify_raw(nil, sig, digest) ++ assert_equal false, key.verify_raw(nil, invalid_sig, digest) ++ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, digest) } + end + + def test_DSAPrivateKey +diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb +index 95d4338a51..4b6df0290f 100644 +--- a/test/openssl/test_pkey_ec.rb ++++ b/test/openssl/test_pkey_ec.rb +@@ -109,13 +109,30 @@ def test_derive_key + assert_equal a.derive(b), a.dh_compute_key(b.public_key) + end + +- def test_dsa_sign_verify ++ def test_sign_verify_raw ++ key = Fixtures.pkey("p256") + data1 = "foo" + data2 = "bar" +- key = OpenSSL::PKey::EC.new("prime256v1").generate_key! ++ ++ malformed_sig = "*" * 30 ++ ++ # Sign by #dsa_sign_asn1 + sig = key.dsa_sign_asn1(data1) + assert_equal true, key.dsa_verify_asn1(data1, sig) + assert_equal false, key.dsa_verify_asn1(data2, sig) ++ assert_raise(OpenSSL::PKey::ECError) { key.dsa_verify_asn1(data1, malformed_sig) } ++ assert_equal true, key.verify_raw(nil, sig, data1) ++ assert_equal false, key.verify_raw(nil, sig, data2) ++ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, data1) } ++ ++ # Sign by #sign_raw ++ sig = key.sign_raw(nil, data1) ++ assert_equal true, key.dsa_verify_asn1(data1, sig) ++ assert_equal false, key.dsa_verify_asn1(data2, sig) ++ assert_raise(OpenSSL::PKey::ECError) { key.dsa_verify_asn1(data1, malformed_sig) } ++ assert_equal true, key.verify_raw(nil, sig, data1) ++ assert_equal false, key.verify_raw(nil, sig, data2) ++ assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, data1) } + end + + def test_dsa_sign_asn1_FIPS186_3 +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index d6bfca3ac5..5e127f5407 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -13,32 +13,6 @@ def test_no_private_exp + assert_raise(OpenSSL::PKey::RSAError){ key.private_decrypt("foo") } + end + +- def test_padding +- key = OpenSSL::PKey::RSA.new(512, 3) +- +- # Need right size for raw mode +- plain0 = "x" * (512/8) +- cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING) +- plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING) +- assert_equal(plain0, plain1) +- +- # Need smaller size for pkcs1 mode +- plain0 = "x" * (512/8 - 11) +- cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING) +- plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING) +- assert_equal(plain0, plain1) +- +- cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default +- plain1 = key.public_decrypt(cipherdef) +- assert_equal(plain0, plain1) +- assert_equal(cipher1, cipherdef) +- +- # Failure cases +- assert_raise(ArgumentError){ key.private_encrypt() } +- assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) } +- assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) } +- end +- + def test_private + # Generated by key size and public exponent + key = OpenSSL::PKey::RSA.new(512, 3) +@@ -133,6 +107,58 @@ def test_sign_verify_options + assert_equal false, key.verify("SHA256", sig_pss, data) + end + ++ def test_sign_verify_raw ++ key = Fixtures.pkey("rsa-1") ++ data = "Sign me!" ++ hash = OpenSSL::Digest.digest("SHA1", data) ++ signature = key.sign_raw("SHA1", hash) ++ assert_equal true, key.verify_raw("SHA1", signature, hash) ++ assert_equal true, key.verify("SHA1", signature, data) ++ ++ # Too long data ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ key.sign_raw("SHA1", "x" * (key.n.num_bytes + 1)) ++ } ++ ++ # With options ++ pssopts = { ++ "rsa_padding_mode" => "pss", ++ "rsa_pss_saltlen" => 20, ++ "rsa_mgf1_md" => "SHA256" ++ } ++ sig_pss = key.sign_raw("SHA1", hash, pssopts) ++ assert_equal true, key.verify("SHA1", sig_pss, data, pssopts) ++ assert_equal true, key.verify_raw("SHA1", sig_pss, hash, pssopts) ++ end ++ ++ def test_sign_verify_raw_legacy ++ key = Fixtures.pkey("rsa-1") ++ bits = key.n.num_bits ++ ++ # Need right size for raw mode ++ plain0 = "x" * (bits/8) ++ cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING) ++ plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING) ++ assert_equal(plain0, plain1) ++ ++ # Need smaller size for pkcs1 mode ++ plain0 = "x" * (bits/8 - 11) ++ cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING) ++ plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING) ++ assert_equal(plain0, plain1) ++ ++ cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default ++ plain1 = key.public_decrypt(cipherdef) ++ assert_equal(plain0, plain1) ++ assert_equal(cipher1, cipherdef) ++ ++ # Failure cases ++ assert_raise(ArgumentError){ key.private_encrypt() } ++ assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) } ++ assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) } ++ end ++ ++ + def test_verify_empty_rsa + rsa = OpenSSL::PKey::RSA.new + assert_raise(OpenSSL::PKey::PKeyError, "[Bug #12783]") { +-- +2.32.0 + + +From 4330b1b9661fcab1172473f4fdd9986602c1e78c Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 18 May 2020 20:24:08 +0900 +Subject: [PATCH 4/6] pkey/rsa: port RSA#{private,public}_{encrypt,decrypt} to + the EVP API + +Implement these methods using the new OpenSSL::PKey::PKey#{encrypt,sign} +family. The definitions are now in lib/openssl/pkey.rb. + +Also, recommend using those generic methods in the documentation. +--- + ext/openssl/lib/openssl/pkey.rb | 106 ++++++++++++++++++++++++ + ext/openssl/ossl_pkey_rsa.c | 141 -------------------------------- + 2 files changed, 106 insertions(+), 141 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 569559e1ce..dd8c7c0b09 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -243,5 +243,111 @@ def new(*args, &blk) # :nodoc: + end + end + end ++ ++ # :call-seq: ++ # rsa.private_encrypt(string) -> String ++ # rsa.private_encrypt(string, padding) -> String ++ # ++ # Encrypt +string+ with the private key. +padding+ defaults to ++ # PKCS1_PADDING. The encrypted string output can be decrypted using ++ # #public_decrypt. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and ++ # PKey::PKey#verify_recover instead. ++ def private_encrypt(string, padding = PKCS1_PADDING) ++ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" ++ private? or raise OpenSSL::PKey::RSAError, "private key needed." ++ begin ++ sign_raw(nil, string, { ++ "rsa_padding_mode" => translate_padding_mode(padding), ++ }) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::RSAError, $!.message ++ end ++ end ++ ++ # :call-seq: ++ # rsa.public_decrypt(string) -> String ++ # rsa.public_decrypt(string, padding) -> String ++ # ++ # Decrypt +string+, which has been encrypted with the private key, with the ++ # public key. +padding+ defaults to PKCS1_PADDING. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and ++ # PKey::PKey#verify_recover instead. ++ def public_decrypt(string, padding = PKCS1_PADDING) ++ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" ++ begin ++ verify_recover(nil, string, { ++ "rsa_padding_mode" => translate_padding_mode(padding), ++ }) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::RSAError, $!.message ++ end ++ end ++ ++ # :call-seq: ++ # rsa.public_encrypt(string) -> String ++ # rsa.public_encrypt(string, padding) -> String ++ # ++ # Encrypt +string+ with the public key. +padding+ defaults to ++ # PKCS1_PADDING. The encrypted string output can be decrypted using ++ # #private_decrypt. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead. ++ def public_encrypt(data, padding = PKCS1_PADDING) ++ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" ++ begin ++ encrypt(data, { ++ "rsa_padding_mode" => translate_padding_mode(padding), ++ }) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::RSAError, $!.message ++ end ++ end ++ ++ # :call-seq: ++ # rsa.private_decrypt(string) -> String ++ # rsa.private_decrypt(string, padding) -> String ++ # ++ # Decrypt +string+, which has been encrypted with the public key, with the ++ # private key. +padding+ defaults to PKCS1_PADDING. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead. ++ def private_decrypt(data, padding = PKCS1_PADDING) ++ n or raise OpenSSL::PKey::RSAError, "incomplete RSA" ++ private? or raise OpenSSL::PKey::RSAError, "private key needed." ++ begin ++ decrypt(data, { ++ "rsa_padding_mode" => translate_padding_mode(padding), ++ }) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::RSAError, $!.message ++ end ++ end ++ ++ PKCS1_PADDING = 1 ++ SSLV23_PADDING = 2 ++ NO_PADDING = 3 ++ PKCS1_OAEP_PADDING = 4 ++ ++ private def translate_padding_mode(num) ++ case num ++ when PKCS1_PADDING ++ "pkcs1" ++ when SSLV23_PADDING ++ "sslv23" ++ when NO_PADDING ++ "none" ++ when PKCS1_OAEP_PADDING ++ "oaep" ++ else ++ raise OpenSSL::PKey::PKeyError, "unsupported padding mode" ++ end ++ end + end + end +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 1c5476cdcd..8ebd3ec559 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -229,138 +229,6 @@ ossl_rsa_to_der(VALUE self) + return ossl_pkey_export_spki(self, 1); + } + +-/* +- * call-seq: +- * rsa.public_encrypt(string) => String +- * rsa.public_encrypt(string, padding) => String +- * +- * Encrypt _string_ with the public key. _padding_ defaults to PKCS1_PADDING. +- * The encrypted string output can be decrypted using #private_decrypt. +- */ +-static VALUE +-ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self) +-{ +- RSA *rsa; +- const BIGNUM *rsa_n; +- int buf_len, pad; +- VALUE str, buffer, padding; +- +- GetRSA(self, rsa); +- RSA_get0_key(rsa, &rsa_n, NULL, NULL); +- if (!rsa_n) +- ossl_raise(eRSAError, "incomplete RSA"); +- rb_scan_args(argc, argv, "11", &buffer, &padding); +- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); +- StringValue(buffer); +- str = rb_str_new(0, RSA_size(rsa)); +- buf_len = RSA_public_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), +- (unsigned char *)RSTRING_PTR(str), rsa, pad); +- if (buf_len < 0) ossl_raise(eRSAError, NULL); +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- +-/* +- * call-seq: +- * rsa.public_decrypt(string) => String +- * rsa.public_decrypt(string, padding) => String +- * +- * Decrypt _string_, which has been encrypted with the private key, with the +- * public key. _padding_ defaults to PKCS1_PADDING. +- */ +-static VALUE +-ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) +-{ +- RSA *rsa; +- const BIGNUM *rsa_n; +- int buf_len, pad; +- VALUE str, buffer, padding; +- +- GetRSA(self, rsa); +- RSA_get0_key(rsa, &rsa_n, NULL, NULL); +- if (!rsa_n) +- ossl_raise(eRSAError, "incomplete RSA"); +- rb_scan_args(argc, argv, "11", &buffer, &padding); +- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); +- StringValue(buffer); +- str = rb_str_new(0, RSA_size(rsa)); +- buf_len = RSA_public_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), +- (unsigned char *)RSTRING_PTR(str), rsa, pad); +- if (buf_len < 0) ossl_raise(eRSAError, NULL); +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- +-/* +- * call-seq: +- * rsa.private_encrypt(string) => String +- * rsa.private_encrypt(string, padding) => String +- * +- * Encrypt _string_ with the private key. _padding_ defaults to PKCS1_PADDING. +- * The encrypted string output can be decrypted using #public_decrypt. +- */ +-static VALUE +-ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self) +-{ +- RSA *rsa; +- const BIGNUM *rsa_n; +- int buf_len, pad; +- VALUE str, buffer, padding; +- +- GetRSA(self, rsa); +- RSA_get0_key(rsa, &rsa_n, NULL, NULL); +- if (!rsa_n) +- ossl_raise(eRSAError, "incomplete RSA"); +- if (!RSA_PRIVATE(self, rsa)) +- ossl_raise(eRSAError, "private key needed."); +- rb_scan_args(argc, argv, "11", &buffer, &padding); +- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); +- StringValue(buffer); +- str = rb_str_new(0, RSA_size(rsa)); +- buf_len = RSA_private_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), +- (unsigned char *)RSTRING_PTR(str), rsa, pad); +- if (buf_len < 0) ossl_raise(eRSAError, NULL); +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- +-/* +- * call-seq: +- * rsa.private_decrypt(string) => String +- * rsa.private_decrypt(string, padding) => String +- * +- * Decrypt _string_, which has been encrypted with the public key, with the +- * private key. _padding_ defaults to PKCS1_PADDING. +- */ +-static VALUE +-ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) +-{ +- RSA *rsa; +- const BIGNUM *rsa_n; +- int buf_len, pad; +- VALUE str, buffer, padding; +- +- GetRSA(self, rsa); +- RSA_get0_key(rsa, &rsa_n, NULL, NULL); +- if (!rsa_n) +- ossl_raise(eRSAError, "incomplete RSA"); +- if (!RSA_PRIVATE(self, rsa)) +- ossl_raise(eRSAError, "private key needed."); +- rb_scan_args(argc, argv, "11", &buffer, &padding); +- pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); +- StringValue(buffer); +- str = rb_str_new(0, RSA_size(rsa)); +- buf_len = RSA_private_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), +- (unsigned char *)RSTRING_PTR(str), rsa, pad); +- if (buf_len < 0) ossl_raise(eRSAError, NULL); +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- + /* + * call-seq: + * rsa.sign_pss(digest, data, salt_length:, mgf1_hash:) -> String +@@ -657,10 +525,6 @@ Init_ossl_rsa(void) + rb_define_alias(cRSA, "to_pem", "export"); + rb_define_alias(cRSA, "to_s", "export"); + rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0); +- rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, -1); +- rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1); +- rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1); +- rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, -1); + rb_define_method(cRSA, "sign_pss", ossl_rsa_sign_pss, -1); + rb_define_method(cRSA, "verify_pss", ossl_rsa_verify_pss, -1); + +@@ -678,11 +542,6 @@ Init_ossl_rsa(void) + + rb_define_method(cRSA, "params", ossl_rsa_get_params, 0); + +- DefRSAConst(PKCS1_PADDING); +- DefRSAConst(SSLV23_PADDING); +- DefRSAConst(NO_PADDING); +- DefRSAConst(PKCS1_OAEP_PADDING); +- + /* + * TODO: Test it + rb_define_method(cRSA, "blinding_on!", ossl_rsa_blinding_on, 0); +-- +2.32.0 + + +From d45a31cf70f5a55d7f6cf5082efc4dbb68d1169d Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 10 Jul 2020 13:43:20 +0900 +Subject: [PATCH 5/6] pkey/ec: refactor EC#dsa_{sign,verify}_asn1 with + PKey#{sign,verify}_raw + +With the newly added OpenSSL::PKey::PKey#{sign,verify}_raw, +OpenSSL::PKey::EC's low level signing operation methods can be +implemented in Ruby. The definitions are now in lib/openssl/pkey.rb. +--- + ext/openssl/lib/openssl/pkey.rb | 22 +++++++++++++ + ext/openssl/ossl_pkey_ec.c | 55 --------------------------------- + 2 files changed, 22 insertions(+), 55 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index dd8c7c0b09..e587109694 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -164,6 +164,28 @@ def new(*args, &blk) # :nodoc: + class EC + include OpenSSL::Marshal + ++ # :call-seq: ++ # key.dsa_sign_asn1(data) -> String ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. ++ def dsa_sign_asn1(data) ++ sign_raw(nil, data) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::ECError, $!.message ++ end ++ ++ # :call-seq: ++ # key.dsa_verify_asn1(data, sig) -> true | false ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. ++ def dsa_verify_asn1(data, sig) ++ verify_raw(nil, sig, data) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::ECError, $!.message ++ end ++ + # :call-seq: + # ec.dh_compute_key(pubkey) -> string + # +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index 829529d4b9..f52e67079d 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -476,57 +476,6 @@ static VALUE ossl_ec_key_check_key(VALUE self) + return Qtrue; + } + +-/* +- * call-seq: +- * key.dsa_sign_asn1(data) => String +- * +- * See the OpenSSL documentation for ECDSA_sign() +- */ +-static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data) +-{ +- EC_KEY *ec; +- unsigned int buf_len; +- VALUE str; +- +- GetEC(self, ec); +- StringValue(data); +- +- if (EC_KEY_get0_private_key(ec) == NULL) +- ossl_raise(eECError, "Private EC key needed!"); +- +- str = rb_str_new(0, ECDSA_size(ec)); +- if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1) +- ossl_raise(eECError, "ECDSA_sign"); +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- +-/* +- * call-seq: +- * key.dsa_verify_asn1(data, sig) => true or false +- * +- * See the OpenSSL documentation for ECDSA_verify() +- */ +-static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) +-{ +- EC_KEY *ec; +- +- GetEC(self, ec); +- StringValue(data); +- StringValue(sig); +- +- switch (ECDSA_verify(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data), +- (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), ec)) { +- case 1: +- return Qtrue; +- case 0: +- return Qfalse; +- default: +- ossl_raise(eECError, "ECDSA_verify"); +- } +-} +- + /* + * OpenSSL::PKey::EC::Group + */ +@@ -1615,10 +1564,6 @@ void Init_ossl_ec(void) + rb_define_alias(cEC, "generate_key", "generate_key!"); + rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0); + +- rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1); +- rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2); +-/* do_sign/do_verify */ +- + rb_define_method(cEC, "export", ossl_ec_key_export, -1); + rb_define_alias(cEC, "to_pem", "export"); + rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0); +-- +2.32.0 + + +From 2494043e302c920e90e06cce443c5cd428e183f7 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 10 Jul 2020 13:51:18 +0900 +Subject: [PATCH 6/6] pkey/dsa: refactor DSA#sys{sign,verify} with + PKey#{sign,verify}_raw + +With the newly added OpenSSL::PKey::PKey#{sign,verify}_raw, +OpenSSL::PKey::DSA's low level signing operation methods can be +implemented in Ruby. The definitions are now in lib/openssl/pkey.rb. +--- + ext/openssl/lib/openssl/pkey.rb | 54 ++++++++++++++++++++ + ext/openssl/ossl_pkey_dsa.c | 88 --------------------------------- + 2 files changed, 54 insertions(+), 88 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index e587109694..f6bf5892b0 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -158,6 +158,60 @@ def new(*args, &blk) # :nodoc: + end + end + end ++ ++ # :call-seq: ++ # dsa.syssign(string) -> string ++ # ++ # Computes and returns the \DSA signature of +string+, where +string+ is ++ # expected to be an already-computed message digest of the original input ++ # data. The signature is issued using the private key of this DSA instance. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. ++ # ++ # +string+:: ++ # A message digest of the original input data to be signed. ++ # ++ # Example: ++ # dsa = OpenSSL::PKey::DSA.new(2048) ++ # doc = "Sign me" ++ # digest = OpenSSL::Digest.digest('SHA1', doc) ++ # ++ # # With legacy #syssign and #sysverify: ++ # sig = dsa.syssign(digest) ++ # p dsa.sysverify(digest, sig) #=> true ++ # ++ # # With #sign_raw and #verify_raw: ++ # sig = dsa.sign_raw(nil, digest) ++ # p dsa.verify_raw(nil, sig, digest) #=> true ++ def syssign(string) ++ q or raise OpenSSL::PKey::DSAError, "incomplete DSA" ++ private? or raise OpenSSL::PKey::DSAError, "Private DSA key needed!" ++ begin ++ sign_raw(nil, string) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::DSAError, $!.message ++ end ++ end ++ ++ # :call-seq: ++ # dsa.sysverify(digest, sig) -> true | false ++ # ++ # Verifies whether the signature is valid given the message digest input. ++ # It does so by validating +sig+ using the public key of this DSA instance. ++ # ++ # Deprecated in version 3.0. ++ # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead. ++ # ++ # +digest+:: ++ # A message digest of the original input data to be signed. ++ # +sig+:: ++ # A \DSA signature value. ++ def sysverify(digest, sig) ++ verify_raw(nil, sig, digest) ++ rescue OpenSSL::PKey::PKeyError ++ raise OpenSSL::PKey::DSAError, $!.message ++ end + end + + if defined?(EC) +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index ab9ac781e8..7af00eebec 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -264,92 +264,6 @@ ossl_dsa_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * dsa.syssign(string) -> aString +- * +- * Computes and returns the DSA signature of _string_, where _string_ is +- * expected to be an already-computed message digest of the original input +- * data. The signature is issued using the private key of this DSA instance. +- * +- * === Parameters +- * * _string_ is a message digest of the original input data to be signed. +- * +- * === Example +- * dsa = OpenSSL::PKey::DSA.new(2048) +- * doc = "Sign me" +- * digest = OpenSSL::Digest.digest('SHA1', doc) +- * sig = dsa.syssign(digest) +- * +- * +- */ +-static VALUE +-ossl_dsa_sign(VALUE self, VALUE data) +-{ +- DSA *dsa; +- const BIGNUM *dsa_q; +- unsigned int buf_len; +- VALUE str; +- +- GetDSA(self, dsa); +- DSA_get0_pqg(dsa, NULL, &dsa_q, NULL); +- if (!dsa_q) +- ossl_raise(eDSAError, "incomplete DSA"); +- if (!DSA_PRIVATE(self, dsa)) +- ossl_raise(eDSAError, "Private DSA key needed!"); +- StringValue(data); +- str = rb_str_new(0, DSA_size(dsa)); +- if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data), +- (unsigned char *)RSTRING_PTR(str), +- &buf_len, dsa)) { /* type is ignored (0) */ +- ossl_raise(eDSAError, NULL); +- } +- rb_str_set_len(str, buf_len); +- +- return str; +-} +- +-/* +- * call-seq: +- * dsa.sysverify(digest, sig) -> true | false +- * +- * Verifies whether the signature is valid given the message digest input. It +- * does so by validating _sig_ using the public key of this DSA instance. +- * +- * === Parameters +- * * _digest_ is a message digest of the original input data to be signed +- * * _sig_ is a DSA signature value +- * +- * === Example +- * dsa = OpenSSL::PKey::DSA.new(2048) +- * doc = "Sign me" +- * digest = OpenSSL::Digest.digest('SHA1', doc) +- * sig = dsa.syssign(digest) +- * puts dsa.sysverify(digest, sig) # => true +- * +- */ +-static VALUE +-ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) +-{ +- DSA *dsa; +- int ret; +- +- GetDSA(self, dsa); +- StringValue(digest); +- StringValue(sig); +- /* type is ignored (0) */ +- ret = DSA_verify(0, (unsigned char *)RSTRING_PTR(digest), RSTRING_LENINT(digest), +- (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), dsa); +- if (ret < 0) { +- ossl_raise(eDSAError, NULL); +- } +- else if (ret == 1) { +- return Qtrue; +- } +- +- return Qfalse; +-} +- + /* + * Document-method: OpenSSL::PKey::DSA#set_pqg + * call-seq: +@@ -404,8 +318,6 @@ Init_ossl_dsa(void) + rb_define_alias(cDSA, "to_pem", "export"); + rb_define_alias(cDSA, "to_s", "export"); + rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0); +- rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1); +- rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2); + + DEF_OSSL_PKEY_BN(cDSA, dsa, p); + DEF_OSSL_PKEY_BN(cDSA, dsa, q); +-- +2.32.0 + diff --git a/ruby-3.1.0-Migrate-from-the-low-level-HMAC-API-to-the-EVP-API.patch b/ruby-3.1.0-Migrate-from-the-low-level-HMAC-API-to-the-EVP-API.patch new file mode 100644 index 0000000..d25cae9 --- /dev/null +++ b/ruby-3.1.0-Migrate-from-the-low-level-HMAC-API-to-the-EVP-API.patch @@ -0,0 +1,523 @@ +From 8253d7c9cea16c2aa009b59db4f5d93afb74c6eb Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 30 Jun 2020 14:27:13 +0900 +Subject: [PATCH 1/2] hmac: add a test case for OpenSSL::HMAC singleton methods + +--- + test/openssl/test_hmac.rb | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/test/openssl/test_hmac.rb b/test/openssl/test_hmac.rb +index 9cb3c5a86..7202a5902 100644 +--- a/test/openssl/test_hmac.rb ++++ b/test/openssl/test_hmac.rb +@@ -49,6 +49,15 @@ def test_eq + refute_equal h1, h2.digest + refute_equal h1, h3 + end ++ ++ def test_singleton_methods ++ # RFC 2202 2. Test Cases for HMAC-MD5 ++ key = ["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*") ++ digest = OpenSSL::HMAC.digest("MD5", key, "Hi There") ++ assert_equal ["9294727a3638bb1c13f48ef8158bfc9d"].pack("H*"), digest ++ hexdigest = OpenSSL::HMAC.hexdigest("MD5", key, "Hi There") ++ assert_equal "9294727a3638bb1c13f48ef8158bfc9d", hexdigest ++ end + end + + end + +From 0317e2fc028be40a7d64d0e4337d3e21539613ce Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 18 May 2020 16:15:07 +0900 +Subject: [PATCH 2/2] hmac: migrate from the low-level HMAC API to the EVP API + +Use the EVP API instead of the low-level HMAC API. Use of the HMAC API +has been discouraged and is being marked as deprecated starting from +OpenSSL 3.0.0. + +The two singleton methods OpenSSL::HMAC, HMAC.digest and HMAC.hexdigest +are now in lib/openssl/hmac.rb. +--- + ext/openssl/extconf.rb | 3 +- + ext/openssl/lib/openssl/hmac.rb | 40 +++++++ + ext/openssl/openssl_missing.c | 26 ----- + ext/openssl/openssl_missing.h | 10 +- + ext/openssl/ossl.h | 1 - + ext/openssl/ossl_hmac.c | 179 ++++++++------------------------ + 6 files changed, 89 insertions(+), 170 deletions(-) + +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index 693e55cd9..063498a76 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -141,8 +141,7 @@ def find_openssl_library + have_func("BN_GENCB_get_arg") + have_func("EVP_MD_CTX_new") + have_func("EVP_MD_CTX_free") +-have_func("HMAC_CTX_new") +-have_func("HMAC_CTX_free") ++have_func("EVP_MD_CTX_pkey_ctx") + have_func("X509_STORE_get_ex_data") + have_func("X509_STORE_set_ex_data") + have_func("X509_STORE_get_ex_new_index") +diff --git a/ext/openssl/lib/openssl/hmac.rb b/ext/openssl/lib/openssl/hmac.rb +index 3d4427611d..9bc8bc8df3 100644 +--- a/ext/openssl/lib/openssl/hmac.rb ++++ b/ext/openssl/lib/openssl/hmac.rb +@@ -9,5 +9,45 @@ def ==(other) + + OpenSSL.fixed_length_secure_compare(self.digest, other.digest) + end ++ ++ class << self ++ # :call-seq: ++ # HMAC.digest(digest, key, data) -> aString ++ # ++ # Returns the authentication code as a binary string. The _digest_ parameter ++ # specifies the digest algorithm to use. This may be a String representing ++ # the algorithm name or an instance of OpenSSL::Digest. ++ # ++ # === Example ++ # key = 'key' ++ # data = 'The quick brown fox jumps over the lazy dog' ++ # ++ # hmac = OpenSSL::HMAC.digest('SHA1', key, data) ++ # #=> "\xDE|\x9B\x85\xB8\xB7\x8A\xA6\xBC\x8Az6\xF7\n\x90p\x1C\x9D\xB4\xD9" ++ def digest(digest, key, data) ++ hmac = new(key, digest) ++ hmac << data ++ hmac.digest ++ end ++ ++ # :call-seq: ++ # HMAC.hexdigest(digest, key, data) -> aString ++ # ++ # Returns the authentication code as a hex-encoded string. The _digest_ ++ # parameter specifies the digest algorithm to use. This may be a String ++ # representing the algorithm name or an instance of OpenSSL::Digest. ++ # ++ # === Example ++ # key = 'key' ++ # data = 'The quick brown fox jumps over the lazy dog' ++ # ++ # hmac = OpenSSL::HMAC.hexdigest('SHA1', key, data) ++ # #=> "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" ++ def hexdigest(digest, key, data) ++ hmac = new(key, digest) ++ hmac << data ++ hmac.hexdigest ++ end ++ end + end + end +diff --git a/ext/openssl/openssl_missing.c b/ext/openssl/openssl_missing.c +index b36ef0288..010c158dc 100644 +--- a/ext/openssl/openssl_missing.c ++++ b/ext/openssl/openssl_missing.c +@@ -13,9 +13,6 @@ + #if !defined(OPENSSL_NO_ENGINE) + # include + #endif +-#if !defined(OPENSSL_NO_HMAC) +-# include +-#endif + #include + + #include "openssl_missing.h" +@@ -58,29 +55,6 @@ ossl_EC_curve_nist2nid(const char *name) + #endif + + /*** added in 1.1.0 ***/ +-#if !defined(HAVE_HMAC_CTX_NEW) +-HMAC_CTX * +-ossl_HMAC_CTX_new(void) +-{ +- HMAC_CTX *ctx = OPENSSL_malloc(sizeof(HMAC_CTX)); +- if (!ctx) +- return NULL; +- HMAC_CTX_init(ctx); +- return ctx; +-} +-#endif +- +-#if !defined(HAVE_HMAC_CTX_FREE) +-void +-ossl_HMAC_CTX_free(HMAC_CTX *ctx) +-{ +- if (ctx) { +- HMAC_CTX_cleanup(ctx); +- OPENSSL_free(ctx); +- } +-} +-#endif +- + #if !defined(HAVE_X509_CRL_GET0_SIGNATURE) + void + ossl_X509_CRL_get0_signature(const X509_CRL *crl, const ASN1_BIT_STRING **psig, +diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h +index 7d218f86f..06d2a9082 100644 +--- a/ext/openssl/openssl_missing.h ++++ b/ext/openssl/openssl_missing.h +@@ -54,14 +54,8 @@ int ossl_EC_curve_nist2nid(const char *); + # define EVP_MD_CTX_free EVP_MD_CTX_destroy + #endif + +-#if !defined(HAVE_HMAC_CTX_NEW) +-HMAC_CTX *ossl_HMAC_CTX_new(void); +-# define HMAC_CTX_new ossl_HMAC_CTX_new +-#endif +- +-#if !defined(HAVE_HMAC_CTX_FREE) +-void ossl_HMAC_CTX_free(HMAC_CTX *); +-# define HMAC_CTX_free ossl_HMAC_CTX_free ++#if !defined(HAVE_EVP_MD_CTX_PKEY_CTX) ++# define EVP_MD_CTX_pkey_ctx(x) (x)->pctx + #endif + + #if !defined(HAVE_X509_STORE_GET_EX_DATA) +diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h +index c20f506bd..577eb6d6b 100644 +--- a/ext/openssl/ossl.h ++++ b/ext/openssl/ossl.h +@@ -24,7 +24,6 @@ + #include + #include + #include +-#include + #include + #include + #ifndef OPENSSL_NO_TS +diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c +index 70e9fb819..a21db6c48 100644 +--- a/ext/openssl/ossl_hmac.c ++++ b/ext/openssl/ossl_hmac.c +@@ -7,14 +7,12 @@ + * This program is licensed under the same licence as Ruby. + * (See the file 'LICENCE'.) + */ +-#if !defined(OPENSSL_NO_HMAC) +- + #include "ossl.h" + + #define NewHMAC(klass) \ + TypedData_Wrap_Struct((klass), &ossl_hmac_type, 0) + #define GetHMAC(obj, ctx) do { \ +- TypedData_Get_Struct((obj), HMAC_CTX, &ossl_hmac_type, (ctx)); \ ++ TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_hmac_type, (ctx)); \ + if (!(ctx)) { \ + ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \ + } \ +@@ -36,7 +34,7 @@ VALUE eHMACError; + static void + ossl_hmac_free(void *ctx) + { +- HMAC_CTX_free(ctx); ++ EVP_MD_CTX_free(ctx); + } + + static const rb_data_type_t ossl_hmac_type = { +@@ -51,12 +49,12 @@ static VALUE + ossl_hmac_alloc(VALUE klass) + { + VALUE obj; +- HMAC_CTX *ctx; ++ EVP_MD_CTX *ctx; + + obj = NewHMAC(klass); +- ctx = HMAC_CTX_new(); ++ ctx = EVP_MD_CTX_new(); + if (!ctx) +- ossl_raise(eHMACError, NULL); ++ ossl_raise(eHMACError, "EVP_MD_CTX"); + RTYPEDDATA_DATA(obj) = ctx; + + return obj; +@@ -76,8 +74,7 @@ ossl_hmac_alloc(VALUE klass) + * === Example + * + * key = 'key' +- * digest = OpenSSL::Digest.new('sha1') +- * instance = OpenSSL::HMAC.new(key, digest) ++ * instance = OpenSSL::HMAC.new(key, 'SHA1') + * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f + * instance.class + * #=> OpenSSL::HMAC +@@ -86,7 +83,7 @@ ossl_hmac_alloc(VALUE klass) + * + * Two instances can be securely compared with #== in constant time: + * +- * other_instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1')) ++ * other_instance = OpenSSL::HMAC.new('key', 'SHA1') + * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f + * instance == other_instance + * #=> true +@@ -95,12 +92,23 @@ ossl_hmac_alloc(VALUE klass) + static VALUE + ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest) + { +- HMAC_CTX *ctx; ++ EVP_MD_CTX *ctx; ++ EVP_PKEY *pkey; + +- StringValue(key); + GetHMAC(self, ctx); +- HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LENINT(key), +- ossl_evp_get_digestbyname(digest), NULL); ++ StringValue(key); ++ pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, ++ (unsigned char *)RSTRING_PTR(key), ++ RSTRING_LENINT(key)); ++ if (!pkey) ++ ossl_raise(eHMACError, "EVP_PKEY_new_mac_key"); ++ if (EVP_DigestSignInit(ctx, NULL, ossl_evp_get_digestbyname(digest), ++ NULL, pkey) != 1) { ++ EVP_PKEY_free(pkey); ++ ossl_raise(eHMACError, "EVP_DigestSignInit"); ++ } ++ /* Decrement reference counter; EVP_MD_CTX still keeps it */ ++ EVP_PKEY_free(pkey); + + return self; + } +@@ -108,16 +116,15 @@ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest) + static VALUE + ossl_hmac_copy(VALUE self, VALUE other) + { +- HMAC_CTX *ctx1, *ctx2; ++ EVP_MD_CTX *ctx1, *ctx2; + + rb_check_frozen(self); + if (self == other) return self; + + GetHMAC(self, ctx1); + GetHMAC(other, ctx2); +- +- if (!HMAC_CTX_copy(ctx1, ctx2)) +- ossl_raise(eHMACError, "HMAC_CTX_copy"); ++ if (EVP_MD_CTX_copy(ctx1, ctx2) != 1) ++ ossl_raise(eHMACError, "EVP_MD_CTX_copy"); + return self; + } + +@@ -142,33 +149,16 @@ ossl_hmac_copy(VALUE self, VALUE other) + static VALUE + ossl_hmac_update(VALUE self, VALUE data) + { +- HMAC_CTX *ctx; ++ EVP_MD_CTX *ctx; + + StringValue(data); + GetHMAC(self, ctx); +- HMAC_Update(ctx, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)); ++ if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1) ++ ossl_raise(eHMACError, "EVP_DigestSignUpdate"); + + return self; + } + +-static void +-hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len) +-{ +- HMAC_CTX *final; +- +- final = HMAC_CTX_new(); +- if (!final) +- ossl_raise(eHMACError, "HMAC_CTX_new"); +- +- if (!HMAC_CTX_copy(final, ctx)) { +- HMAC_CTX_free(final); +- ossl_raise(eHMACError, "HMAC_CTX_copy"); +- } +- +- HMAC_Final(final, buf, buf_len); +- HMAC_CTX_free(final); +-} +- + /* + * call-seq: + * hmac.digest -> string +@@ -176,7 +166,7 @@ hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len) + * Returns the authentication code an instance represents as a binary string. + * + * === Example +- * instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1')) ++ * instance = OpenSSL::HMAC.new('key', 'SHA1') + * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f + * instance.digest + * #=> "\xF4+\xB0\xEE\xB0\x18\xEB\xBDE\x97\xAEr\x13q\x1E\xC6\a`\x84?" +@@ -184,15 +174,16 @@ hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len) + static VALUE + ossl_hmac_digest(VALUE self) + { +- HMAC_CTX *ctx; +- unsigned int buf_len; ++ EVP_MD_CTX *ctx; ++ size_t buf_len; + VALUE ret; + + GetHMAC(self, ctx); + ret = rb_str_new(NULL, EVP_MAX_MD_SIZE); +- hmac_final(ctx, (unsigned char *)RSTRING_PTR(ret), &buf_len); +- assert(buf_len <= EVP_MAX_MD_SIZE); +- rb_str_set_len(ret, buf_len); ++ if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(ret), ++ &buf_len) != 1) ++ ossl_raise(eHMACError, "EVP_DigestSignFinal"); ++ rb_str_set_len(ret, (long)buf_len); + + return ret; + } +@@ -207,13 +198,14 @@ ossl_hmac_digest(VALUE self) + static VALUE + ossl_hmac_hexdigest(VALUE self) + { +- HMAC_CTX *ctx; ++ EVP_MD_CTX *ctx; + unsigned char buf[EVP_MAX_MD_SIZE]; +- unsigned int buf_len; ++ size_t buf_len; + VALUE ret; + + GetHMAC(self, ctx); +- hmac_final(ctx, buf, &buf_len); ++ if (EVP_DigestSignFinal(ctx, buf, &buf_len) != 1) ++ ossl_raise(eHMACError, "EVP_DigestSignFinal"); + ret = rb_str_new(NULL, buf_len * 2); + ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len); + +@@ -230,7 +222,7 @@ ossl_hmac_hexdigest(VALUE self) + * === Example + * + * data = "The quick brown fox jumps over the lazy dog" +- * instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1')) ++ * instance = OpenSSL::HMAC.new('key', 'SHA1') + * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f + * + * instance.update(data) +@@ -242,84 +234,17 @@ ossl_hmac_hexdigest(VALUE self) + static VALUE + ossl_hmac_reset(VALUE self) + { +- HMAC_CTX *ctx; ++ EVP_MD_CTX *ctx; ++ EVP_PKEY *pkey; + + GetHMAC(self, ctx); +- HMAC_Init_ex(ctx, NULL, 0, NULL, NULL); ++ pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_pkey_ctx(ctx)); ++ if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_md(ctx), NULL, pkey) != 1) ++ ossl_raise(eHMACError, "EVP_DigestSignInit"); + + return self; + } + +-/* +- * call-seq: +- * HMAC.digest(digest, key, data) -> aString +- * +- * Returns the authentication code as a binary string. The _digest_ parameter +- * specifies the digest algorithm to use. This may be a String representing +- * the algorithm name or an instance of OpenSSL::Digest. +- * +- * === Example +- * +- * key = 'key' +- * data = 'The quick brown fox jumps over the lazy dog' +- * +- * hmac = OpenSSL::HMAC.digest('sha1', key, data) +- * #=> "\xDE|\x9B\x85\xB8\xB7\x8A\xA6\xBC\x8Az6\xF7\n\x90p\x1C\x9D\xB4\xD9" +- * +- */ +-static VALUE +-ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data) +-{ +- unsigned char *buf; +- unsigned int buf_len; +- +- StringValue(key); +- StringValue(data); +- buf = HMAC(ossl_evp_get_digestbyname(digest), RSTRING_PTR(key), +- RSTRING_LENINT(key), (unsigned char *)RSTRING_PTR(data), +- RSTRING_LEN(data), NULL, &buf_len); +- +- return rb_str_new((const char *)buf, buf_len); +-} +- +-/* +- * call-seq: +- * HMAC.hexdigest(digest, key, data) -> aString +- * +- * Returns the authentication code as a hex-encoded string. The _digest_ +- * parameter specifies the digest algorithm to use. This may be a String +- * representing the algorithm name or an instance of OpenSSL::Digest. +- * +- * === Example +- * +- * key = 'key' +- * data = 'The quick brown fox jumps over the lazy dog' +- * +- * hmac = OpenSSL::HMAC.hexdigest('sha1', key, data) +- * #=> "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" +- * +- */ +-static VALUE +-ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data) +-{ +- unsigned char buf[EVP_MAX_MD_SIZE]; +- unsigned int buf_len; +- VALUE ret; +- +- StringValue(key); +- StringValue(data); +- +- if (!HMAC(ossl_evp_get_digestbyname(digest), RSTRING_PTR(key), +- RSTRING_LENINT(key), (unsigned char *)RSTRING_PTR(data), +- RSTRING_LEN(data), buf, &buf_len)) +- ossl_raise(eHMACError, "HMAC"); +- +- ret = rb_str_new(NULL, buf_len * 2); +- ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len); +- +- return ret; +-} +- + /* + * INIT + */ +@@ -353,8 +278,7 @@ Init_ossl_hmac(void) + * data1 = File.read("file1") + * data2 = File.read("file2") + * key = "key" +- * digest = OpenSSL::Digest.new('SHA256') +- * hmac = OpenSSL::HMAC.new(key, digest) ++ * hmac = OpenSSL::HMAC.new(key, 'SHA256') + * hmac << data1 + * hmac << data2 + * mac = hmac.digest +@@ -364,8 +288,6 @@ Init_ossl_hmac(void) + cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject); + + rb_define_alloc_func(cHMAC, ossl_hmac_alloc); +- rb_define_singleton_method(cHMAC, "digest", ossl_hmac_s_digest, 3); +- rb_define_singleton_method(cHMAC, "hexdigest", ossl_hmac_s_hexdigest, 3); + + rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2); + rb_define_method(cHMAC, "initialize_copy", ossl_hmac_copy, 1); +@@ -378,12 +300,3 @@ Init_ossl_hmac(void) + rb_define_alias(cHMAC, "inspect", "hexdigest"); + rb_define_alias(cHMAC, "to_s", "hexdigest"); + } +- +-#else /* NO_HMAC */ +-# warning >>> OpenSSL is compiled without HMAC support <<< +-void +-Init_ossl_hmac(void) +-{ +- rb_warning("HMAC is not available: OpenSSL is compiled without HMAC."); +-} +-#endif /* NO_HMAC */ +-- +2.34.1 + diff --git a/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch b/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch new file mode 100644 index 0000000..b906c19 --- /dev/null +++ b/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support-part-2.patch @@ -0,0 +1,458 @@ +From 91d04f991f8b9910efea7bbe5aecb0fea2bbd5fa Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 24 Oct 2021 17:50:18 +0900 +Subject: [PATCH 1/8] cipher: update test_ciphers + +Do not attempt to actually use all algorithms. Not all algorithms listed +in OpenSSL::Cipher.ciphers are always available. +--- + test/openssl/test_cipher.rb | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb +index 6d18c0c8..b5fdf0b3 100644 +--- a/test/openssl/test_cipher.rb ++++ b/test/openssl/test_cipher.rb +@@ -135,14 +135,11 @@ def test_ctr_if_exists + end + + def test_ciphers +- OpenSSL::Cipher.ciphers.each{|name| +- next if /netbsd/ =~ RUBY_PLATFORM && /idea|rc5/i =~ name +- begin +- assert_kind_of(OpenSSL::Cipher, OpenSSL::Cipher.new(name)) +- rescue OpenSSL::Cipher::CipherError => e +- raise unless /wrap/ =~ name and /wrap mode not allowed/ =~ e.message +- end +- } ++ ciphers = OpenSSL::Cipher.ciphers ++ assert_kind_of Array, ciphers ++ assert_include ciphers, "aes-128-cbc" ++ assert_include ciphers, "aes128" # alias of aes-128-cbc ++ assert_include ciphers, "aes-128-gcm" + end + + def test_AES + +From 6a60c7b2e7b6afe8b8c98d864ef2740094d86e1d Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 11 Dec 2021 16:27:42 +0900 +Subject: [PATCH 2/8] hmac: fix wrong usage of EVP_DigestSignFinal() + +According to the manpage, the "siglen" parameter must be initialized +beforehand. +--- + ext/openssl/ossl_hmac.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c +index f89ff2f9..bfe3a74b 100644 +--- a/ext/openssl/ossl_hmac.c ++++ b/ext/openssl/ossl_hmac.c +@@ -175,7 +175,7 @@ static VALUE + ossl_hmac_digest(VALUE self) + { + EVP_MD_CTX *ctx; +- size_t buf_len; ++ size_t buf_len = EVP_MAX_MD_SIZE; + VALUE ret; + + GetHMAC(self, ctx); +@@ -200,7 +200,7 @@ ossl_hmac_hexdigest(VALUE self) + { + EVP_MD_CTX *ctx; + unsigned char buf[EVP_MAX_MD_SIZE]; +- size_t buf_len; ++ size_t buf_len = EVP_MAX_MD_SIZE; + VALUE ret; + + GetHMAC(self, ctx); + +From 46995816392a79d037df5550b2fb226652c06f42 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 11 Dec 2021 16:30:30 +0900 +Subject: [PATCH 3/8] hmac: skip test_dup on OpenSSL 3.0 for now + +EVP_MD_CTX_copy() doesn't seem to work as intended on HMAC EVP_MD_CTX +on OpenSSL 3.0.0 and causes a double free. I haven't found the root +problem yet, but let's skip the test case for now. +--- + test/openssl/test_hmac.rb | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/test/openssl/test_hmac.rb b/test/openssl/test_hmac.rb +index 2f53a813..47cb3718 100644 +--- a/test/openssl/test_hmac.rb ++++ b/test/openssl/test_hmac.rb +@@ -19,6 +19,7 @@ def test_hmac + end + + def test_dup ++ pend "HMAC#initialize_copy is currently broken on OpenSSL 3.0.0" if openssl?(3, 0, 0) + h1 = OpenSSL::HMAC.new("KEY", "MD5") + h1.update("DATA") + h = h1.dup + +From 69a27d8de4bd291cb4eb21a4d715b197e7da5a06 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Thu, 15 Apr 2021 00:51:58 +0900 +Subject: [PATCH 4/8] engine: disable OpenSSL::Engine on OpenSSL 3.0 + +The entire ENGINE API is deprecated in OpenSSL 3.0 in favor of the new +"Provider" concept. + +OpenSSL::Engine will not be defined when compiled with OpenSSL 3.0. +We would need a way to interact with providers from Ruby programs, but +since the concept is completely different from the ENGINE API, it will +not be through the current OpenSSL::Engine interface. +--- + ext/openssl/openssl_missing.c | 3 --- + ext/openssl/ossl.h | 8 +++++--- + ext/openssl/ossl_engine.c | 3 ++- + ext/openssl/ossl_pkey.c | 4 ++++ + 4 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/ext/openssl/openssl_missing.c b/ext/openssl/openssl_missing.c +index 8b93cba6..4415703d 100644 +--- a/ext/openssl/openssl_missing.c ++++ b/ext/openssl/openssl_missing.c +@@ -10,9 +10,6 @@ + #include RUBY_EXTCONF_H + + #include /* memcpy() */ +-#if !defined(OPENSSL_NO_ENGINE) +-# include +-#endif + #include + + #include "openssl_missing.h" +diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h +index 3a0ab1e5..4b512689 100644 +--- a/ext/openssl/ossl.h ++++ b/ext/openssl/ossl.h +@@ -18,6 +18,7 @@ + #include + #include + #include ++ + #include + #include + #include +@@ -30,9 +31,6 @@ + #include + #endif + #include +-#if !defined(OPENSSL_NO_ENGINE) +-# include +-#endif + #if !defined(OPENSSL_NO_OCSP) + # include + #endif +@@ -54,6 +52,10 @@ + (LIBRESSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12)) + #endif + ++#if !defined(OPENSSL_NO_ENGINE) && !OSSL_OPENSSL_PREREQ(3, 0, 0) ++# define OSSL_USE_ENGINE ++#endif ++ + /* + * Common Module + */ +diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c +index 661a1368..1abde7f7 100644 +--- a/ext/openssl/ossl_engine.c ++++ b/ext/openssl/ossl_engine.c +@@ -9,7 +9,8 @@ + */ + #include "ossl.h" + +-#if !defined(OPENSSL_NO_ENGINE) ++#ifdef OSSL_USE_ENGINE ++# include + + #define NewEngine(klass) \ + TypedData_Wrap_Struct((klass), &ossl_engine_type, 0) +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 7030be3c..94760d32 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -9,6 +9,10 @@ + */ + #include "ossl.h" + ++#ifdef OSSL_USE_ENGINE ++# include ++#endif ++ + /* + * Classes + */ + +From b1ee2f23b28c2d0b14fd9b4b9fef13e870370746 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Wed, 17 Nov 2021 11:39:06 +0900 +Subject: [PATCH 5/8] ssl: add constants for new SSL_OP_* flags + +Add all SSL_OP_* constants defined in OpenSSL 3.0.0 which are not +specific to DTLS. +--- + ext/openssl/ossl_ssl.c | 35 +++++++++++++++++++++++++++++------ + 1 file changed, 29 insertions(+), 6 deletions(-) + +diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c +index 3b425ca7..9a0682a7 100644 +--- a/ext/openssl/ossl_ssl.c ++++ b/ext/openssl/ossl_ssl.c +@@ -2941,13 +2941,28 @@ Init_ossl_ssl(void) + rb_define_const(mSSL, "VERIFY_CLIENT_ONCE", INT2NUM(SSL_VERIFY_CLIENT_ONCE)); + + rb_define_const(mSSL, "OP_ALL", ULONG2NUM(SSL_OP_ALL)); ++#ifdef SSL_OP_CLEANSE_PLAINTEXT /* OpenSSL 3.0 */ ++ rb_define_const(mSSL, "OP_CLEANSE_PLAINTEXT", ULONG2NUM(SSL_OP_CLEANSE_PLAINTEXT)); ++#endif + rb_define_const(mSSL, "OP_LEGACY_SERVER_CONNECT", ULONG2NUM(SSL_OP_LEGACY_SERVER_CONNECT)); ++#ifdef SSL_OP_ENABLE_KTLS /* OpenSSL 3.0 */ ++ rb_define_const(mSSL, "OP_ENABLE_KTLS", ULONG2NUM(SSL_OP_ENABLE_KTLS)); ++#endif + #ifdef SSL_OP_TLSEXT_PADDING /* OpenSSL 1.0.1h and OpenSSL 1.0.2 */ + rb_define_const(mSSL, "OP_TLSEXT_PADDING", ULONG2NUM(SSL_OP_TLSEXT_PADDING)); + #endif + #ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG /* OpenSSL 1.0.1f and OpenSSL 1.0.2 */ + rb_define_const(mSSL, "OP_SAFARI_ECDHE_ECDSA_BUG", ULONG2NUM(SSL_OP_SAFARI_ECDHE_ECDSA_BUG)); + #endif ++#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF /* OpenSSL 3.0 */ ++ rb_define_const(mSSL, "OP_IGNORE_UNEXPECTED_EOF", ULONG2NUM(SSL_OP_IGNORE_UNEXPECTED_EOF)); ++#endif ++#ifdef SSL_OP_ALLOW_CLIENT_RENEGOTIATION /* OpenSSL 3.0 */ ++ rb_define_const(mSSL, "OP_ALLOW_CLIENT_RENEGOTIATION", ULONG2NUM(SSL_OP_ALLOW_CLIENT_RENEGOTIATION)); ++#endif ++#ifdef SSL_OP_DISABLE_TLSEXT_CA_NAMES /* OpenSSL 3.0 */ ++ rb_define_const(mSSL, "OP_DISABLE_TLSEXT_CA_NAMES", ULONG2NUM(SSL_OP_DISABLE_TLSEXT_CA_NAMES)); ++#endif + #ifdef SSL_OP_ALLOW_NO_DHE_KEX /* OpenSSL 1.1.1 */ + rb_define_const(mSSL, "OP_ALLOW_NO_DHE_KEX", ULONG2NUM(SSL_OP_ALLOW_NO_DHE_KEX)); + #endif +@@ -2959,13 +2974,15 @@ Init_ossl_ssl(void) + #ifdef SSL_OP_NO_ENCRYPT_THEN_MAC /* OpenSSL 1.1.1 */ + rb_define_const(mSSL, "OP_NO_ENCRYPT_THEN_MAC", ULONG2NUM(SSL_OP_NO_ENCRYPT_THEN_MAC)); + #endif +- rb_define_const(mSSL, "OP_CIPHER_SERVER_PREFERENCE", ULONG2NUM(SSL_OP_CIPHER_SERVER_PREFERENCE)); +- rb_define_const(mSSL, "OP_TLS_ROLLBACK_BUG", ULONG2NUM(SSL_OP_TLS_ROLLBACK_BUG)); +-#ifdef SSL_OP_NO_RENEGOTIATION /* OpenSSL 1.1.1 */ +- rb_define_const(mSSL, "OP_NO_RENEGOTIATION", ULONG2NUM(SSL_OP_NO_RENEGOTIATION)); ++#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT /* OpenSSL 1.1.1 */ ++ rb_define_const(mSSL, "OP_ENABLE_MIDDLEBOX_COMPAT", ULONG2NUM(SSL_OP_ENABLE_MIDDLEBOX_COMPAT)); ++#endif ++#ifdef SSL_OP_PRIORITIZE_CHACHA /* OpenSSL 1.1.1 */ ++ rb_define_const(mSSL, "OP_PRIORITIZE_CHACHA", ULONG2NUM(SSL_OP_PRIORITIZE_CHACHA)); ++#endif ++#ifdef SSL_OP_NO_ANTI_REPLAY /* OpenSSL 1.1.1 */ ++ rb_define_const(mSSL, "OP_NO_ANTI_REPLAY", ULONG2NUM(SSL_OP_NO_ANTI_REPLAY)); + #endif +- rb_define_const(mSSL, "OP_CRYPTOPRO_TLSEXT_BUG", ULONG2NUM(SSL_OP_CRYPTOPRO_TLSEXT_BUG)); +- + rb_define_const(mSSL, "OP_NO_SSLv3", ULONG2NUM(SSL_OP_NO_SSLv3)); + rb_define_const(mSSL, "OP_NO_TLSv1", ULONG2NUM(SSL_OP_NO_TLSv1)); + rb_define_const(mSSL, "OP_NO_TLSv1_1", ULONG2NUM(SSL_OP_NO_TLSv1_1)); +@@ -2973,6 +2990,12 @@ Init_ossl_ssl(void) + #ifdef SSL_OP_NO_TLSv1_3 /* OpenSSL 1.1.1 */ + rb_define_const(mSSL, "OP_NO_TLSv1_3", ULONG2NUM(SSL_OP_NO_TLSv1_3)); + #endif ++ rb_define_const(mSSL, "OP_CIPHER_SERVER_PREFERENCE", ULONG2NUM(SSL_OP_CIPHER_SERVER_PREFERENCE)); ++ rb_define_const(mSSL, "OP_TLS_ROLLBACK_BUG", ULONG2NUM(SSL_OP_TLS_ROLLBACK_BUG)); ++#ifdef SSL_OP_NO_RENEGOTIATION /* OpenSSL 1.1.1 */ ++ rb_define_const(mSSL, "OP_NO_RENEGOTIATION", ULONG2NUM(SSL_OP_NO_RENEGOTIATION)); ++#endif ++ rb_define_const(mSSL, "OP_CRYPTOPRO_TLSEXT_BUG", ULONG2NUM(SSL_OP_CRYPTOPRO_TLSEXT_BUG)); + + /* SSL_OP_* flags for DTLS */ + #if 0 + +From e168df0f3570709bfb38e9a39838bd0a7e78164c Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 12 Dec 2021 00:47:35 +0900 +Subject: [PATCH 6/8] ssl: update test_options_disable_versions + +Use the combination of TLS 1.2 and TLS 1.3 instead of TLS 1.1 and TLS +1.2 so that will the test case will be run on latest platforms. +--- + test/openssl/test_ssl.rb | 75 +++++++++++++++++++++------------------- + 1 file changed, 40 insertions(+), 35 deletions(-) + +diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb +index 22691292..2abade06 100644 +--- a/test/openssl/test_ssl.rb ++++ b/test/openssl/test_ssl.rb +@@ -1180,46 +1180,51 @@ def test_minmax_version + end + + def test_options_disable_versions +- # Note: Use of these OP_* flags has been deprecated since OpenSSL 1.1.0. ++ # It's recommended to use SSLContext#{min,max}_version= instead in real ++ # applications. The purpose of this test case is to check that SSL options ++ # are properly propagated to OpenSSL library. + supported = check_supported_protocol_versions ++ if !defined?(OpenSSL::SSL::TLS1_3_VERSION) || ++ !supported.include?(OpenSSL::SSL::TLS1_2_VERSION) || ++ !supported.include?(OpenSSL::SSL::TLS1_3_VERSION) || ++ !defined?(OpenSSL::SSL::OP_NO_TLSv1_3) # LibreSSL < 3.4 ++ pend "this test case requires both TLS 1.2 and TLS 1.3 to be supported " \ ++ "and enabled by default" ++ end + +- if supported.include?(OpenSSL::SSL::TLS1_1_VERSION) && +- supported.include?(OpenSSL::SSL::TLS1_2_VERSION) +- # Server disables ~ TLS 1.1 +- ctx_proc = proc { |ctx| +- ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 | +- OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 +- } +- start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| +- # Client only supports TLS 1.1 +- ctx1 = OpenSSL::SSL::SSLContext.new +- ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_1_VERSION +- assert_handshake_error { server_connect(port, ctx1) { } } ++ # Server disables TLS 1.2 and earlier ++ ctx_proc = proc { |ctx| ++ ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 | ++ OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 | ++ OpenSSL::SSL::OP_NO_TLSv1_2 ++ } ++ start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| ++ # Client only supports TLS 1.2 ++ ctx1 = OpenSSL::SSL::SSLContext.new ++ ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_2_VERSION ++ assert_handshake_error { server_connect(port, ctx1) { } } + +- # Client only supports TLS 1.2 +- ctx2 = OpenSSL::SSL::SSLContext.new +- ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_2_VERSION +- assert_nothing_raised { server_connect(port, ctx2) { } } +- } ++ # Client only supports TLS 1.3 ++ ctx2 = OpenSSL::SSL::SSLContext.new ++ ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_3_VERSION ++ assert_nothing_raised { server_connect(port, ctx2) { } } ++ } + +- # Server only supports TLS 1.1 +- ctx_proc = proc { |ctx| +- ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION +- } +- start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| +- # Client disables TLS 1.1 +- ctx1 = OpenSSL::SSL::SSLContext.new +- ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_1 +- assert_handshake_error { server_connect(port, ctx1) { } } ++ # Server only supports TLS 1.2 ++ ctx_proc = proc { |ctx| ++ ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION ++ } ++ start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| ++ # Client doesn't support TLS 1.2 ++ ctx1 = OpenSSL::SSL::SSLContext.new ++ ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_2 ++ assert_handshake_error { server_connect(port, ctx1) { } } + +- # Client disables TLS 1.2 +- ctx2 = OpenSSL::SSL::SSLContext.new +- ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_2 +- assert_nothing_raised { server_connect(port, ctx2) { } } +- } +- else +- pend "TLS 1.1 and TLS 1.2 must be supported; skipping" +- end ++ # Client supports TLS 1.2 by default ++ ctx2 = OpenSSL::SSL::SSLContext.new ++ ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_3 ++ assert_nothing_raised { server_connect(port, ctx2) { } } ++ } + end + + def test_ssl_methods_constant + +From ccdb6f7bfa5f988a07beecedbf2b6205b6ab8492 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 20 Mar 2021 23:16:41 +0900 +Subject: [PATCH 7/8] pkey: assume a pkey always has public key components on + OpenSSL 3.0 + +OpenSSL 3.0's EVP_PKEY_get0() returns NULL for provider-backed pkeys. +This causes segfault because it was supposed to never return NULL +before. + +We can't check the existence of public key components in this way on +OpenSSL 3.0. Let's just skip it for now. +--- + ext/openssl/ossl_pkey.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 94760d32..09d45d85 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -428,9 +428,19 @@ ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self) + return pkey_generate(argc, argv, self, 0); + } + ++/* ++ * TODO: There is no convenient way to check the presence of public key ++ * components on OpenSSL 3.0. But since keys are immutable on 3.0, pkeys without ++ * these should only be created by OpenSSL::PKey.generate_parameters or by ++ * parsing DER-/PEM-encoded string. We would need another flag for that. ++ */ + void + ossl_pkey_check_public_key(const EVP_PKEY *pkey) + { ++#if OSSL_OPENSSL_PREREQ(3, 0, 0) ++ if (EVP_PKEY_missing_parameters(pkey)) ++ ossl_raise(ePKeyError, "parameters missing"); ++#else + void *ptr; + const BIGNUM *n, *e, *pubkey; + +@@ -466,6 +476,7 @@ ossl_pkey_check_public_key(const EVP_PKEY *pkey) + return; + } + ossl_raise(ePKeyError, "public key missing"); ++#endif + } + + EVP_PKEY * + +From d6535d13d174cd87ae99f3e60e97f7a00e1474e5 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 12 Apr 2021 10:43:46 +0900 +Subject: [PATCH 8/8] pkey: use EVP_PKEY_CTX_new_from_name() on OpenSSL 3.0 + +Replace EVP_PKEY_CTX_new_id() with the new EVP_PKEY_CTX_new_from_name() +which takes the algorithm name in a string instead of in an NID. +--- + ext/openssl/ossl_pkey.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 09d45d85..2a4835a2 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -315,6 +315,11 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + } + else { ++#if OSSL_OPENSSL_PREREQ(3, 0, 0) ++ ctx = EVP_PKEY_CTX_new_from_name(NULL, StringValueCStr(alg), NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_from_name"); ++#else + const EVP_PKEY_ASN1_METHOD *ameth; + ENGINE *tmpeng; + int pkey_id; +@@ -333,6 +338,7 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam) + ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id"); ++#endif + } + + if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) { diff --git a/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch b/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch new file mode 100644 index 0000000..a780108 --- /dev/null +++ b/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch @@ -0,0 +1,304 @@ +From 8f948ed68a4ed6c05ff66d822711e3b70ae4bb3f Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 27 Sep 2021 13:32:03 +0900 +Subject: [PATCH 1/5] ext/openssl/ossl.h: add helper macros for + OpenSSL/LibreSSL versions + +Add following convenient macros: + + - OSSL_IS_LIBRESSL + - OSSL_OPENSSL_PREREQ(maj, min, pat) + - OSSL_LIBRESSL_PREREQ(maj, min, pat) +--- + ext/openssl/ossl.h | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h +index c20f506bda..a0cef29d74 100644 +--- a/ext/openssl/ossl.h ++++ b/ext/openssl/ossl.h +@@ -42,6 +42,18 @@ + #include + #include + ++#ifndef LIBRESSL_VERSION_NUMBER ++# define OSSL_IS_LIBRESSL 0 ++# define OSSL_OPENSSL_PREREQ(maj, min, pat) \ ++ (OPENSSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12)) ++# define OSSL_LIBRESSL_PREREQ(maj, min, pat) 0 ++#else ++# define OSSL_IS_LIBRESSL 1 ++# define OSSL_OPENSSL_PREREQ(maj, min, pat) 0 ++# define OSSL_LIBRESSL_PREREQ(maj, min, pat) \ ++ (LIBRESSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12)) ++#endif ++ + /* + * Common Module + */ +-- +2.32.0 + + +From bbf235091e49807ece8f3a3df95bbfcc9d3ab43d Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 22 Feb 2020 05:37:01 +0900 +Subject: [PATCH 2/5] ts: use TS_VERIFY_CTX_set_certs instead of + TS_VERIFY_CTS_set_certs + +OpenSSL 3.0 fixed the typo in the function name and replaced the +current 'CTS' version with a macro. +--- + ext/openssl/extconf.rb | 5 ++++- + ext/openssl/openssl_missing.h | 5 +++++ + ext/openssl/ossl_ts.c | 2 +- + 3 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index 17d93443fc..09cae05b72 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -165,7 +165,7 @@ def find_openssl_library + have_func("TS_STATUS_INFO_get0_status") + have_func("TS_STATUS_INFO_get0_text") + have_func("TS_STATUS_INFO_get0_failure_info") +-have_func("TS_VERIFY_CTS_set_certs") ++have_func("TS_VERIFY_CTS_set_certs(NULL, NULL)", "openssl/ts.h") + have_func("TS_VERIFY_CTX_set_store") + have_func("TS_VERIFY_CTX_add_flags") + have_func("TS_RESP_CTX_set_time_cb") +@@ -174,6 +174,9 @@ def find_openssl_library + + # added in 1.1.1 + have_func("EVP_PKEY_check") ++ ++# added in 3.0.0 ++have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", "openssl/ts.h") + + Logging::message "=== Checking done. ===\n" + +diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h +index e575415f49..fe486bcfcf 100644 +--- a/ext/openssl/openssl_missing.h ++++ b/ext/openssl/openssl_missing.h +@@ -236,4 +236,9 @@ IMPL_PKEY_GETTER(EC_KEY, ec) + } while (0) + #endif + ++/* added in 3.0.0 */ ++#if !defined(HAVE_TS_VERIFY_CTX_SET_CERTS) ++# define TS_VERIFY_CTX_set_certs(ctx, crts) TS_VERIFY_CTS_set_certs(ctx, crts) ++#endif ++ + #endif /* _OSSL_OPENSSL_MISSING_H_ */ +diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c +index 692c0d620f..f1da7c1947 100644 +--- a/ext/openssl/ossl_ts.c ++++ b/ext/openssl/ossl_ts.c +@@ -820,7 +820,7 @@ ossl_ts_resp_verify(int argc, VALUE *argv, VALUE self) + X509_up_ref(cert); + } + +- TS_VERIFY_CTS_set_certs(ctx, x509inter); ++ TS_VERIFY_CTX_set_certs(ctx, x509inter); + TS_VERIFY_CTX_add_flags(ctx, TS_VFY_SIGNATURE); + TS_VERIFY_CTX_set_store(ctx, x509st); + +-- +2.32.0 + + +From 5fba3bc1df93ab6abc3ea53be3393480f36ea259 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 19 Mar 2021 19:18:25 +0900 +Subject: [PATCH 3/5] ssl: use SSL_get_rbio() to check if SSL is started or not + +Use SSL_get_rbio() instead of SSL_get_fd(). SSL_get_fd() internally +calls SSL_get_rbio() and it's enough for our purpose. + +In OpenSSL 3.0, SSL_get_fd() leaves an entry in the OpenSSL error queue +if BIO has not been set up yet, and we would have to clean it up. +--- + ext/openssl/ossl_ssl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c +index 4b7efa39f5..ec430bfb0c 100644 +--- a/ext/openssl/ossl_ssl.c ++++ b/ext/openssl/ossl_ssl.c +@@ -1535,8 +1535,8 @@ ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) + static inline int + ssl_started(SSL *ssl) + { +- /* the FD is set in ossl_ssl_setup(), called by #connect or #accept */ +- return SSL_get_fd(ssl) >= 0; ++ /* BIO is created through ossl_ssl_setup(), called by #connect or #accept */ ++ return SSL_get_rbio(ssl) != NULL; + } + + static void +-- +2.32.0 + +From 0a253027e6be47c0b7fd8b664f1048f24d7ca657 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Thu, 22 Apr 2021 13:57:47 +0900 +Subject: [PATCH 4/5] digest: use EVP_MD_CTX_get0_md() instead of + EVP_MD_CTX_md() if exists + +The function was renamed in OpenSSL 3.0 due to the change of the +lifetime of EVP_MD objects. They are no longer necessarily statically +allocated and can be reference-counted -- when an EVP_MD_CTX is free'd, +the associated EVP_MD can also become inaccessible. + +Currently Ruby/OpenSSL only handles builtin algorithms, so no special +handling is needed except for adapting to the rename. +--- + ext/openssl/extconf.rb | 1 + + ext/openssl/openssl_missing.h | 4 ++++ + ext/openssl/ossl_digest.c | 6 +++--- + ext/openssl/ossl_hmac.c | 2 +- + 4 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index 98f96afe..842b7f5b 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -177,6 +177,7 @@ def find_openssl_library + + # added in 3.0.0 + have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", "openssl/ts.h") ++have_func("EVP_MD_CTX_get0_md") + + Logging::message "=== Checking done. ===\n" + +diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h +index 1b1a54a8..64212349 100644 +--- a/ext/openssl/openssl_missing.h ++++ b/ext/openssl/openssl_missing.h +@@ -241,4 +241,8 @@ IMPL_PKEY_GETTER(EC_KEY, ec) + # define TS_VERIFY_CTX_set_certs(ctx, crts) TS_VERIFY_CTS_set_certs(ctx, crts) + #endif + ++#ifndef HAVE_EVP_MD_CTX_GET0_MD ++# define EVP_MD_CTX_get0_md(ctx) EVP_MD_CTX_md(ctx) ++#endif ++ + #endif /* _OSSL_OPENSSL_MISSING_H_ */ +diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c +index b2506de7..fc326ec1 100644 +--- a/ext/openssl/ossl_digest.c ++++ b/ext/openssl/ossl_digest.c +@@ -63,7 +63,7 @@ ossl_evp_get_digestbyname(VALUE obj) + + GetDigest(obj, ctx); + +- md = EVP_MD_CTX_md(ctx); ++ md = EVP_MD_CTX_get0_md(ctx); + } + + return md; +@@ -176,7 +176,7 @@ ossl_digest_reset(VALUE self) + EVP_MD_CTX *ctx; + + GetDigest(self, ctx); +- if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_md(ctx), NULL) != 1) { ++ if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_get0_md(ctx), NULL) != 1) { + ossl_raise(eDigestError, "Digest initialization failed."); + } + +@@ -259,7 +259,7 @@ ossl_digest_name(VALUE self) + + GetDigest(self, ctx); + +- return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx))); ++ return rb_str_new_cstr(EVP_MD_name(EVP_MD_CTX_get0_md(ctx))); + } + + /* +diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c +index a21db6c4..2642728b 100644 +--- a/ext/openssl/ossl_hmac.c ++++ b/ext/openssl/ossl_hmac.c +@@ -239,7 +239,7 @@ ossl_hmac_reset(VALUE self) + + GetHMAC(self, ctx); + pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_pkey_ctx(ctx)); +- if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_md(ctx), NULL, pkey) != 1) ++ if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_get0_md(ctx), NULL, pkey) != 1) + ossl_raise(eHMACError, "EVP_DigestSignInit"); + + return self; + +From c106d888c62e44a11cdbba5e4d2d0cb837ec3e52 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 22 Jun 2021 18:50:17 +0900 +Subject: [PATCH 5/5] hmac: use EVP_MD_CTX_get_pkey_ctx() instead of + EVP_MD_CTX_pkey_ctx() + +OpenSSL 3.0 renamed EVP_MD_CTX_pkey_ctx() to include "get" in the +function name. Adjust compatibility macro so that we can use the new +function name for all OpenSSL 1.0.2-3.0. +--- + ext/openssl/extconf.rb | 1 + + ext/openssl/openssl_missing.h | 16 ++++++++++++---- + ext/openssl/ossl_hmac.c | 2 +- + 3 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index 842b7f5b..d9d34b7c 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -178,6 +178,7 @@ def find_openssl_library + # added in 3.0.0 + have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", "openssl/ts.h") + have_func("EVP_MD_CTX_get0_md") ++have_func("EVP_MD_CTX_get_pkey_ctx") + + Logging::message "=== Checking done. ===\n" + +diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h +index 64212349..55c4f378 100644 +--- a/ext/openssl/openssl_missing.h ++++ b/ext/openssl/openssl_missing.h +@@ -42,10 +42,6 @@ int ossl_EC_curve_nist2nid(const char *); + # define EVP_MD_CTX_free EVP_MD_CTX_destroy + #endif + +-#if !defined(HAVE_EVP_MD_CTX_PKEY_CTX) +-# define EVP_MD_CTX_pkey_ctx(x) (x)->pctx +-#endif +- + #if !defined(HAVE_X509_STORE_GET_EX_DATA) + # define X509_STORE_get_ex_data(x, idx) \ + CRYPTO_get_ex_data(&(x)->ex_data, (idx)) +@@ -245,4 +241,16 @@ IMPL_PKEY_GETTER(EC_KEY, ec) + # define EVP_MD_CTX_get0_md(ctx) EVP_MD_CTX_md(ctx) + #endif + ++/* ++ * OpenSSL 1.1.0 added EVP_MD_CTX_pkey_ctx(), and then it was renamed to ++ * EVP_MD_CTX_get_pkey_ctx(x) in OpenSSL 3.0. ++ */ ++#ifndef HAVE_EVP_MD_CTX_GET_PKEY_CTX ++# ifdef HAVE_EVP_MD_CTX_PKEY_CTX ++# define EVP_MD_CTX_get_pkey_ctx(x) EVP_MD_CTX_pkey_ctx(x) ++# else ++# define EVP_MD_CTX_get_pkey_ctx(x) (x)->pctx ++# endif ++#endif ++ + #endif /* _OSSL_OPENSSL_MISSING_H_ */ +diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c +index 2642728b..f89ff2f9 100644 +--- a/ext/openssl/ossl_hmac.c ++++ b/ext/openssl/ossl_hmac.c +@@ -238,7 +238,7 @@ ossl_hmac_reset(VALUE self) + EVP_PKEY *pkey; + + GetHMAC(self, ctx); +- pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_pkey_ctx(ctx)); ++ pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_get_pkey_ctx(ctx)); + if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_get0_md(ctx), NULL, pkey) != 1) + ossl_raise(eHMACError, "EVP_DigestSignInit"); + diff --git a/ruby-3.1.0-Properly-exclude-test-cases.patch b/ruby-3.1.0-Properly-exclude-test-cases.patch new file mode 100644 index 0000000..ca2cd9b --- /dev/null +++ b/ruby-3.1.0-Properly-exclude-test-cases.patch @@ -0,0 +1,93 @@ +From 96684439e96aa92e10376b5be45f006772028295 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Thu, 21 Oct 2021 13:02:38 +0200 +Subject: [PATCH] Properly exclude test cases. + +Lets consider the following scenario: + +~~~ +irb(#):001:0> p suite +OpenSSL::TestEC +=> OpenSSL::TestEC + +irb(#):002:0> p all_test_methods +["test_ECPrivateKey", "test_ECPrivateKey_encrypted", "test_PUBKEY", "test_check_key", "test_derive_key", "test_dh_compute_key", "test_dsa_sign_asn1_FIPS186_3", "test_ec_group", "test_ec_key", "test_ec_point", "test_ec_point_add", "test_ec_point_mul", "test_generate", "test_marshal", "test_sign_verify", "test_sign_verify_raw"] +=> +["test_ECPrivateKey", + "test_ECPrivateKey_encrypted", + "test_PUBKEY", + "test_check_key", + "test_derive_key", + "test_dh_compute_key", + "test_dsa_sign_asn1_FIPS186_3", + "test_ec_group", + "test_ec_key", + "test_ec_point", + "test_ec_point_add", + "test_ec_point_mul", + "test_generate", + "test_marshal", + "test_sign_verify", + "test_sign_verify_raw"] + +irb(#):003:0> p filter +/\A(?=.*)(?!.*(?-mix:(?-mix:memory_leak)|(?-mix:OpenSSL::TestEC.test_check_key)))/ +=> /\A(?=.*)(?!.*(?-mix:(?-mix:memory_leak)|(?-mix:OpenSSL::TestEC.test_check_key)))/ + +irb(#):004:0> method = "test_check_key" +=> "test_check_key" +~~~ + +The intention here is to exclude the `test_check_key` test case. +Unfortunately this does not work as expected, because the negative filter +is never checked: + +~~~ + +irb(#):005:0> filter === method +=> true + +irb(#):006:0> filter === "#{suite}##{method}" +=> false + +irb(#):007:0> filter === method || filter === "#{suite}##{method}" +=> true +~~~ + +Therefore always filter against the fully qualified method name +`#{suite}##{method}`, which should provide the expected result. + +However, if plain string filter is used, keep checking also only the +method name. + +This resolves [Bug #16936]. +--- + tool/lib/minitest/unit.rb | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/tool/lib/minitest/unit.rb b/tool/lib/minitest/unit.rb +index c58a609bfa..d5af6cb906 100644 +--- a/tool/lib/minitest/unit.rb ++++ b/tool/lib/minitest/unit.rb +@@ -956,9 +956,15 @@ def _run_suite suite, type + + all_test_methods = suite.send "#{type}_methods" + +- filtered_test_methods = all_test_methods.find_all { |m| +- filter === m || filter === "#{suite}##{m}" +- } ++ filtered_test_methods = if Regexp === filter ++ all_test_methods.find_all { |m| ++ filter === "#{suite}##{m}" ++ } ++ else ++ all_test_methods.find_all {|m| ++ filter === m || filter === "#{suite}##{m}" ++ } ++ end + + leakchecker = LeakChecker.new + +-- +2.32.0 + diff --git a/ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch b/ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch new file mode 100644 index 0000000..d1de216 --- /dev/null +++ b/ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch @@ -0,0 +1,1450 @@ +From 8b8e1d7f9b6b5a335864bbd0716df2af1ec41d91 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Thu, 16 Mar 2017 16:06:53 +0900 +Subject: [PATCH 1/5] pkey: simplify ossl_pkey_new() + +ossl_{rsa,dsa,dh,ec}_new() called from this function are not used +anywhere else. Inline them into pkey_new0() and reduce code +duplication. +--- + ext/openssl/ossl_pkey.c | 22 +++++++++------------- + ext/openssl/ossl_pkey.h | 3 --- + ext/openssl/ossl_pkey_dh.c | 21 --------------------- + ext/openssl/ossl_pkey_dsa.c | 21 --------------------- + ext/openssl/ossl_pkey_ec.c | 20 -------------------- + ext/openssl/ossl_pkey_rsa.c | 22 ---------------------- + 6 files changed, 9 insertions(+), 100 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 23204087ac..c6dbf57272 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -95,7 +95,7 @@ const rb_data_type_t ossl_evp_pkey_type = { + static VALUE + pkey_new0(EVP_PKEY *pkey) + { +- VALUE obj; ++ VALUE klass, obj; + int type; + + if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE) +@@ -103,26 +103,22 @@ pkey_new0(EVP_PKEY *pkey) + + switch (type) { + #if !defined(OPENSSL_NO_RSA) +- case EVP_PKEY_RSA: +- return ossl_rsa_new(pkey); ++ case EVP_PKEY_RSA: klass = cRSA; break; + #endif + #if !defined(OPENSSL_NO_DSA) +- case EVP_PKEY_DSA: +- return ossl_dsa_new(pkey); ++ case EVP_PKEY_DSA: klass = cDSA; break; + #endif + #if !defined(OPENSSL_NO_DH) +- case EVP_PKEY_DH: +- return ossl_dh_new(pkey); ++ case EVP_PKEY_DH: klass = cDH; break; + #endif + #if !defined(OPENSSL_NO_EC) +- case EVP_PKEY_EC: +- return ossl_ec_new(pkey); ++ case EVP_PKEY_EC: klass = cEC; break; + #endif +- default: +- obj = NewPKey(cPKey); +- SetPKey(obj, pkey); +- return obj; ++ default: klass = cPKey; break; + } ++ obj = NewPKey(klass); ++ SetPKey(obj, pkey); ++ return obj; + } + + VALUE +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index 0db59305f7..e363a261c2 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -56,7 +56,6 @@ void Init_ossl_pkey(void); + extern VALUE cRSA; + extern VALUE eRSAError; + +-VALUE ossl_rsa_new(EVP_PKEY *); + void Init_ossl_rsa(void); + + /* +@@ -65,7 +64,6 @@ void Init_ossl_rsa(void); + extern VALUE cDSA; + extern VALUE eDSAError; + +-VALUE ossl_dsa_new(EVP_PKEY *); + void Init_ossl_dsa(void); + + /* +@@ -74,7 +72,6 @@ void Init_ossl_dsa(void); + extern VALUE cDH; + extern VALUE eDHError; + +-VALUE ossl_dh_new(EVP_PKEY *); + void Init_ossl_dh(void); + + /* +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index bf4e3f9322..dff69cfc33 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -54,27 +54,6 @@ dh_instance(VALUE klass, DH *dh) + return obj; + } + +-VALUE +-ossl_dh_new(EVP_PKEY *pkey) +-{ +- VALUE obj; +- +- if (!pkey) { +- obj = dh_instance(cDH, DH_new()); +- } else { +- obj = NewPKey(cDH); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { +- ossl_raise(rb_eTypeError, "Not a DH key!"); +- } +- SetPKey(obj, pkey); +- } +- if (obj == Qfalse) { +- ossl_raise(eDHError, NULL); +- } +- +- return obj; +-} +- + /* + * Private + */ +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index 431c20e05c..e9be9ac482 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -68,27 +68,6 @@ dsa_instance(VALUE klass, DSA *dsa) + return obj; + } + +-VALUE +-ossl_dsa_new(EVP_PKEY *pkey) +-{ +- VALUE obj; +- +- if (!pkey) { +- obj = dsa_instance(cDSA, DSA_new()); +- } else { +- obj = NewPKey(cDSA); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { +- ossl_raise(rb_eTypeError, "Not a DSA key!"); +- } +- SetPKey(obj, pkey); +- } +- if (obj == Qfalse) { +- ossl_raise(eDSAError, NULL); +- } +- +- return obj; +-} +- + /* + * Private + */ +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index fc2bc6c815..eabf495f19 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -84,26 +84,6 @@ static VALUE ec_instance(VALUE klass, EC_KEY *ec) + return obj; + } + +-VALUE ossl_ec_new(EVP_PKEY *pkey) +-{ +- VALUE obj; +- +- if (!pkey) { +- obj = ec_instance(cEC, EC_KEY_new()); +- } else { +- obj = NewPKey(cEC); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { +- ossl_raise(rb_eTypeError, "Not a EC key!"); +- } +- SetPKey(obj, pkey); +- } +- if (obj == Qfalse) { +- ossl_raise(eECError, NULL); +- } +- +- return obj; +-} +- + /* + * Creates a new EC_KEY on the EC group obj. arg can be an EC::Group or a String + * representing an OID. +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 761866c66a..c1ae44fe40 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -69,28 +69,6 @@ rsa_instance(VALUE klass, RSA *rsa) + return obj; + } + +-VALUE +-ossl_rsa_new(EVP_PKEY *pkey) +-{ +- VALUE obj; +- +- if (!pkey) { +- obj = rsa_instance(cRSA, RSA_new()); +- } +- else { +- obj = NewPKey(cRSA); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { +- ossl_raise(rb_eTypeError, "Not a RSA key!"); +- } +- SetPKey(obj, pkey); +- } +- if (obj == Qfalse) { +- ossl_raise(eRSAError, NULL); +- } +- +- return obj; +-} +- + /* + * Private + */ +-- +2.32.0 + + +From 2b0d259ef7aae707922996d305675a68dad27abd Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Thu, 16 Mar 2017 16:09:35 +0900 +Subject: [PATCH 2/5] pkey: inline {rsa,dsa,dh,ec}_instance() + +Merge the code into the callers so that the wrapping Ruby object is +allocated before the raw key object is allocated. This prevents possible +memory leak on Ruby object allocation failure, and also reduces the +lines of code. +--- + ext/openssl/ossl_pkey_dh.c | 63 ++++++++++++---------------------- + ext/openssl/ossl_pkey_dsa.c | 68 ++++++++++++++----------------------- + ext/openssl/ossl_pkey_ec.c | 34 ++++--------------- + ext/openssl/ossl_pkey_rsa.c | 67 +++++++++++++----------------------- + 4 files changed, 76 insertions(+), 156 deletions(-) + +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index dff69cfc33..bc50e5566b 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -29,31 +29,6 @@ + VALUE cDH; + VALUE eDHError; + +-/* +- * Public +- */ +-static VALUE +-dh_instance(VALUE klass, DH *dh) +-{ +- EVP_PKEY *pkey; +- VALUE obj; +- +- if (!dh) { +- return Qfalse; +- } +- obj = NewPKey(klass); +- if (!(pkey = EVP_PKEY_new())) { +- return Qfalse; +- } +- if (!EVP_PKEY_assign_DH(pkey, dh)) { +- EVP_PKEY_free(pkey); +- return Qfalse; +- } +- SetPKey(obj, pkey); +- +- return obj; +-} +- + /* + * Private + */ +@@ -84,7 +59,7 @@ dh_generate(int size, int gen) + if (!dh || !cb) { + DH_free(dh); + BN_GENCB_free(cb); +- return NULL; ++ ossl_raise(eDHError, "malloc failure"); + } + + if (rb_block_given_p()) +@@ -110,12 +85,12 @@ dh_generate(int size, int gen) + ossl_clear_error(); + rb_jump_tag(cb_arg.state); + } +- return NULL; ++ ossl_raise(eDHError, "DH_generate_parameters_ex"); + } + + if (!DH_generate_key(dh)) { + DH_free(dh); +- return NULL; ++ ossl_raise(eDHError, "DH_generate_key"); + } + + return dh; +@@ -136,6 +111,7 @@ dh_generate(int size, int gen) + static VALUE + ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) + { ++ EVP_PKEY *pkey; + DH *dh ; + int g = 2; + VALUE size, gen, obj; +@@ -143,13 +119,14 @@ ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) + if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) { + g = NUM2INT(gen); + } ++ obj = rb_obj_alloc(klass); ++ GetPKey(obj, pkey); ++ + dh = dh_generate(NUM2INT(size), g); +- obj = dh_instance(klass, dh); +- if (obj == Qfalse) { +- DH_free(dh); +- ossl_raise(eDHError, NULL); ++ if (!EVP_PKEY_assign_DH(pkey, dh)) { ++ DH_free(dh); ++ ossl_raise(eDHError, "EVP_PKEY_assign_DH"); + } +- + return obj; + } + +@@ -195,9 +172,7 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) + if (!NIL_P(gen)) { + g = NUM2INT(gen); + } +- if (!(dh = dh_generate(NUM2INT(arg), g))) { +- ossl_raise(eDHError, NULL); +- } ++ dh = dh_generate(NUM2INT(arg), g); + } + else { + arg = ossl_to_der_if_possible(arg); +@@ -434,17 +409,21 @@ ossl_dh_to_text(VALUE self) + static VALUE + ossl_dh_to_public_key(VALUE self) + { ++ EVP_PKEY *pkey; + DH *orig_dh, *dh; + VALUE obj; + ++ obj = rb_obj_alloc(rb_obj_class(self)); ++ GetPKey(obj, pkey); ++ + GetDH(self, orig_dh); +- dh = DHparams_dup(orig_dh); /* err check perfomed by dh_instance */ +- obj = dh_instance(rb_obj_class(self), dh); +- if (obj == Qfalse) { +- DH_free(dh); +- ossl_raise(eDHError, NULL); ++ dh = DHparams_dup(orig_dh); ++ if (!dh) ++ ossl_raise(eDHError, "DHparams_dup"); ++ if (!EVP_PKEY_assign_DH(pkey, dh)) { ++ DH_free(dh); ++ ossl_raise(eDHError, "EVP_PKEY_assign_DH"); + } +- + return obj; + } + +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index e9be9ac482..c907f31c19 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -43,31 +43,6 @@ DSA_PRIVATE(VALUE obj, DSA *dsa) + VALUE cDSA; + VALUE eDSAError; + +-/* +- * Public +- */ +-static VALUE +-dsa_instance(VALUE klass, DSA *dsa) +-{ +- EVP_PKEY *pkey; +- VALUE obj; +- +- if (!dsa) { +- return Qfalse; +- } +- obj = NewPKey(klass); +- if (!(pkey = EVP_PKEY_new())) { +- return Qfalse; +- } +- if (!EVP_PKEY_assign_DSA(pkey, dsa)) { +- EVP_PKEY_free(pkey); +- return Qfalse; +- } +- SetPKey(obj, pkey); +- +- return obj; +-} +- + /* + * Private + */ +@@ -100,9 +75,9 @@ dsa_generate(int size) + unsigned long h; + + if (!dsa || !cb) { +- DSA_free(dsa); +- BN_GENCB_free(cb); +- return NULL; ++ DSA_free(dsa); ++ BN_GENCB_free(cb); ++ ossl_raise(eDSAError, "malloc failure"); + } + + if (rb_block_given_p()) +@@ -132,12 +107,12 @@ dsa_generate(int size) + ossl_clear_error(); + rb_jump_tag(cb_arg.state); + } +- return NULL; ++ ossl_raise(eDSAError, "DSA_generate_parameters_ex"); + } + + if (!DSA_generate_key(dsa)) { +- DSA_free(dsa); +- return NULL; ++ DSA_free(dsa); ++ ossl_raise(eDSAError, "DSA_generate_key"); + } + + return dsa; +@@ -157,14 +132,18 @@ dsa_generate(int size) + static VALUE + ossl_dsa_s_generate(VALUE klass, VALUE size) + { +- DSA *dsa = dsa_generate(NUM2INT(size)); /* err handled by dsa_instance */ +- VALUE obj = dsa_instance(klass, dsa); ++ EVP_PKEY *pkey; ++ DSA *dsa; ++ VALUE obj; + +- if (obj == Qfalse) { +- DSA_free(dsa); +- ossl_raise(eDSAError, NULL); +- } ++ obj = rb_obj_alloc(klass); ++ GetPKey(obj, pkey); + ++ dsa = dsa_generate(NUM2INT(size)); ++ if (!EVP_PKEY_assign_DSA(pkey, dsa)) { ++ DSA_free(dsa); ++ ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); ++ } + return obj; + } + +@@ -460,20 +439,23 @@ ossl_dsa_to_text(VALUE self) + static VALUE + ossl_dsa_to_public_key(VALUE self) + { +- EVP_PKEY *pkey; ++ EVP_PKEY *pkey, *pkey_new; + DSA *dsa; + VALUE obj; + + GetPKeyDSA(self, pkey); +- /* err check performed by dsa_instance */ ++ obj = rb_obj_alloc(rb_obj_class(self)); ++ GetPKey(obj, pkey_new); ++ + #define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \ + (i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa)) + dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey)); + #undef DSAPublicKey_dup +- obj = dsa_instance(rb_obj_class(self), dsa); +- if (obj == Qfalse) { +- DSA_free(dsa); +- ossl_raise(eDSAError, NULL); ++ if (!dsa) ++ ossl_raise(eDSAError, "DSAPublicKey_dup"); ++ if (!EVP_PKEY_assign_DSA(pkey_new, dsa)) { ++ DSA_free(dsa); ++ ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); + } + return obj; + } +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index eabf495f19..aec9d1e60f 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -63,27 +63,6 @@ static ID id_i_group; + static VALUE ec_group_new(const EC_GROUP *group); + static VALUE ec_point_new(const EC_POINT *point, const EC_GROUP *group); + +-static VALUE ec_instance(VALUE klass, EC_KEY *ec) +-{ +- EVP_PKEY *pkey; +- VALUE obj; +- +- if (!ec) { +- return Qfalse; +- } +- obj = NewPKey(klass); +- if (!(pkey = EVP_PKEY_new())) { +- return Qfalse; +- } +- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { +- EVP_PKEY_free(pkey); +- return Qfalse; +- } +- SetPKey(obj, pkey); +- +- return obj; +-} +- + /* + * Creates a new EC_KEY on the EC group obj. arg can be an EC::Group or a String + * representing an OID. +@@ -130,17 +109,18 @@ ec_key_new_from_group(VALUE arg) + static VALUE + ossl_ec_key_s_generate(VALUE klass, VALUE arg) + { ++ EVP_PKEY *pkey; + EC_KEY *ec; + VALUE obj; + +- ec = ec_key_new_from_group(arg); ++ obj = rb_obj_alloc(klass); ++ GetPKey(obj, pkey); + +- obj = ec_instance(klass, ec); +- if (obj == Qfalse) { +- EC_KEY_free(ec); +- ossl_raise(eECError, NULL); ++ ec = ec_key_new_from_group(arg); ++ if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { ++ EC_KEY_free(ec); ++ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); + } +- + if (!EC_KEY_generate_key(ec)) + ossl_raise(eECError, "EC_KEY_generate_key"); + +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index c1ae44fe40..fbdb9c8960 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -44,31 +44,6 @@ RSA_PRIVATE(VALUE obj, RSA *rsa) + VALUE cRSA; + VALUE eRSAError; + +-/* +- * Public +- */ +-static VALUE +-rsa_instance(VALUE klass, RSA *rsa) +-{ +- EVP_PKEY *pkey; +- VALUE obj; +- +- if (!rsa) { +- return Qfalse; +- } +- obj = NewPKey(klass); +- if (!(pkey = EVP_PKEY_new())) { +- return Qfalse; +- } +- if (!EVP_PKEY_assign_RSA(pkey, rsa)) { +- EVP_PKEY_free(pkey); +- return Qfalse; +- } +- SetPKey(obj, pkey); +- +- return obj; +-} +- + /* + * Private + */ +@@ -102,7 +77,7 @@ rsa_generate(int size, unsigned long exp) + RSA_free(rsa); + BN_free(e); + BN_GENCB_free(cb); +- return NULL; ++ ossl_raise(eRSAError, "malloc failure"); + } + for (i = 0; i < (int)sizeof(exp) * 8; ++i) { + if (exp & (1UL << i)) { +@@ -110,7 +85,7 @@ rsa_generate(int size, unsigned long exp) + BN_free(e); + RSA_free(rsa); + BN_GENCB_free(cb); +- return NULL; ++ ossl_raise(eRSAError, "BN_set_bit"); + } + } + } +@@ -139,7 +114,7 @@ rsa_generate(int size, unsigned long exp) + ossl_clear_error(); + rb_jump_tag(cb_arg.state); + } +- return NULL; ++ ossl_raise(eRSAError, "RSA_generate_key_ex"); + } + + return rsa; +@@ -158,26 +133,26 @@ static VALUE + ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) + { + /* why does this method exist? why can't initialize take an optional exponent? */ ++ EVP_PKEY *pkey; + RSA *rsa; + VALUE size, exp; + VALUE obj; + + rb_scan_args(argc, argv, "11", &size, &exp); ++ obj = rb_obj_alloc(klass); ++ GetPKey(obj, pkey); + +- rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp)); /* err handled by rsa_instance */ +- obj = rsa_instance(klass, rsa); +- +- if (obj == Qfalse) { +- RSA_free(rsa); +- ossl_raise(eRSAError, NULL); ++ rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp)); ++ if (!EVP_PKEY_assign_RSA(pkey, rsa)) { ++ RSA_free(rsa); ++ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); + } +- + return obj; + } + + /* + * call-seq: +- * RSA.new(key_size) => RSA instance ++ * RSA.new(size [, exponent]) => RSA instance + * RSA.new(encoded_key) => RSA instance + * RSA.new(encoded_key, pass_phrase) => RSA instance + * +@@ -206,10 +181,11 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + GetPKey(self, pkey); + if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { + rsa = RSA_new(); ++ if (!rsa) ++ ossl_raise(eRSAError, "RSA_new"); + } + else if (RB_INTEGER_TYPE_P(arg)) { + rsa = rsa_generate(NUM2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2ULONG(pass)); +- if (!rsa) ossl_raise(eRSAError, NULL); + } + else { + pass = ossl_pem_passwd_value(pass); +@@ -243,7 +219,7 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + } + if (!EVP_PKEY_assign_RSA(pkey, rsa)) { + RSA_free(rsa); +- ossl_raise(eRSAError, NULL); ++ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); + } + + return self; +@@ -787,17 +763,20 @@ ossl_rsa_to_text(VALUE self) + static VALUE + ossl_rsa_to_public_key(VALUE self) + { +- EVP_PKEY *pkey; ++ EVP_PKEY *pkey, *pkey_new; + RSA *rsa; + VALUE obj; + + GetPKeyRSA(self, pkey); +- /* err check performed by rsa_instance */ ++ obj = rb_obj_alloc(rb_obj_class(self)); ++ GetPKey(obj, pkey_new); ++ + rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey)); +- obj = rsa_instance(rb_obj_class(self), rsa); +- if (obj == Qfalse) { +- RSA_free(rsa); +- ossl_raise(eRSAError, NULL); ++ if (!rsa) ++ ossl_raise(eRSAError, "RSAPublicKey_dup"); ++ if (!EVP_PKEY_assign_RSA(pkey_new, rsa)) { ++ RSA_free(rsa); ++ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); + } + return obj; + } +-- +2.32.0 + + +From 1e1fedc6c2c9d42bc76b5a24bf0f39c8101f8d53 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 18 Mar 2017 17:26:33 +0900 +Subject: [PATCH 3/5] pkey: have PKey.read parse PEM-encoded DHParameter + +Try PEM_read_bio_Parameters(). Only PEM format is supported at the +moment since corresponding d2i_* functions are not provided by OpenSSL. +--- + ext/openssl/ossl_pkey.c | 3 +++ + test/openssl/test_pkey_dh.rb | 2 ++ + test/openssl/utils.rb | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index c6dbf57272..a00d66aada 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -178,6 +178,9 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) + OSSL_BIO_reset(bio); + if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL))) + goto ok; ++ OSSL_BIO_reset(bio); ++ if ((pkey = PEM_read_bio_Parameters(bio, NULL))) ++ goto ok; + + BIO_free(bio); + ossl_raise(ePKeyError, "Could not parse PKey"); +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index fd2c7a66a9..4a05626a12 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -36,6 +36,8 @@ def test_DHparams + EOF + key = OpenSSL::PKey::DH.new(pem) + assert_same_dh dup_public(dh1024), key ++ key = OpenSSL::PKey.read(pem) ++ assert_same_dh dup_public(dh1024), key + + assert_equal asn1.to_der, dh1024.to_der + assert_equal pem, dh1024.export +diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb +index 3776fbac4e..c1d737b2ab 100644 +--- a/test/openssl/utils.rb ++++ b/test/openssl/utils.rb +@@ -42,9 +42,6 @@ module Fixtures + + def pkey(name) + OpenSSL::PKey.read(read_file("pkey", name)) +- rescue OpenSSL::PKey::PKeyError +- # TODO: DH parameters can be read by OpenSSL::PKey.read atm +- OpenSSL::PKey::DH.new(read_file("pkey", name)) + end + + def read_file(category, name) +-- +2.32.0 + + +From 70655b40a980dad36dfb3054d309f6484e2a70b7 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 13 Jun 2017 23:39:41 +0900 +Subject: [PATCH 4/5] pkey: refactor DER/PEM-encoded string parsing code + +Export the flow used by OpenSSL::PKey.read and let the subclasses call +it before attempting other formats. +--- + ext/openssl/ossl_pkey.c | 57 +++++++++++++++++++++---------------- + ext/openssl/ossl_pkey.h | 1 + + ext/openssl/ossl_pkey_dsa.c | 37 +++++++++++------------- + ext/openssl/ossl_pkey_ec.c | 29 +++++++------------ + ext/openssl/ossl_pkey_rsa.c | 26 ++++++++--------- + 5 files changed, 73 insertions(+), 77 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index a00d66aada..47ddd0f014 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -136,6 +136,35 @@ ossl_pkey_new(EVP_PKEY *pkey) + return obj; + } + ++EVP_PKEY * ++ossl_pkey_read_generic(BIO *bio, VALUE pass) ++{ ++ void *ppass = (void *)pass; ++ EVP_PKEY *pkey; ++ ++ if ((pkey = d2i_PrivateKey_bio(bio, NULL))) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass))) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if ((pkey = d2i_PUBKEY_bio(bio, NULL))) ++ goto out; ++ OSSL_BIO_reset(bio); ++ /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */ ++ if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass))) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL))) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if ((pkey = PEM_read_bio_Parameters(bio, NULL))) ++ goto out; ++ ++ out: ++ return pkey; ++} ++ + /* + * call-seq: + * OpenSSL::PKey.read(string [, pwd ]) -> PKey +@@ -160,33 +189,11 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) + VALUE data, pass; + + rb_scan_args(argc, argv, "11", &data, &pass); +- pass = ossl_pem_passwd_value(pass); +- + bio = ossl_obj2bio(&data); +- if ((pkey = d2i_PrivateKey_bio(bio, NULL))) +- goto ok; +- OSSL_BIO_reset(bio); +- if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, (void *)pass))) +- goto ok; +- OSSL_BIO_reset(bio); +- if ((pkey = d2i_PUBKEY_bio(bio, NULL))) +- goto ok; +- OSSL_BIO_reset(bio); +- /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */ +- if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass))) +- goto ok; +- OSSL_BIO_reset(bio); +- if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL))) +- goto ok; +- OSSL_BIO_reset(bio); +- if ((pkey = PEM_read_bio_Parameters(bio, NULL))) +- goto ok; +- +- BIO_free(bio); +- ossl_raise(ePKeyError, "Could not parse PKey"); +- +-ok: ++ pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass)); + BIO_free(bio); ++ if (!pkey) ++ ossl_raise(ePKeyError, "Could not parse PKey"); + return ossl_pkey_new(pkey); + } + +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index e363a261c2..895927e3fb 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -45,6 +45,7 @@ void ossl_generate_cb_stop(void *ptr); + + VALUE ossl_pkey_new(EVP_PKEY *); + void ossl_pkey_check_public_key(const EVP_PKEY *); ++EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE); + EVP_PKEY *GetPKeyPtr(VALUE); + EVP_PKEY *DupPKeyPtr(VALUE); + EVP_PKEY *GetPrivPKeyPtr(VALUE); +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index c907f31c19..56f58559ed 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -170,37 +170,34 @@ ossl_dsa_s_generate(VALUE klass, VALUE size) + static VALUE + ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) + { +- EVP_PKEY *pkey; +- DSA *dsa; ++ EVP_PKEY *pkey, *tmp; ++ DSA *dsa = NULL; + BIO *in; + VALUE arg, pass; + + GetPKey(self, pkey); +- if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { ++ rb_scan_args(argc, argv, "02", &arg, &pass); ++ if (argc == 0) { + dsa = DSA_new(); ++ if (!dsa) ++ ossl_raise(eDSAError, "DSA_new"); + } +- else if (RB_INTEGER_TYPE_P(arg)) { +- if (!(dsa = dsa_generate(NUM2INT(arg)))) { +- ossl_raise(eDSAError, NULL); +- } ++ else if (argc == 1 && RB_INTEGER_TYPE_P(arg)) { ++ dsa = dsa_generate(NUM2INT(arg)); + } + else { + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); + in = ossl_obj2bio(&arg); +- dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); +- if (!dsa) { +- OSSL_BIO_reset(in); +- dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL); +- } +- if (!dsa) { +- OSSL_BIO_reset(in); +- dsa = d2i_DSAPrivateKey_bio(in, NULL); +- } +- if (!dsa) { +- OSSL_BIO_reset(in); +- dsa = d2i_DSA_PUBKEY_bio(in, NULL); +- } ++ ++ tmp = ossl_pkey_read_generic(in, pass); ++ if (tmp) { ++ if (EVP_PKEY_base_id(tmp) != EVP_PKEY_DSA) ++ rb_raise(eDSAError, "incorrect pkey type: %s", ++ OBJ_nid2sn(EVP_PKEY_base_id(tmp))); ++ dsa = EVP_PKEY_get1_DSA(tmp); ++ EVP_PKEY_free(tmp); ++ } + if (!dsa) { + OSSL_BIO_reset(in); + #define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \ +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index aec9d1e60f..ca8f5c6e4e 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -162,24 +162,17 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) + } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { + ec = ec_key_new_from_group(arg); + } else { +- BIO *in; +- +- pass = ossl_pem_passwd_value(pass); +- in = ossl_obj2bio(&arg); +- +- ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); +- if (!ec) { +- OSSL_BIO_reset(in); +- ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, (void *)pass); +- } +- if (!ec) { +- OSSL_BIO_reset(in); +- ec = d2i_ECPrivateKey_bio(in, NULL); +- } +- if (!ec) { +- OSSL_BIO_reset(in); +- ec = d2i_EC_PUBKEY_bio(in, NULL); +- } ++ BIO *in = ossl_obj2bio(&arg); ++ EVP_PKEY *tmp; ++ pass = ossl_pem_passwd_value(pass); ++ tmp = ossl_pkey_read_generic(in, pass); ++ if (tmp) { ++ if (EVP_PKEY_base_id(tmp) != EVP_PKEY_EC) ++ rb_raise(eECError, "incorrect pkey type: %s", ++ OBJ_nid2sn(EVP_PKEY_base_id(tmp))); ++ ec = EVP_PKEY_get1_EC_KEY(tmp); ++ EVP_PKEY_free(tmp); ++ } + BIO_free(in); + + if (!ec) { +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index fbdb9c8960..8415121c7d 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -179,7 +179,8 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + VALUE arg, pass; + + GetPKey(self, pkey); +- if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { ++ rb_scan_args(argc, argv, "02", &arg, &pass); ++ if (argc == 0) { + rsa = RSA_new(); + if (!rsa) + ossl_raise(eRSAError, "RSA_new"); +@@ -191,19 +192,15 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); + in = ossl_obj2bio(&arg); +- rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); +- if (!rsa) { +- OSSL_BIO_reset(in); +- rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL); +- } +- if (!rsa) { +- OSSL_BIO_reset(in); +- rsa = d2i_RSAPrivateKey_bio(in, NULL); +- } +- if (!rsa) { +- OSSL_BIO_reset(in); +- rsa = d2i_RSA_PUBKEY_bio(in, NULL); +- } ++ ++ tmp = ossl_pkey_read_generic(in, pass); ++ if (tmp) { ++ if (EVP_PKEY_base_id(tmp) != EVP_PKEY_RSA) ++ rb_raise(eRSAError, "incorrect pkey type: %s", ++ OBJ_nid2sn(EVP_PKEY_base_id(tmp))); ++ rsa = EVP_PKEY_get1_RSA(tmp); ++ EVP_PKEY_free(tmp); ++ } + if (!rsa) { + OSSL_BIO_reset(in); + rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); +@@ -214,6 +211,7 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + } + BIO_free(in); + if (!rsa) { ++ ossl_clear_error(); + ossl_raise(eRSAError, "Neither PUB key nor PRIV key"); + } + } +-- +2.32.0 + + +From eacc680b1efc82935efc945bbe23c9073f17f440 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Wed, 14 Jun 2017 00:25:43 +0900 +Subject: [PATCH 5/5] pkey: refactor #export/#to_pem and #to_der + +Add ossl_pkey_export_traditional() and ossl_pkey_export_spki() helper +functions, and use them. This reduces code duplication. +--- + ext/openssl/ossl_pkey.c | 54 +++++++++++++++++++++-- + ext/openssl/ossl_pkey.h | 14 ++++++ + ext/openssl/ossl_pkey_dsa.c | 49 +++------------------ + ext/openssl/ossl_pkey_ec.c | 86 ++++++++----------------------------- + ext/openssl/ossl_pkey_rsa.c | 84 +++++++++++------------------------- + 5 files changed, 114 insertions(+), 173 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 47ddd0f014..610a83fd2d 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -341,6 +341,52 @@ ossl_pkey_inspect(VALUE self) + OBJ_nid2sn(nid)); + } + ++VALUE ++ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der) ++{ ++ EVP_PKEY *pkey; ++ VALUE cipher, pass; ++ const EVP_CIPHER *enc = NULL; ++ BIO *bio; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "02", &cipher, &pass); ++ if (!NIL_P(cipher)) { ++ enc = ossl_evp_get_cipherbyname(cipher); ++ pass = ossl_pem_passwd_value(pass); ++ } ++ ++ bio = BIO_new(BIO_s_mem()); ++ if (!bio) ++ ossl_raise(ePKeyError, "BIO_new"); ++ if (to_der) { ++ if (!i2d_PrivateKey_bio(bio, pkey)) { ++ BIO_free(bio); ++ ossl_raise(ePKeyError, "i2d_PrivateKey_bio"); ++ } ++ } ++ else { ++#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER) ++ if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0, ++ ossl_pem_passwd_cb, ++ (void *)pass)) { ++#else ++ char pem_str[80]; ++ const char *aname; ++ ++ EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &aname, pkey->ameth); ++ snprintf(pem_str, sizeof(pem_str), "%s PRIVATE KEY", aname); ++ if (!PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, pem_str, bio, ++ pkey, enc, NULL, 0, ossl_pem_passwd_cb, ++ (void *)pass)) { ++#endif ++ BIO_free(bio); ++ ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional"); ++ } ++ } ++ return ossl_membio2str(bio); ++} ++ + static VALUE + do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der) + { +@@ -410,8 +456,8 @@ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self) + return do_pkcs8_export(argc, argv, self, 0); + } + +-static VALUE +-do_spki_export(VALUE self, int to_der) ++VALUE ++ossl_pkey_export_spki(VALUE self, int to_der) + { + EVP_PKEY *pkey; + BIO *bio; +@@ -444,7 +490,7 @@ do_spki_export(VALUE self, int to_der) + static VALUE + ossl_pkey_public_to_der(VALUE self) + { +- return do_spki_export(self, 1); ++ return ossl_pkey_export_spki(self, 1); + } + + /* +@@ -456,7 +502,7 @@ ossl_pkey_public_to_der(VALUE self) + static VALUE + ossl_pkey_public_to_pem(VALUE self) + { +- return do_spki_export(self, 0); ++ return ossl_pkey_export_spki(self, 0); + } + + /* +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index 895927e3fb..7dbaed47bc 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -49,6 +49,20 @@ EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE); + EVP_PKEY *GetPKeyPtr(VALUE); + EVP_PKEY *DupPKeyPtr(VALUE); + EVP_PKEY *GetPrivPKeyPtr(VALUE); ++ ++/* ++ * Serializes _self_ in X.509 SubjectPublicKeyInfo format and returns the ++ * resulting String. Sub-classes use this when overriding #to_der. ++ */ ++VALUE ossl_pkey_export_spki(VALUE self, int to_der); ++/* ++ * Serializes the private key _self_ in the traditional private key format ++ * and returns the resulting String. Sub-classes use this when overriding ++ * #to_der. ++ */ ++VALUE ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, ++ int to_der); ++ + void Init_ossl_pkey(void); + + /* +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index 56f58559ed..0e68f7f27f 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -296,34 +296,12 @@ static VALUE + ossl_dsa_export(int argc, VALUE *argv, VALUE self) + { + DSA *dsa; +- BIO *out; +- const EVP_CIPHER *ciph = NULL; +- VALUE cipher, pass, str; + + GetDSA(self, dsa); +- rb_scan_args(argc, argv, "02", &cipher, &pass); +- if (!NIL_P(cipher)) { +- ciph = ossl_evp_get_cipherbyname(cipher); +- pass = ossl_pem_passwd_value(pass); +- } +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eDSAError, NULL); +- } +- if (DSA_HAS_PRIVATE(dsa)) { +- if (!PEM_write_bio_DSAPrivateKey(out, dsa, ciph, NULL, 0, +- ossl_pem_passwd_cb, (void *)pass)){ +- BIO_free(out); +- ossl_raise(eDSAError, NULL); +- } +- } else { +- if (!PEM_write_bio_DSA_PUBKEY(out, dsa)) { +- BIO_free(out); +- ossl_raise(eDSAError, NULL); +- } +- } +- str = ossl_membio2str(out); +- +- return str; ++ if (DSA_HAS_PRIVATE(dsa)) ++ return ossl_pkey_export_traditional(argc, argv, self, 0); ++ else ++ return ossl_pkey_export_spki(self, 0); + } + + /* +@@ -337,25 +315,12 @@ static VALUE + ossl_dsa_to_der(VALUE self) + { + DSA *dsa; +- int (*i2d_func)(DSA *, unsigned char **); +- unsigned char *p; +- long len; +- VALUE str; + + GetDSA(self, dsa); +- if(DSA_HAS_PRIVATE(dsa)) +- i2d_func = (int (*)(DSA *,unsigned char **))i2d_DSAPrivateKey; ++ if (DSA_HAS_PRIVATE(dsa)) ++ return ossl_pkey_export_traditional(0, NULL, self, 1); + else +- i2d_func = i2d_DSA_PUBKEY; +- if((len = i2d_func(dsa, NULL)) <= 0) +- ossl_raise(eDSAError, NULL); +- str = rb_str_new(0, len); +- p = (unsigned char *)RSTRING_PTR(str); +- if(i2d_func(dsa, &p) < 0) +- ossl_raise(eDSAError, NULL); +- ossl_str_adjust(str, p); +- +- return str; ++ return ossl_pkey_export_spki(self, 1); + } + + +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index ca8f5c6e4e..6fe2533e2a 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -141,7 +141,7 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg) + static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) + { + EVP_PKEY *pkey; +- EC_KEY *ec; ++ EC_KEY *ec = NULL; + VALUE arg, pass; + + GetPKey(self, pkey); +@@ -378,66 +378,6 @@ static VALUE ossl_ec_key_is_private(VALUE self) + return EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse; + } + +-static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format) +-{ +- EC_KEY *ec; +- BIO *out; +- int i = -1; +- int private = 0; +- VALUE str; +- const EVP_CIPHER *cipher = NULL; +- +- GetEC(self, ec); +- +- if (EC_KEY_get0_public_key(ec) == NULL) +- ossl_raise(eECError, "can't export - no public key set"); +- +- if (EC_KEY_check_key(ec) != 1) +- ossl_raise(eECError, "can't export - EC_KEY_check_key failed"); +- +- if (EC_KEY_get0_private_key(ec)) +- private = 1; +- +- if (!NIL_P(ciph)) { +- cipher = ossl_evp_get_cipherbyname(ciph); +- pass = ossl_pem_passwd_value(pass); +- } +- +- if (!(out = BIO_new(BIO_s_mem()))) +- ossl_raise(eECError, "BIO_new(BIO_s_mem())"); +- +- switch(format) { +- case EXPORT_PEM: +- if (private) { +- i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, ossl_pem_passwd_cb, (void *)pass); +- } else { +- i = PEM_write_bio_EC_PUBKEY(out, ec); +- } +- +- break; +- case EXPORT_DER: +- if (private) { +- i = i2d_ECPrivateKey_bio(out, ec); +- } else { +- i = i2d_EC_PUBKEY_bio(out, ec); +- } +- +- break; +- default: +- BIO_free(out); +- ossl_raise(rb_eRuntimeError, "unknown format (internal error)"); +- } +- +- if (i != 1) { +- BIO_free(out); +- ossl_raise(eECError, "outlen=%d", i); +- } +- +- str = ossl_membio2str(out); +- +- return str; +-} +- + /* + * call-seq: + * key.export([cipher, pass_phrase]) => String +@@ -448,11 +388,16 @@ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int forma + * instance. Note that encryption will only be effective for a private key, + * public keys will always be encoded in plain text. + */ +-static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self) ++static VALUE ++ossl_ec_key_export(int argc, VALUE *argv, VALUE self) + { +- VALUE cipher, passwd; +- rb_scan_args(argc, argv, "02", &cipher, &passwd); +- return ossl_ec_key_to_string(self, cipher, passwd, EXPORT_PEM); ++ EC_KEY *ec; ++ ++ GetEC(self, ec); ++ if (EC_KEY_get0_private_key(ec)) ++ return ossl_pkey_export_traditional(argc, argv, self, 0); ++ else ++ return ossl_pkey_export_spki(self, 0); + } + + /* +@@ -461,9 +406,16 @@ static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self) + * + * See the OpenSSL documentation for i2d_ECPrivateKey_bio() + */ +-static VALUE ossl_ec_key_to_der(VALUE self) ++static VALUE ++ossl_ec_key_to_der(VALUE self) + { +- return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER); ++ EC_KEY *ec; ++ ++ GetEC(self, ec); ++ if (EC_KEY_get0_private_key(ec)) ++ return ossl_pkey_export_traditional(0, NULL, self, 1); ++ else ++ return ossl_pkey_export_spki(self, 1); + } + + /* +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 8415121c7d..3c298a2aea 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -173,8 +173,8 @@ ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) + static VALUE + ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + { +- EVP_PKEY *pkey; +- RSA *rsa; ++ EVP_PKEY *pkey, *tmp; ++ RSA *rsa = NULL; + BIO *in; + VALUE arg, pass; + +@@ -279,6 +279,21 @@ ossl_rsa_is_private(VALUE self) + return RSA_PRIVATE(self, rsa) ? Qtrue : Qfalse; + } + ++static int ++can_export_rsaprivatekey(VALUE self) ++{ ++ RSA *rsa; ++ const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; ++ ++ GetRSA(self, rsa); ++ ++ RSA_get0_key(rsa, &n, &e, &d); ++ RSA_get0_factors(rsa, &p, &q); ++ RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); ++ ++ return n && e && d && p && q && dmp1 && dmq1 && iqmp; ++} ++ + /* + * call-seq: + * rsa.export([cipher, pass_phrase]) => PEM-format String +@@ -292,41 +307,10 @@ ossl_rsa_is_private(VALUE self) + static VALUE + ossl_rsa_export(int argc, VALUE *argv, VALUE self) + { +- RSA *rsa; +- const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; +- BIO *out; +- const EVP_CIPHER *ciph = NULL; +- VALUE cipher, pass, str; +- +- GetRSA(self, rsa); +- +- rb_scan_args(argc, argv, "02", &cipher, &pass); +- +- if (!NIL_P(cipher)) { +- ciph = ossl_evp_get_cipherbyname(cipher); +- pass = ossl_pem_passwd_value(pass); +- } +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eRSAError, NULL); +- } +- RSA_get0_key(rsa, &n, &e, &d); +- RSA_get0_factors(rsa, &p, &q); +- RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); +- if (n && e && d && p && q && dmp1 && dmq1 && iqmp) { +- if (!PEM_write_bio_RSAPrivateKey(out, rsa, ciph, NULL, 0, +- ossl_pem_passwd_cb, (void *)pass)) { +- BIO_free(out); +- ossl_raise(eRSAError, NULL); +- } +- } else { +- if (!PEM_write_bio_RSA_PUBKEY(out, rsa)) { +- BIO_free(out); +- ossl_raise(eRSAError, NULL); +- } +- } +- str = ossl_membio2str(out); +- +- return str; ++ if (can_export_rsaprivatekey(self)) ++ return ossl_pkey_export_traditional(argc, argv, self, 0); ++ else ++ return ossl_pkey_export_spki(self, 0); + } + + /* +@@ -338,30 +322,10 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self) + static VALUE + ossl_rsa_to_der(VALUE self) + { +- RSA *rsa; +- const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; +- int (*i2d_func)(const RSA *, unsigned char **); +- unsigned char *ptr; +- long len; +- VALUE str; +- +- GetRSA(self, rsa); +- RSA_get0_key(rsa, &n, &e, &d); +- RSA_get0_factors(rsa, &p, &q); +- RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); +- if (n && e && d && p && q && dmp1 && dmq1 && iqmp) +- i2d_func = i2d_RSAPrivateKey; ++ if (can_export_rsaprivatekey(self)) ++ return ossl_pkey_export_traditional(0, NULL, self, 1); + else +- i2d_func = (int (*)(const RSA *, unsigned char **))i2d_RSA_PUBKEY; +- if((len = i2d_func(rsa, NULL)) <= 0) +- ossl_raise(eRSAError, NULL); +- str = rb_str_new(0, len); +- ptr = (unsigned char *)RSTRING_PTR(str); +- if(i2d_func(rsa, &ptr) < 0) +- ossl_raise(eRSAError, NULL); +- ossl_str_adjust(str, ptr); +- +- return str; ++ return ossl_pkey_export_spki(self, 1); + } + + /* +-- +2.32.0 + diff --git a/ruby-3.1.0-Support-GCCs-DWARF-5.patch b/ruby-3.1.0-Support-GCCs-DWARF-5.patch new file mode 100644 index 0000000..d9b434a --- /dev/null +++ b/ruby-3.1.0-Support-GCCs-DWARF-5.patch @@ -0,0 +1,229 @@ +From 3b91792d3d644d6d6b0059cb315c9fe5d3626bab Mon Sep 17 00:00:00 2001 +From: Yusuke Endoh +Date: Sat, 6 Mar 2021 00:03:57 +0900 +Subject: [PATCH] Support GCC's DWARF 5 [Bug #17585] + +Co-Authored-By: xtkoba (Tee KOBAYASHI) +--- + addr2line.c | 119 ++++++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 97 insertions(+), 22 deletions(-) + +diff --git a/addr2line.c b/addr2line.c +index 0029cffbca..855efb40d4 100644 +--- a/addr2line.c ++++ b/addr2line.c +@@ -159,11 +159,12 @@ typedef struct obj_info { + struct dwarf_section debug_info; + struct dwarf_section debug_line; + struct dwarf_section debug_ranges; ++ struct dwarf_section debug_rnglists; + struct dwarf_section debug_str; + struct obj_info *next; + } obj_info_t; + +-#define DWARF_SECTION_COUNT 5 ++#define DWARF_SECTION_COUNT 6 + + static struct dwarf_section * + obj_dwarf_section_at(obj_info_t *obj, int n) +@@ -173,6 +174,7 @@ obj_dwarf_section_at(obj_info_t *obj, int n) + &obj->debug_info, + &obj->debug_line, + &obj->debug_ranges, ++ &obj->debug_rnglists, + &obj->debug_str + }; + if (n < 0 || DWARF_SECTION_COUNT <= n) { +@@ -411,7 +413,7 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line, + FILL_LINE(); + break; + case DW_LNS_advance_pc: +- a = uleb128((char **)&p); ++ a = uleb128((char **)&p) * header.minimum_instruction_length; + addr += a; + break; + case DW_LNS_advance_line: { +@@ -451,7 +453,7 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line, + /* isa = (unsigned int)*/(void)uleb128((char **)&p); + break; + case 0: +- a = *(unsigned char *)p++; ++ a = uleb128((char **)&p); + op = *p++; + switch (op) { + case DW_LNE_end_sequence: +@@ -808,6 +810,18 @@ enum + DW_FORM_addrx4 = 0x2c + }; + ++/* Range list entry encodings */ ++enum { ++ DW_RLE_end_of_list = 0x00, ++ DW_RLE_base_addressx = 0x01, ++ DW_RLE_startx_endx = 0x02, ++ DW_RLE_startx_length = 0x03, ++ DW_RLE_offset_pair = 0x04, ++ DW_RLE_base_address = 0x05, ++ DW_RLE_start_end = 0x06, ++ DW_RLE_start_length = 0x07 ++}; ++ + enum { + VAL_none = 0, + VAL_cstr = 1, +@@ -961,6 +975,23 @@ debug_info_reader_init(DebugInfoReader *reader, obj_info_t *obj) + reader->current_low_pc = 0; + } + ++static void ++di_skip_die_attributes(char **p) ++{ ++ for (;;) { ++ uint64_t at = uleb128(p); ++ uint64_t form = uleb128(p); ++ if (!at && !form) break; ++ switch (form) { ++ default: ++ break; ++ case DW_FORM_implicit_const: ++ sleb128(p); ++ break; ++ } ++ } ++} ++ + static void + di_read_debug_abbrev_cu(DebugInfoReader *reader) + { +@@ -975,12 +1006,7 @@ di_read_debug_abbrev_cu(DebugInfoReader *reader) + prev = abbrev_number; + uleb128(&p); /* tag */ + p++; /* has_children */ +- /* skip content */ +- for (;;) { +- uint64_t at = uleb128(&p); +- uint64_t form = uleb128(&p); +- if (!at && !form) break; +- } ++ di_skip_die_attributes(&p); + } + } + +@@ -1244,12 +1270,7 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number) + /* skip 255th record */ + uleb128(&p); /* tag */ + p++; /* has_children */ +- /* skip content */ +- for (;;) { +- uint64_t at = uleb128(&p); +- uint64_t form = uleb128(&p); +- if (!at && !form) break; +- } ++ di_skip_die_attributes(&p); + for (uint64_t n = uleb128(&p); abbrev_number != n; n = uleb128(&p)) { + if (n == 0) { + fprintf(stderr,"%d: Abbrev Number %"PRId64" not found\n",__LINE__, abbrev_number); +@@ -1257,12 +1278,7 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number) + } + uleb128(&p); /* tag */ + p++; /* has_children */ +- /* skip content */ +- for (;;) { +- uint64_t at = uleb128(&p); +- uint64_t form = uleb128(&p); +- if (!at && !form) break; +- } ++ di_skip_die_attributes(&p); + } + return p; + } +@@ -1390,6 +1406,21 @@ ranges_set(ranges_t *ptr, DebugInfoValue *v) + } + } + ++static uint64_t ++read_dw_form_addr(DebugInfoReader *reader, char **ptr) ++{ ++ char *p = *ptr; ++ *ptr = p + reader->format; ++ if (reader->format == 4) { ++ return read_uint32(&p); ++ } else if (reader->format == 8) { ++ return read_uint64(&p); ++ } else { ++ fprintf(stderr,"unknown address_size:%d", reader->address_size); ++ abort(); ++ } ++} ++ + static uintptr_t + ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr) + { +@@ -1403,8 +1434,50 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr) + } + else if (ptr->ranges_set) { + /* TODO: support base address selection entry */ +- char *p = reader->obj->debug_ranges.ptr + ptr->ranges; ++ char *p; + uint64_t base = ptr->low_pc_set ? ptr->low_pc : reader->current_low_pc; ++ if (reader->obj->debug_rnglists.ptr) { ++ p = reader->obj->debug_rnglists.ptr + ptr->ranges; ++ for (;;) { ++ uint8_t rle = read_uint8(&p); ++ uintptr_t base_address = 0; ++ uintptr_t from, to; ++ if (rle == DW_RLE_end_of_list) break; ++ switch (rle) { ++ case DW_RLE_base_addressx: ++ uleb128(&p); ++ break; ++ case DW_RLE_startx_endx: ++ uleb128(&p); ++ uleb128(&p); ++ break; ++ case DW_RLE_startx_length: ++ uleb128(&p); ++ uleb128(&p); ++ break; ++ case DW_RLE_offset_pair: ++ from = base_address + uleb128(&p); ++ to = base_address + uleb128(&p); ++ if (base + from <= addr && addr < base + to) { ++ return from; ++ } ++ break; ++ case DW_RLE_base_address: ++ base_address = read_dw_form_addr(reader, &p); ++ break; ++ case DW_RLE_start_end: ++ read_dw_form_addr(reader, &p); ++ read_dw_form_addr(reader, &p); ++ break; ++ case DW_RLE_start_length: ++ read_dw_form_addr(reader, &p); ++ uleb128(&p); ++ break; ++ } ++ } ++ return false; ++ } ++ p = reader->obj->debug_ranges.ptr + ptr->ranges; + for (;;) { + uintptr_t from = read_uintptr(&p); + uintptr_t to = read_uintptr(&p); +@@ -1750,6 +1823,7 @@ fill_lines(int num_traces, void **traces, int check_debuglink, + ".debug_info", + ".debug_line", + ".debug_ranges", ++ ".debug_rnglists", + ".debug_str" + }; + +@@ -2006,6 +2080,7 @@ found_mach_header: + "__debug_info", + "__debug_line", + "__debug_ranges", ++ "__debug_rnglists", + "__debug_str" + }; + struct LP(segment_command) *scmd = (struct LP(segment_command) *)lcmd; diff --git a/ruby-3.1.0-Use-EVP-API-in-more-places.patch b/ruby-3.1.0-Use-EVP-API-in-more-places.patch new file mode 100644 index 0000000..f9c4580 --- /dev/null +++ b/ruby-3.1.0-Use-EVP-API-in-more-places.patch @@ -0,0 +1,831 @@ +From cf070378020088cd7e69b1cb08be68152ab8a078 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 17 May 2020 18:25:38 +0900 +Subject: [PATCH 1/3] pkey: implement #to_text using EVP API + +Use EVP_PKEY_print_private() instead of the low-level API *_print() +functions, such as RSA_print(). + +EVP_PKEY_print_*() family was added in OpenSSL 1.0.0. + +Note that it falls back to EVP_PKEY_print_public() and +EVP_PKEY_print_params() as necessary. This is required for EVP_PKEY_DH +type for which _private() fails if the private component is not set in +the pkey object. + +Since the new API works in the same way for all key types, we now +implement #to_text in the base class OpenSSL::PKey::PKey rather than in +each subclass. +--- + ext/openssl/ossl_pkey.c | 38 +++++++++++++++++++++++++++++++++++++ + ext/openssl/ossl_pkey_dh.c | 29 ---------------------------- + ext/openssl/ossl_pkey_dsa.c | 29 ---------------------------- + ext/openssl/ossl_pkey_ec.c | 27 -------------------------- + ext/openssl/ossl_pkey_rsa.c | 31 ------------------------------ + test/openssl/test_pkey.rb | 5 +++++ + 6 files changed, 43 insertions(+), 116 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index f9282b9417..21cd4b2cda 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -539,6 +539,43 @@ ossl_pkey_inspect(VALUE self) + OBJ_nid2sn(nid)); + } + ++/* ++ * call-seq: ++ * pkey.to_text -> string ++ * ++ * Dumps key parameters, public key, and private key components contained in ++ * the key into a human-readable text. ++ * ++ * This is intended for debugging purpose. ++ * ++ * See also the man page EVP_PKEY_print_private(3). ++ */ ++static VALUE ++ossl_pkey_to_text(VALUE self) ++{ ++ EVP_PKEY *pkey; ++ BIO *bio; ++ ++ GetPKey(self, pkey); ++ if (!(bio = BIO_new(BIO_s_mem()))) ++ ossl_raise(ePKeyError, "BIO_new"); ++ ++ if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1) ++ goto out; ++ ++ BIO_free(bio); ++ ossl_raise(ePKeyError, "EVP_PKEY_print_params"); ++ ++ out: ++ return ossl_membio2str(bio); ++} ++ + VALUE + ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der) + { +@@ -1039,6 +1076,7 @@ Init_ossl_pkey(void) + rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0); + rb_define_method(cPKey, "oid", ossl_pkey_oid, 0); + rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0); ++ rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0); + rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1); + rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1); + rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0); +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index 6b477b077c..acd3bf474e 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -266,34 +266,6 @@ ossl_dh_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * dh.to_text -> aString +- * +- * Prints all parameters of key to buffer +- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! +- * Don't use :-)) (I's up to you) +- */ +-static VALUE +-ossl_dh_to_text(VALUE self) +-{ +- DH *dh; +- BIO *out; +- VALUE str; +- +- GetDH(self, dh); +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eDHError, NULL); +- } +- if (!DHparams_print(out, dh)) { +- BIO_free(out); +- ossl_raise(eDHError, NULL); +- } +- str = ossl_membio2str(out); +- +- return str; +-} +- + /* + * call-seq: + * dh.public_key -> aDH +@@ -426,7 +398,6 @@ Init_ossl_dh(void) + rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1); + rb_define_method(cDH, "public?", ossl_dh_is_public, 0); + rb_define_method(cDH, "private?", ossl_dh_is_private, 0); +- rb_define_method(cDH, "to_text", ossl_dh_to_text, 0); + rb_define_method(cDH, "export", ossl_dh_export, 0); + rb_define_alias(cDH, "to_pem", "export"); + rb_define_alias(cDH, "to_s", "export"); +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index 1c5a8a737e..f017cceb4a 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -264,34 +264,6 @@ ossl_dsa_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * dsa.to_text -> aString +- * +- * Prints all parameters of key to buffer +- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! +- * Don't use :-)) (I's up to you) +- */ +-static VALUE +-ossl_dsa_to_text(VALUE self) +-{ +- DSA *dsa; +- BIO *out; +- VALUE str; +- +- GetDSA(self, dsa); +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eDSAError, NULL); +- } +- if (!DSA_print(out, dsa, 0)) { /* offset = 0 */ +- BIO_free(out); +- ossl_raise(eDSAError, NULL); +- } +- str = ossl_membio2str(out); +- +- return str; +-} +- + /* + * call-seq: + * dsa.public_key -> aDSA +@@ -469,7 +441,6 @@ Init_ossl_dsa(void) + + rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0); + rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0); +- rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0); + rb_define_method(cDSA, "export", ossl_dsa_export, -1); + rb_define_alias(cDSA, "to_pem", "export"); + rb_define_alias(cDSA, "to_s", "export"); +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index c2534251c3..ecb8305184 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -417,32 +417,6 @@ ossl_ec_key_to_der(VALUE self) + else + return ossl_pkey_export_spki(self, 1); + } +- +-/* +- * call-seq: +- * key.to_text => String +- * +- * See the OpenSSL documentation for EC_KEY_print() +- */ +-static VALUE ossl_ec_key_to_text(VALUE self) +-{ +- EC_KEY *ec; +- BIO *out; +- VALUE str; +- +- GetEC(self, ec); +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eECError, "BIO_new(BIO_s_mem())"); +- } +- if (!EC_KEY_print(out, ec, 0)) { +- BIO_free(out); +- ossl_raise(eECError, "EC_KEY_print"); +- } +- str = ossl_membio2str(out); +- +- return str; +-} +- + /* + * call-seq: + * key.generate_key! => self +@@ -1633,7 +1607,6 @@ void Init_ossl_ec(void) + rb_define_method(cEC, "export", ossl_ec_key_export, -1); + rb_define_alias(cEC, "to_pem", "export"); + rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0); +- rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0); + + + rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc); +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 43f82cb29e..7a7e66dbda 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -587,36 +587,6 @@ ossl_rsa_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * rsa.to_text => String +- * +- * THIS METHOD IS INSECURE, PRIVATE INFORMATION CAN LEAK OUT!!! +- * +- * Dumps all parameters of a keypair to a String +- * +- * Don't use :-)) (It's up to you) +- */ +-static VALUE +-ossl_rsa_to_text(VALUE self) +-{ +- RSA *rsa; +- BIO *out; +- VALUE str; +- +- GetRSA(self, rsa); +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eRSAError, NULL); +- } +- if (!RSA_print(out, rsa, 0)) { /* offset = 0 */ +- BIO_free(out); +- ossl_raise(eRSAError, NULL); +- } +- str = ossl_membio2str(out); +- +- return str; +-} +- + /* + * call-seq: + * rsa.public_key -> RSA +@@ -738,7 +708,6 @@ Init_ossl_rsa(void) + + rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0); + rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0); +- rb_define_method(cRSA, "to_text", ossl_rsa_to_text, 0); + rb_define_method(cRSA, "export", ossl_rsa_export, -1); + rb_define_alias(cRSA, "to_pem", "export"); + rb_define_alias(cRSA, "to_s", "export"); +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index 5307fe5b08..3630458b3c 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -151,4 +151,9 @@ def test_x25519 + assert_equal bob_pem, bob.public_to_pem + assert_equal [shared_secret].pack("H*"), alice.derive(bob) + end ++ ++ def test_to_text ++ rsa = Fixtures.pkey("rsa1024") ++ assert_include rsa.to_text, "publicExponent" ++ end + end +-- +2.32.0 + + +From 0c45b22e485bfa62f4d704b08e3704e6444118c4 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Thu, 15 Apr 2021 19:11:32 +0900 +Subject: [PATCH 2/3] pkey: implement {DH,DSA,RSA}#public_key in Ruby + +The low-level API that is used to implement #public_key is deprecated +in OpenSSL 3.0. It is actually very simple to implement in another way, +using existing methods only, in much shorter code. Let's do it. + +While we are at it, the documentation is updated to recommend against +using #public_key. Now that OpenSSL::PKey::PKey implements public_to_der +method, there is no real use case for #public_key in newly written Ruby +programs. +--- + ext/openssl/lib/openssl/pkey.rb | 55 ++++++++++++++++++++++++++++ + ext/openssl/ossl_pkey_dh.c | 63 +++++++-------------------------- + ext/openssl/ossl_pkey_dsa.c | 42 ---------------------- + ext/openssl/ossl_pkey_rsa.c | 58 +----------------------------- + test/openssl/test_pkey_rsa.rb | 37 ++++++++++--------- + 5 files changed, 87 insertions(+), 168 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 53ee52f98b..569559e1ce 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -10,6 +10,30 @@ module OpenSSL::PKey + class DH + include OpenSSL::Marshal + ++ # :call-seq: ++ # dh.public_key -> dhnew ++ # ++ # Returns a new DH instance that carries just the \DH parameters. ++ # ++ # Contrary to the method name, the returned DH object contains only ++ # parameters and not the public key. ++ # ++ # This method is provided for backwards compatibility. In most cases, there ++ # is no need to call this method. ++ # ++ # For the purpose of re-generating the key pair while keeping the ++ # parameters, check OpenSSL::PKey.generate_key. ++ # ++ # Example: ++ # # OpenSSL::PKey::DH.generate by default generates a random key pair ++ # dh1 = OpenSSL::PKey::DH.generate(2048) ++ # p dh1.priv_key #=> # ++ # dhcopy = dh1.public_key ++ # p dhcopy.priv_key #=> nil ++ def public_key ++ DH.new(to_der) ++ end ++ + # :call-seq: + # dh.compute_key(pub_bn) -> string + # +@@ -89,6 +113,22 @@ def new(*args, &blk) # :nodoc: + class DSA + include OpenSSL::Marshal + ++ # :call-seq: ++ # dsa.public_key -> dsanew ++ # ++ # Returns a new DSA instance that carries just the \DSA parameters and the ++ # public key. ++ # ++ # This method is provided for backwards compatibility. In most cases, there ++ # is no need to call this method. ++ # ++ # For the purpose of serializing the public key, to PEM or DER encoding of ++ # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and ++ # PKey#public_to_der. ++ def public_key ++ OpenSSL::PKey.read(public_to_der) ++ end ++ + class << self + # :call-seq: + # DSA.generate(size) -> dsa +@@ -159,6 +199,21 @@ def to_bn(conversion_form = group.point_conversion_form) + class RSA + include OpenSSL::Marshal + ++ # :call-seq: ++ # rsa.public_key -> rsanew ++ # ++ # Returns a new RSA instance that carries just the public key components. ++ # ++ # This method is provided for backwards compatibility. In most cases, there ++ # is no need to call this method. ++ # ++ # For the purpose of serializing the public key, to PEM or DER encoding of ++ # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and ++ # PKey#public_to_der. ++ def public_key ++ OpenSSL::PKey.read(public_to_der) ++ end ++ + class << self + # :call-seq: + # RSA.generate(size, exponent = 65537) -> RSA +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index acd3bf474e..a512b209d3 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -266,48 +266,6 @@ ossl_dh_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * dh.public_key -> aDH +- * +- * Returns a new DH instance that carries just the public information, i.e. +- * the prime _p_ and the generator _g_, but no public/private key yet. Such +- * a pair may be generated using DH#generate_key!. The "public key" needed +- * for a key exchange with DH#compute_key is considered as per-session +- * information and may be retrieved with DH#pub_key once a key pair has +- * been generated. +- * If the current instance already contains private information (and thus a +- * valid public/private key pair), this information will no longer be present +- * in the new instance generated by DH#public_key. This feature is helpful for +- * publishing the Diffie-Hellman parameters without leaking any of the private +- * per-session information. +- * +- * === Example +- * dh = OpenSSL::PKey::DH.new(2048) # has public and private key set +- * public_key = dh.public_key # contains only prime and generator +- * parameters = public_key.to_der # it's safe to publish this +- */ +-static VALUE +-ossl_dh_to_public_key(VALUE self) +-{ +- EVP_PKEY *pkey; +- DH *orig_dh, *dh; +- VALUE obj; +- +- obj = rb_obj_alloc(rb_obj_class(self)); +- GetPKey(obj, pkey); +- +- GetDH(self, orig_dh); +- dh = DHparams_dup(orig_dh); +- if (!dh) +- ossl_raise(eDHError, "DHparams_dup"); +- if (!EVP_PKEY_assign_DH(pkey, dh)) { +- DH_free(dh); +- ossl_raise(eDHError, "EVP_PKEY_assign_DH"); +- } +- return obj; +-} +- + /* + * call-seq: + * dh.params_ok? -> true | false +@@ -384,14 +342,20 @@ Init_ossl_dh(void) + * The per-session private key, an OpenSSL::BN. + * + * === Example of a key exchange +- * dh1 = OpenSSL::PKey::DH.new(2048) +- * der = dh1.public_key.to_der #you may send this publicly to the participating party +- * dh2 = OpenSSL::PKey::DH.new(der) +- * dh2.generate_key! #generate the per-session key pair +- * symm_key1 = dh1.compute_key(dh2.pub_key) +- * symm_key2 = dh2.compute_key(dh1.pub_key) ++ * # you may send the parameters (der) and own public key (pub1) publicly ++ * # to the participating party ++ * dh1 = OpenSSL::PKey::DH.new(2048) ++ * der = dh1.to_der ++ * pub1 = dh1.pub_key ++ * ++ * # the other party generates its per-session key pair ++ * dhparams = OpenSSL::PKey::DH.new(der) ++ * dh2 = OpenSSL::PKey.generate_key(dhparams) ++ * pub2 = dh2.pub_key + * +- * puts symm_key1 == symm_key2 # => true ++ * symm_key1 = dh1.compute_key(pub2) ++ * symm_key2 = dh2.compute_key(pub1) ++ * puts symm_key1 == symm_key2 # => true + */ + cDH = rb_define_class_under(mPKey, "DH", cPKey); + rb_define_method(cDH, "initialize", ossl_dh_initialize, -1); +@@ -402,7 +366,6 @@ Init_ossl_dh(void) + rb_define_alias(cDH, "to_pem", "export"); + rb_define_alias(cDH, "to_s", "export"); + rb_define_method(cDH, "to_der", ossl_dh_to_der, 0); +- rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0); + rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0); + + DEF_OSSL_PKEY_BN(cDH, dh, p); +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index f017cceb4a..ab9ac781e8 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -264,47 +264,6 @@ ossl_dsa_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * dsa.public_key -> aDSA +- * +- * Returns a new DSA instance that carries just the public key information. +- * If the current instance has also private key information, this will no +- * longer be present in the new instance. This feature is helpful for +- * publishing the public key information without leaking any of the private +- * information. +- * +- * === Example +- * dsa = OpenSSL::PKey::DSA.new(2048) # has public and private information +- * pub_key = dsa.public_key # has only the public part available +- * pub_key_der = pub_key.to_der # it's safe to publish this +- * +- * +- */ +-static VALUE +-ossl_dsa_to_public_key(VALUE self) +-{ +- EVP_PKEY *pkey, *pkey_new; +- DSA *dsa; +- VALUE obj; +- +- GetPKeyDSA(self, pkey); +- obj = rb_obj_alloc(rb_obj_class(self)); +- GetPKey(obj, pkey_new); +- +-#define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \ +- (i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa)) +- dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey)); +-#undef DSAPublicKey_dup +- if (!dsa) +- ossl_raise(eDSAError, "DSAPublicKey_dup"); +- if (!EVP_PKEY_assign_DSA(pkey_new, dsa)) { +- DSA_free(dsa); +- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); +- } +- return obj; +-} +- + /* + * call-seq: + * dsa.syssign(string) -> aString +@@ -445,7 +404,6 @@ Init_ossl_dsa(void) + rb_define_alias(cDSA, "to_pem", "export"); + rb_define_alias(cDSA, "to_s", "export"); + rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0); +- rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0); + rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1); + rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2); + +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 7a7e66dbda..1c5476cdcd 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -390,7 +390,7 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) + * data = "Sign me!" + * pkey = OpenSSL::PKey::RSA.new(2048) + * signature = pkey.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA256") +- * pub_key = pkey.public_key ++ * pub_key = OpenSSL::PKey.read(pkey.public_to_der) + * puts pub_key.verify_pss("SHA256", signature, data, + * salt_length: :auto, mgf1_hash: "SHA256") # => true + */ +@@ -587,61 +587,6 @@ ossl_rsa_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * rsa.public_key -> RSA +- * +- * Makes new RSA instance containing the public key from the private key. +- */ +-static VALUE +-ossl_rsa_to_public_key(VALUE self) +-{ +- EVP_PKEY *pkey, *pkey_new; +- RSA *rsa; +- VALUE obj; +- +- GetPKeyRSA(self, pkey); +- obj = rb_obj_alloc(rb_obj_class(self)); +- GetPKey(obj, pkey_new); +- +- rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey)); +- if (!rsa) +- ossl_raise(eRSAError, "RSAPublicKey_dup"); +- if (!EVP_PKEY_assign_RSA(pkey_new, rsa)) { +- RSA_free(rsa); +- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); +- } +- return obj; +-} +- +-/* +- * TODO: Test me +- +-static VALUE +-ossl_rsa_blinding_on(VALUE self) +-{ +- RSA *rsa; +- +- GetRSA(self, rsa); +- +- if (RSA_blinding_on(rsa, ossl_bn_ctx) != 1) { +- ossl_raise(eRSAError, NULL); +- } +- return self; +-} +- +-static VALUE +-ossl_rsa_blinding_off(VALUE self) +-{ +- RSA *rsa; +- +- GetRSA(self, rsa); +- RSA_blinding_off(rsa); +- +- return self; +-} +- */ +- + /* + * Document-method: OpenSSL::PKey::RSA#set_key + * call-seq: +@@ -712,7 +657,6 @@ Init_ossl_rsa(void) + rb_define_alias(cRSA, "to_pem", "export"); + rb_define_alias(cRSA, "to_s", "export"); + rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0); +- rb_define_method(cRSA, "public_key", ossl_rsa_to_public_key, 0); + rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, -1); + rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1); + rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1); +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index d1e68dbc9f..5f8d04e754 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -69,29 +69,28 @@ def test_private + end + + def test_new +- key = OpenSSL::PKey::RSA.new 512 +- pem = key.public_key.to_pem +- OpenSSL::PKey::RSA.new pem +- assert_equal([], OpenSSL.errors) +- end ++ key = OpenSSL::PKey::RSA.new(512) ++ assert_equal 512, key.n.num_bits ++ assert_equal 65537, key.e ++ assert_not_nil key.d + +- def test_new_exponent_default +- assert_equal(65537, OpenSSL::PKey::RSA.new(512).e) ++ # Specify public exponent ++ key2 = OpenSSL::PKey::RSA.new(512, 3) ++ assert_equal 512, key2.n.num_bits ++ assert_equal 3, key2.e ++ assert_not_nil key2.d + end + +- def test_new_with_exponent +- 1.upto(30) do |idx| +- e = (2 ** idx) + 1 +- key = OpenSSL::PKey::RSA.new(512, e) +- assert_equal(e, key.e) +- end +- end ++ def test_s_generate ++ key1 = OpenSSL::PKey::RSA.generate(512) ++ assert_equal 512, key1.n.num_bits ++ assert_equal 65537, key1.e + +- def test_generate +- key = OpenSSL::PKey::RSA.generate(512, 17) +- assert_equal 512, key.n.num_bits +- assert_equal 17, key.e +- assert_not_nil key.d ++ # Specify public exponent ++ key2 = OpenSSL::PKey::RSA.generate(512, 3) ++ assert_equal 512, key2.n.num_bits ++ assert_equal 3, key2.e ++ assert_not_nil key2.d + end + + def test_new_break +-- +2.32.0 + + +From 2150af0e55b2a25c24f62006e27e0aec3dc81b57 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 10 Jul 2020 14:34:51 +0900 +Subject: [PATCH 3/3] pkey/dh, pkey/ec: use EVP_PKEY_check() family + +Use EVP_PKEY_param_check() instead of DH_check() if available. Also, +use EVP_PKEY_public_check() instead of EC_KEY_check_key(). + +EVP_PKEY_*check() is part of the EVP API and is meant to replace those +low-level functions. They were added by OpenSSL 1.1.1. It is currently +not provided by LibreSSL. +--- + ext/openssl/extconf.rb | 3 +++ + ext/openssl/ossl_pkey_dh.c | 27 +++++++++++++++++++++++---- + ext/openssl/ossl_pkey_ec.c | 23 +++++++++++++++++++---- + test/openssl/test_pkey_dh.rb | 16 ++++++++++++++++ + 4 files changed, 61 insertions(+), 8 deletions(-) + +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index b3c6647faf..17d93443fc 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -172,6 +172,9 @@ def find_openssl_library + have_func("EVP_PBE_scrypt") + have_func("SSL_CTX_set_post_handshake_auth") + ++# added in 1.1.1 ++have_func("EVP_PKEY_check") ++ + Logging::message "=== Checking done. ===\n" + + create_header +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index a512b209d3..ca782bbe59 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -273,19 +273,38 @@ ossl_dh_get_params(VALUE self) + * Validates the Diffie-Hellman parameters associated with this instance. + * It checks whether a safe prime and a suitable generator are used. If this + * is not the case, +false+ is returned. ++ * ++ * See also the man page EVP_PKEY_param_check(3). + */ + static VALUE + ossl_dh_check_params(VALUE self) + { ++ int ret; ++#ifdef HAVE_EVP_PKEY_CHECK ++ EVP_PKEY *pkey; ++ EVP_PKEY_CTX *pctx; ++ ++ GetPKey(self, pkey); ++ pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!pctx) ++ ossl_raise(eDHError, "EVP_PKEY_CTX_new"); ++ ret = EVP_PKEY_param_check(pctx); ++ EVP_PKEY_CTX_free(pctx); ++#else + DH *dh; + int codes; + + GetDH(self, dh); +- if (!DH_check(dh, &codes)) { +- return Qfalse; +- } ++ ret = DH_check(dh, &codes) == 1 && codes == 0; ++#endif + +- return codes == 0 ? Qtrue : Qfalse; ++ if (ret == 1) ++ return Qtrue; ++ else { ++ /* DH_check_ex() will put error entry on failure */ ++ ossl_clear_error(); ++ return Qfalse; ++ } + } + + /* +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index ecb8305184..829529d4b9 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -443,20 +443,35 @@ static VALUE ossl_ec_key_generate_key(VALUE self) + } + + /* +- * call-seq: +- * key.check_key => true ++ * call-seq: ++ * key.check_key => true + * +- * Raises an exception if the key is invalid. ++ * Raises an exception if the key is invalid. + * +- * See the OpenSSL documentation for EC_KEY_check_key() ++ * See also the man page EVP_PKEY_public_check(3). + */ + static VALUE ossl_ec_key_check_key(VALUE self) + { ++#ifdef HAVE_EVP_PKEY_CHECK ++ EVP_PKEY *pkey; ++ EVP_PKEY_CTX *pctx; ++ int ret; ++ ++ GetPKey(self, pkey); ++ pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!pctx) ++ ossl_raise(eDHError, "EVP_PKEY_CTX_new"); ++ ret = EVP_PKEY_public_check(pctx); ++ EVP_PKEY_CTX_free(pctx); ++ if (ret != 1) ++ ossl_raise(eECError, "EVP_PKEY_public_check"); ++#else + EC_KEY *ec; + + GetEC(self, ec); + if (EC_KEY_check_key(ec) != 1) + ossl_raise(eECError, "EC_KEY_check_key"); ++#endif + + return Qtrue; + } +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index 279ce1984c..f80af8f841 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -86,6 +86,22 @@ def test_key_exchange + assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key)) + end + ++ def test_params_ok? ++ dh0 = Fixtures.pkey("dh1024") ++ ++ dh1 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([ ++ OpenSSL::ASN1::Integer(dh0.p), ++ OpenSSL::ASN1::Integer(dh0.g) ++ ])) ++ assert_equal(true, dh1.params_ok?) ++ ++ dh2 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([ ++ OpenSSL::ASN1::Integer(dh0.p + 1), ++ OpenSSL::ASN1::Integer(dh0.g) ++ ])) ++ assert_equal(false, dh2.params_ok?) ++ end ++ + def test_dup + dh = Fixtures.pkey("dh1024") + dh2 = dh.dup +-- +2.32.0 + diff --git a/ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.patch b/ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.patch new file mode 100644 index 0000000..dfdd690 --- /dev/null +++ b/ruby-3.1.0-Use-OSSL_DECODER-to-load-encrypted-PEM-on-OpenSSL-3.0.patch @@ -0,0 +1,114 @@ +From 8c185e0ae5e42bf5f3d76a1a0898946671116fa3 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Wed, 3 Nov 2021 23:31:29 +0900 +Subject: [PATCH 1/2] pkey: test parsing concatenated PEM string + +PEM-encoded private keys are sometimes stored together with irrelevant +PEM blocks, such as the corresponding X.509 certificate. + +PEM_read_bio_*() family automatically skips unknown PEM blocks, but on +OpenSSL 3.0 we will be using the new OSSL_DECODER API instead due to +some breaking changes around the password callback. + +Let's add a test case so that we won't break the current behavior. +--- + test/openssl/test_pkey_rsa.rb | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index dbe87ba4..7510658d 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -306,6 +306,12 @@ def test_RSAPrivateKey + + assert_equal asn1.to_der, rsa1024.to_der + assert_equal pem, rsa1024.export ++ ++ # Unknown PEM prepended ++ cert = issue_cert(OpenSSL::X509::Name.new([["CN", "nobody"]]), rsa1024, 1, [], nil, nil) ++ str = cert.to_text + cert.to_pem + rsa1024.to_pem ++ key = OpenSSL::PKey::RSA.new(str) ++ assert_same_rsa rsa1024, key + end + + def test_RSAPrivateKey_encrypted + +From a84ea531bbd080c3f58fe8d3dc9ffb1af2251f35 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 20 Mar 2021 23:16:16 +0900 +Subject: [PATCH 2/2] pkey: use OSSL_DECODER to load encrypted PEM on OpenSSL + 3.0 + +OpenSSL 3.0 has rewritten routines to load pkeys (PEM_read_bio_* and +d2i_* functions) around the newly introduced OSSL_DECODER API. + +This comes with a slight behavior change. They now decrypt and parse +each encountered PEM block, then check the kind of the block. This used +to be the reverse: they checked the PEM header to see the kind, and then +decrypted the content. This means that the password callback may now be +called repeatedly. + +Let's use the OSSL_DECODER API directly on OpenSSL 3.0 so that the +return value from the password callback will be reused automatically. +--- + ext/openssl/ossl_pkey.c | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index f9f5162e..b08168a5 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -78,6 +78,45 @@ ossl_pkey_new(EVP_PKEY *pkey) + return obj; + } + ++#if OSSL_OPENSSL_PREREQ(3, 0, 0) ++# include ++ ++EVP_PKEY * ++ossl_pkey_read_generic(BIO *bio, VALUE pass) ++{ ++ void *ppass = (void *)pass; ++ OSSL_DECODER_CTX *dctx; ++ EVP_PKEY *pkey = NULL; ++ int pos = 0, pos2; ++ ++ dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, NULL, 0, NULL, NULL); ++ if (!dctx) ++ goto out; ++ if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1) ++ goto out; ++ ++ /* First check DER */ ++ if (OSSL_DECODER_from_bio(dctx, bio) == 1) ++ goto out; ++ ++ /* Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed */ ++ OSSL_BIO_reset(bio); ++ if (OSSL_DECODER_CTX_set_input_type(dctx, "PEM") != 1) ++ goto out; ++ while (OSSL_DECODER_from_bio(dctx, bio) != 1) { ++ if (BIO_eof(bio)) ++ goto out; ++ pos2 = BIO_tell(bio); ++ if (pos2 < 0 || pos2 <= pos) ++ goto out; ++ pos = pos2; ++ } ++ ++ out: ++ OSSL_DECODER_CTX_free(dctx); ++ return pkey; ++} ++#else + EVP_PKEY * + ossl_pkey_read_generic(BIO *bio, VALUE pass) + { +@@ -106,6 +145,7 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass) + out: + return pkey; + } ++#endif + + /* + * call-seq: diff --git a/ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch b/ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch new file mode 100644 index 0000000..d02ce45 --- /dev/null +++ b/ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch @@ -0,0 +1,1113 @@ +From e8504c6248c4b0e5e961f57f004e1133c20c88a5 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 5 Apr 2021 00:30:01 +0900 +Subject: [PATCH 1/5] pkey: fix interrupt handling in + OpenSSL::PKey.generate_key + +rb_thread_call_without_gvl() can be interrupted, but it may be able to +resume the operation. Call rb_thread_check_ints() to see if it raises +an exception or not. +--- + ext/openssl/ossl_pkey.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 22e9f19982..d76f0600d1 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -239,7 +239,7 @@ struct pkey_blocking_generate_arg { + int state; + int yield: 1; + int genparam: 1; +- int stop: 1; ++ int interrupted: 1; + }; + + static VALUE +@@ -261,23 +261,31 @@ static int + pkey_gen_cb(EVP_PKEY_CTX *ctx) + { + struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx); ++ int state; + + if (arg->yield) { +- int state; + rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state); + if (state) { +- arg->stop = 1; + arg->state = state; ++ return 0; ++ } ++ } ++ if (arg->interrupted) { ++ arg->interrupted = 0; ++ state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL); ++ if (state) { ++ arg->state = state; ++ return 0; + } + } +- return !arg->stop; ++ return 1; + } + + static void + pkey_blocking_gen_stop(void *ptr) + { + struct pkey_blocking_generate_arg *arg = ptr; +- arg->stop = 1; ++ arg->interrupted = 1; + } + + static void * +-- +2.32.0 + + +From f433d1b680e7ac5ef13fc15b0844267222438cf3 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 17 May 2020 20:48:23 +0900 +Subject: [PATCH 2/5] pkey/dh: use high level EVP interface to generate + parameters and keys + +Implement PKey::DH.new(size, gen), PKey::DH.generate(size, gen), and +PKey::DH#generate_key! using PKey.generate_parameters and .generate_key +instead of the low level DH functions. + +Note that the EVP interface can enforce additional restrictions - for +example, DH key shorter than 2048 bits is no longer accepted by default +in OpenSSL 3.0. The test code is updated accordingly. +--- + ext/openssl/lib/openssl/pkey.rb | 57 ++++++++++ + ext/openssl/ossl_pkey_dh.c | 186 ++++++-------------------------- + test/openssl/test_pkey_dh.rb | 15 ++- + 3 files changed, 101 insertions(+), 157 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index be60ac2beb..5a3d0ed1ef 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -27,6 +27,63 @@ def compute_key(pub_bn) + peer.set_key(pub_bn, nil) + derive(peer) + end ++ ++ # :call-seq: ++ # dh.generate_key! -> self ++ # ++ # Generates a private and public key unless a private key already exists. ++ # If this DH instance was generated from public \DH parameters (e.g. by ++ # encoding the result of DH#public_key), then this method needs to be ++ # called first in order to generate the per-session keys before performing ++ # the actual key exchange. ++ # ++ # See also OpenSSL::PKey.generate_key. ++ # ++ # Example: ++ # dh = OpenSSL::PKey::DH.new(2048) ++ # public_key = dh.public_key #contains no private/public key yet ++ # public_key.generate_key! ++ # puts public_key.private? # => true ++ def generate_key! ++ unless priv_key ++ tmp = OpenSSL::PKey.generate_key(self) ++ set_key(tmp.pub_key, tmp.priv_key) ++ end ++ self ++ end ++ ++ class << self ++ # :call-seq: ++ # DH.generate(size, generator = 2) -> dh ++ # ++ # Creates a new DH instance from scratch by generating random parameters ++ # and a key pair. ++ # ++ # See also OpenSSL::PKey.generate_parameters and ++ # OpenSSL::PKey.generate_key. ++ # ++ # +size+:: ++ # The desired key size in bits. ++ # +generator+:: ++ # The generator. ++ def generate(size, generator = 2, &blk) ++ dhparams = OpenSSL::PKey.generate_parameters("DH", { ++ "dh_paramgen_prime_len" => size, ++ "dh_paramgen_generator" => generator, ++ }, &blk) ++ OpenSSL::PKey.generate_key(dhparams) ++ end ++ ++ # Handle DH.new(size, generator) form here; new(str) and new() forms ++ # are handled by #initialize ++ def new(*args, &blk) # :nodoc: ++ if args[0].is_a?(Integer) ++ generate(*args, &blk) ++ else ++ super ++ end ++ end ++ end + end + + class DSA +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index 5bc1c49ca1..6b477b077c 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -32,147 +32,56 @@ VALUE eDHError; + /* + * Private + */ +-struct dh_blocking_gen_arg { +- DH *dh; +- int size; +- int gen; +- BN_GENCB *cb; +- int result; +-}; +- +-static void * +-dh_blocking_gen(void *arg) +-{ +- struct dh_blocking_gen_arg *gen = (struct dh_blocking_gen_arg *)arg; +- gen->result = DH_generate_parameters_ex(gen->dh, gen->size, gen->gen, gen->cb); +- return 0; +-} +- +-static DH * +-dh_generate(int size, int gen) +-{ +- struct ossl_generate_cb_arg cb_arg = { 0 }; +- struct dh_blocking_gen_arg gen_arg; +- DH *dh = DH_new(); +- BN_GENCB *cb = BN_GENCB_new(); +- +- if (!dh || !cb) { +- DH_free(dh); +- BN_GENCB_free(cb); +- ossl_raise(eDHError, "malloc failure"); +- } +- +- if (rb_block_given_p()) +- cb_arg.yield = 1; +- BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); +- gen_arg.dh = dh; +- gen_arg.size = size; +- gen_arg.gen = gen; +- gen_arg.cb = cb; +- if (cb_arg.yield == 1) { +- /* we cannot release GVL when callback proc is supplied */ +- dh_blocking_gen(&gen_arg); +- } else { +- /* there's a chance to unblock */ +- rb_thread_call_without_gvl(dh_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); +- } +- +- BN_GENCB_free(cb); +- if (!gen_arg.result) { +- DH_free(dh); +- if (cb_arg.state) { +- /* Clear OpenSSL error queue before re-raising. */ +- ossl_clear_error(); +- rb_jump_tag(cb_arg.state); +- } +- ossl_raise(eDHError, "DH_generate_parameters_ex"); +- } +- +- if (!DH_generate_key(dh)) { +- DH_free(dh); +- ossl_raise(eDHError, "DH_generate_key"); +- } +- +- return dh; +-} +- +-/* +- * call-seq: +- * DH.generate(size [, generator]) -> dh +- * +- * Creates a new DH instance from scratch by generating the private and public +- * components alike. +- * +- * === Parameters +- * * _size_ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure. +- * * _generator_ is a small number > 1, typically 2 or 5. +- * +- */ +-static VALUE +-ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) +-{ +- EVP_PKEY *pkey; +- DH *dh ; +- int g = 2; +- VALUE size, gen, obj; +- +- if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) { +- g = NUM2INT(gen); +- } +- obj = rb_obj_alloc(klass); +- GetPKey(obj, pkey); +- +- dh = dh_generate(NUM2INT(size), g); +- if (!EVP_PKEY_assign_DH(pkey, dh)) { +- DH_free(dh); +- ossl_raise(eDHError, "EVP_PKEY_assign_DH"); +- } +- return obj; +-} +- + /* + * call-seq: + * DH.new -> dh + * DH.new(string) -> dh + * DH.new(size [, generator]) -> dh + * +- * Either generates a DH instance from scratch or by reading already existing +- * DH parameters from _string_. Note that when reading a DH instance from +- * data that was encoded from a DH instance by using DH#to_pem or DH#to_der +- * the result will *not* contain a public/private key pair yet. This needs to +- * be generated using DH#generate_key! first. ++ * Creates a new instance of OpenSSL::PKey::DH. ++ * ++ * If called without arguments, an empty instance without any parameter or key ++ * components is created. Use #set_pqg to manually set the parameters afterwards ++ * (and optionally #set_key to set private and public key components). ++ * ++ * If a String is given, tries to parse it as a DER- or PEM- encoded parameters. ++ * See also OpenSSL::PKey.read which can parse keys of any kinds. ++ * ++ * The DH.new(size [, generator]) form is an alias of DH.generate. + * +- * === Parameters +- * * _size_ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure. +- * * _generator_ is a small number > 1, typically 2 or 5. +- * * _string_ contains the DER or PEM encoded key. ++ * +string+:: ++ * A String that contains the DER or PEM encoded key. ++ * +size+:: ++ * See DH.generate. ++ * +generator+:: ++ * See DH.generate. + * +- * === Examples +- * DH.new # -> dh +- * DH.new(1024) # -> dh +- * DH.new(1024, 5) # -> dh +- * #Reading DH parameters +- * dh = DH.new(File.read('parameters.pem')) # -> dh, but no public/private key yet +- * dh.generate_key! # -> dh with public and private key ++ * Examples: ++ * # Creating an instance from scratch ++ * dh = DH.new ++ * dh.set_pqg(bn_p, nil, bn_g) ++ * ++ * # Generating a parameters and a key pair ++ * dh = DH.new(2048) # An alias of DH.generate(2048) ++ * ++ * # Reading DH parameters ++ * dh = DH.new(File.read('parameters.pem')) # -> dh, but no public/private key yet ++ * dh.generate_key! # -> dh with public and private key + */ + static VALUE + ossl_dh_initialize(int argc, VALUE *argv, VALUE self) + { + EVP_PKEY *pkey; + DH *dh; +- int g = 2; + BIO *in; +- VALUE arg, gen; ++ VALUE arg; + + GetPKey(self, pkey); +- if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) { +- dh = DH_new(); +- } +- else if (RB_INTEGER_TYPE_P(arg)) { +- if (!NIL_P(gen)) { +- g = NUM2INT(gen); +- } +- dh = dh_generate(NUM2INT(arg), g); ++ /* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */ ++ if (rb_scan_args(argc, argv, "01", &arg) == 0) { ++ dh = DH_new(); ++ if (!dh) ++ ossl_raise(eDHError, "DH_new"); + } + else { + arg = ossl_to_der_if_possible(arg); +@@ -449,33 +358,6 @@ ossl_dh_check_params(VALUE self) + return codes == 0 ? Qtrue : Qfalse; + } + +-/* +- * call-seq: +- * dh.generate_key! -> self +- * +- * Generates a private and public key unless a private key already exists. +- * If this DH instance was generated from public DH parameters (e.g. by +- * encoding the result of DH#public_key), then this method needs to be +- * called first in order to generate the per-session keys before performing +- * the actual key exchange. +- * +- * === Example +- * dh = OpenSSL::PKey::DH.new(2048) +- * public_key = dh.public_key #contains no private/public key yet +- * public_key.generate_key! +- * puts public_key.private? # => true +- */ +-static VALUE +-ossl_dh_generate_key(VALUE self) +-{ +- DH *dh; +- +- GetDH(self, dh); +- if (!DH_generate_key(dh)) +- ossl_raise(eDHError, "Failed to generate key"); +- return self; +-} +- + /* + * Document-method: OpenSSL::PKey::DH#set_pqg + * call-seq: +@@ -540,7 +422,6 @@ Init_ossl_dh(void) + * puts symm_key1 == symm_key2 # => true + */ + cDH = rb_define_class_under(mPKey, "DH", cPKey); +- rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1); + rb_define_method(cDH, "initialize", ossl_dh_initialize, -1); + rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1); + rb_define_method(cDH, "public?", ossl_dh_is_public, 0); +@@ -552,7 +433,6 @@ Init_ossl_dh(void) + rb_define_method(cDH, "to_der", ossl_dh_to_der, 0); + rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0); + rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0); +- rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0); + + DEF_OSSL_PKEY_BN(cDH, dh, p); + DEF_OSSL_PKEY_BN(cDH, dh, q); +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index 9efc3ba68d..279ce1984c 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -4,12 +4,19 @@ + if defined?(OpenSSL) && defined?(OpenSSL::PKey::DH) + + class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase +- NEW_KEYLEN = 256 ++ NEW_KEYLEN = 2048 + +- def test_new ++ def test_new_empty ++ dh = OpenSSL::PKey::DH.new ++ assert_equal nil, dh.p ++ assert_equal nil, dh.priv_key ++ end ++ ++ def test_new_generate ++ # This test is slow + dh = OpenSSL::PKey::DH.new(NEW_KEYLEN) + assert_key(dh) +- end ++ end if ENV["OSSL_TEST_ALL"] + + def test_new_break + assert_nil(OpenSSL::PKey::DH.new(NEW_KEYLEN) { break }) +@@ -80,7 +87,7 @@ def test_key_exchange + end + + def test_dup +- dh = OpenSSL::PKey::DH.new(NEW_KEYLEN) ++ dh = Fixtures.pkey("dh1024") + dh2 = dh.dup + assert_equal dh.to_der, dh2.to_der # params + assert_equal_params dh, dh2 # keys +-- +2.32.0 + + +From ba1d1d68ac2b489691eb3fe2052e77b3e57a372b Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 17 May 2020 20:48:23 +0900 +Subject: [PATCH 3/5] pkey/rsa: use high level EVP interface to generate + parameters and keys + +Implement PKey::RSA.new(size, exponent) and PKey::RSA.generate using +OpenSSL::PKey.generate_key instead of the low level RSA functions. +--- + ext/openssl/lib/openssl/pkey.rb | 30 ++++++++ + ext/openssl/ossl_pkey_rsa.c | 132 ++++---------------------------- + 2 files changed, 46 insertions(+), 116 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 5a3d0ed1ef..3bef06e3b3 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -128,5 +128,35 @@ def to_bn(conversion_form = group.point_conversion_form) + + class RSA + include OpenSSL::Marshal ++ ++ class << self ++ # :call-seq: ++ # RSA.generate(size, exponent = 65537) -> RSA ++ # ++ # Generates an \RSA keypair. ++ # ++ # See also OpenSSL::PKey.generate_key. ++ # ++ # +size+:: ++ # The desired key size in bits. ++ # +exponent+:: ++ # An odd Integer, normally 3, 17, or 65537. ++ def generate(size, exp = 0x10001, &blk) ++ OpenSSL::PKey.generate_key("RSA", { ++ "rsa_keygen_bits" => size, ++ "rsa_keygen_pubexp" => exp, ++ }, &blk) ++ end ++ ++ # Handle RSA.new(size, exponent) form here; new(str) and new() forms ++ # are handled by #initialize ++ def new(*args, &blk) # :nodoc: ++ if args[0].is_a?(Integer) ++ generate(*args, &blk) ++ else ++ super ++ end ++ end ++ end + end + end +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 3c298a2aea..43f82cb29e 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -47,125 +47,28 @@ VALUE eRSAError; + /* + * Private + */ +-struct rsa_blocking_gen_arg { +- RSA *rsa; +- BIGNUM *e; +- int size; +- BN_GENCB *cb; +- int result; +-}; +- +-static void * +-rsa_blocking_gen(void *arg) +-{ +- struct rsa_blocking_gen_arg *gen = (struct rsa_blocking_gen_arg *)arg; +- gen->result = RSA_generate_key_ex(gen->rsa, gen->size, gen->e, gen->cb); +- return 0; +-} +- +-static RSA * +-rsa_generate(int size, unsigned long exp) +-{ +- int i; +- struct ossl_generate_cb_arg cb_arg = { 0 }; +- struct rsa_blocking_gen_arg gen_arg; +- RSA *rsa = RSA_new(); +- BIGNUM *e = BN_new(); +- BN_GENCB *cb = BN_GENCB_new(); +- +- if (!rsa || !e || !cb) { +- RSA_free(rsa); +- BN_free(e); +- BN_GENCB_free(cb); +- ossl_raise(eRSAError, "malloc failure"); +- } +- for (i = 0; i < (int)sizeof(exp) * 8; ++i) { +- if (exp & (1UL << i)) { +- if (BN_set_bit(e, i) == 0) { +- BN_free(e); +- RSA_free(rsa); +- BN_GENCB_free(cb); +- ossl_raise(eRSAError, "BN_set_bit"); +- } +- } +- } +- +- if (rb_block_given_p()) +- cb_arg.yield = 1; +- BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); +- gen_arg.rsa = rsa; +- gen_arg.e = e; +- gen_arg.size = size; +- gen_arg.cb = cb; +- if (cb_arg.yield == 1) { +- /* we cannot release GVL when callback proc is supplied */ +- rsa_blocking_gen(&gen_arg); +- } else { +- /* there's a chance to unblock */ +- rb_thread_call_without_gvl(rsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); +- } +- +- BN_GENCB_free(cb); +- BN_free(e); +- if (!gen_arg.result) { +- RSA_free(rsa); +- if (cb_arg.state) { +- /* must clear OpenSSL error stack */ +- ossl_clear_error(); +- rb_jump_tag(cb_arg.state); +- } +- ossl_raise(eRSAError, "RSA_generate_key_ex"); +- } +- +- return rsa; +-} +- + /* + * call-seq: +- * RSA.generate(size) => RSA instance +- * RSA.generate(size, exponent) => RSA instance ++ * RSA.new -> rsa ++ * RSA.new(encoded_key [, passphrase]) -> rsa ++ * RSA.new(encoded_key) { passphrase } -> rsa ++ * RSA.new(size [, exponent]) -> rsa + * +- * Generates an RSA keypair. _size_ is an integer representing the desired key +- * size. Keys smaller than 1024 should be considered insecure. _exponent_ is +- * an odd number normally 3, 17, or 65537. +- */ +-static VALUE +-ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) +-{ +-/* why does this method exist? why can't initialize take an optional exponent? */ +- EVP_PKEY *pkey; +- RSA *rsa; +- VALUE size, exp; +- VALUE obj; +- +- rb_scan_args(argc, argv, "11", &size, &exp); +- obj = rb_obj_alloc(klass); +- GetPKey(obj, pkey); +- +- rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp)); +- if (!EVP_PKEY_assign_RSA(pkey, rsa)) { +- RSA_free(rsa); +- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); +- } +- return obj; +-} +- +-/* +- * call-seq: +- * RSA.new(size [, exponent]) => RSA instance +- * RSA.new(encoded_key) => RSA instance +- * RSA.new(encoded_key, pass_phrase) => RSA instance ++ * Generates or loads an \RSA keypair. + * +- * Generates or loads an RSA keypair. If an integer _key_size_ is given it +- * represents the desired key size. Keys less than 1024 bits should be +- * considered insecure. ++ * If called without arguments, creates a new instance with no key components ++ * set. They can be set individually by #set_key, #set_factors, and ++ * #set_crt_params. + * +- * A key can instead be loaded from an _encoded_key_ which must be PEM or DER +- * encoded. A _pass_phrase_ can be used to decrypt the key. If none is given +- * OpenSSL will prompt for the pass phrase. ++ * If called with a String, tries to parse as DER or PEM encoding of an \RSA key. ++ * Note that, if _passphrase_ is not specified but the key is encrypted with a ++ * passphrase, \OpenSSL will prompt for it. ++ * See also OpenSSL::PKey.read which can parse keys of any kinds. + * +- * = Examples ++ * If called with a number, generates a new key pair. This form works as an ++ * alias of RSA.generate. + * ++ * Examples: + * OpenSSL::PKey::RSA.new 2048 + * OpenSSL::PKey::RSA.new File.read 'rsa.pem' + * OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my pass phrase' +@@ -179,15 +82,13 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + VALUE arg, pass; + + GetPKey(self, pkey); ++ /* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ + rb_scan_args(argc, argv, "02", &arg, &pass); + if (argc == 0) { + rsa = RSA_new(); + if (!rsa) + ossl_raise(eRSAError, "RSA_new"); + } +- else if (RB_INTEGER_TYPE_P(arg)) { +- rsa = rsa_generate(NUM2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2ULONG(pass)); +- } + else { + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); +@@ -832,7 +733,6 @@ Init_ossl_rsa(void) + */ + cRSA = rb_define_class_under(mPKey, "RSA", cPKey); + +- rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1); + rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1); + rb_define_method(cRSA, "initialize_copy", ossl_rsa_initialize_copy, 1); + +-- +2.32.0 + + +From a6c4a8116c09243c39cc8d1e7ececcd8be0cfaf2 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 17 May 2020 22:14:03 +0900 +Subject: [PATCH 4/5] pkey/dsa: use high level EVP interface to generate + parameters and keys + +Implement PKey::DSA.new(size) and PKey::DSA.generate using +OpenSSL::PKey.generate_parameters and .generate_key instead of the low +level DSA functions. +--- + ext/openssl/lib/openssl/pkey.rb | 30 +++++++ + ext/openssl/ossl_pkey_dsa.c | 140 ++++++-------------------------- + test/openssl/test_pkey_dsa.rb | 23 ++---- + 3 files changed, 64 insertions(+), 129 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 3bef06e3b3..53ee52f98b 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -88,6 +88,36 @@ def new(*args, &blk) # :nodoc: + + class DSA + include OpenSSL::Marshal ++ ++ class << self ++ # :call-seq: ++ # DSA.generate(size) -> dsa ++ # ++ # Creates a new DSA instance by generating a private/public key pair ++ # from scratch. ++ # ++ # See also OpenSSL::PKey.generate_parameters and ++ # OpenSSL::PKey.generate_key. ++ # ++ # +size+:: ++ # The desired key size in bits. ++ def generate(size, &blk) ++ dsaparams = OpenSSL::PKey.generate_parameters("DSA", { ++ "dsa_paramgen_bits" => size, ++ }, &blk) ++ OpenSSL::PKey.generate_key(dsaparams) ++ end ++ ++ # Handle DSA.new(size) form here; new(str) and new() forms ++ # are handled by #initialize ++ def new(*args, &blk) # :nodoc: ++ if args[0].is_a?(Integer) ++ generate(*args, &blk) ++ else ++ super ++ end ++ end ++ end + end + + if defined?(EC) +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index 0e68f7f27f..1c5a8a737e 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -46,126 +46,39 @@ VALUE eDSAError; + /* + * Private + */ +-struct dsa_blocking_gen_arg { +- DSA *dsa; +- int size; +- int *counter; +- unsigned long *h; +- BN_GENCB *cb; +- int result; +-}; +- +-static void * +-dsa_blocking_gen(void *arg) +-{ +- struct dsa_blocking_gen_arg *gen = (struct dsa_blocking_gen_arg *)arg; +- gen->result = DSA_generate_parameters_ex(gen->dsa, gen->size, NULL, 0, +- gen->counter, gen->h, gen->cb); +- return 0; +-} +- +-static DSA * +-dsa_generate(int size) +-{ +- struct ossl_generate_cb_arg cb_arg = { 0 }; +- struct dsa_blocking_gen_arg gen_arg; +- DSA *dsa = DSA_new(); +- BN_GENCB *cb = BN_GENCB_new(); +- int counter; +- unsigned long h; +- +- if (!dsa || !cb) { +- DSA_free(dsa); +- BN_GENCB_free(cb); +- ossl_raise(eDSAError, "malloc failure"); +- } +- +- if (rb_block_given_p()) +- cb_arg.yield = 1; +- BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); +- gen_arg.dsa = dsa; +- gen_arg.size = size; +- gen_arg.counter = &counter; +- gen_arg.h = &h; +- gen_arg.cb = cb; +- if (cb_arg.yield == 1) { +- /* we cannot release GVL when callback proc is supplied */ +- dsa_blocking_gen(&gen_arg); +- } else { +- /* there's a chance to unblock */ +- rb_thread_call_without_gvl(dsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); +- } +- +- BN_GENCB_free(cb); +- if (!gen_arg.result) { +- DSA_free(dsa); +- if (cb_arg.state) { +- /* Clear OpenSSL error queue before re-raising. By the way, the +- * documentation of DSA_generate_parameters_ex() says the error code +- * can be obtained by ERR_get_error(), but the default +- * implementation, dsa_builtin_paramgen() doesn't put any error... */ +- ossl_clear_error(); +- rb_jump_tag(cb_arg.state); +- } +- ossl_raise(eDSAError, "DSA_generate_parameters_ex"); +- } +- +- if (!DSA_generate_key(dsa)) { +- DSA_free(dsa); +- ossl_raise(eDSAError, "DSA_generate_key"); +- } +- +- return dsa; +-} +- +-/* +- * call-seq: +- * DSA.generate(size) -> dsa +- * +- * Creates a new DSA instance by generating a private/public key pair +- * from scratch. +- * +- * === Parameters +- * * _size_ is an integer representing the desired key size. +- * +- */ +-static VALUE +-ossl_dsa_s_generate(VALUE klass, VALUE size) +-{ +- EVP_PKEY *pkey; +- DSA *dsa; +- VALUE obj; +- +- obj = rb_obj_alloc(klass); +- GetPKey(obj, pkey); +- +- dsa = dsa_generate(NUM2INT(size)); +- if (!EVP_PKEY_assign_DSA(pkey, dsa)) { +- DSA_free(dsa); +- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); +- } +- return obj; +-} +- + /* + * call-seq: + * DSA.new -> dsa +- * DSA.new(size) -> dsa + * DSA.new(string [, pass]) -> dsa ++ * DSA.new(size) -> dsa + * + * Creates a new DSA instance by reading an existing key from _string_. + * +- * === Parameters +- * * _size_ is an integer representing the desired key size. +- * * _string_ contains a DER or PEM encoded key. +- * * _pass_ is a string that contains an optional password. ++ * If called without arguments, creates a new instance with no key components ++ * set. They can be set individually by #set_pqg and #set_key. + * +- * === Examples +- * DSA.new -> dsa +- * DSA.new(1024) -> dsa +- * DSA.new(File.read('dsa.pem')) -> dsa +- * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa ++ * If called with a String, tries to parse as DER or PEM encoding of a \DSA key. ++ * See also OpenSSL::PKey.read which can parse keys of any kinds. ++ * ++ * If called with a number, generates random parameters and a key pair. This ++ * form works as an alias of DSA.generate. ++ * ++ * +string+:: ++ * A String that contains a DER or PEM encoded key. ++ * +pass+:: ++ * A String that contains an optional password. ++ * +size+:: ++ * See DSA.generate. + * ++ * Examples: ++ * p OpenSSL::PKey::DSA.new(1024) ++ * #=> # ++ * ++ * p OpenSSL::PKey::DSA.new(File.read('dsa.pem')) ++ * #=> # ++ * ++ * p OpenSSL::PKey::DSA.new(File.read('dsa.pem'), 'mypassword') ++ * #=> # + */ + static VALUE + ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) +@@ -176,15 +89,13 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) + VALUE arg, pass; + + GetPKey(self, pkey); ++ /* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ + rb_scan_args(argc, argv, "02", &arg, &pass); + if (argc == 0) { + dsa = DSA_new(); + if (!dsa) + ossl_raise(eDSAError, "DSA_new"); + } +- else if (argc == 1 && RB_INTEGER_TYPE_P(arg)) { +- dsa = dsa_generate(NUM2INT(arg)); +- } + else { + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); +@@ -553,7 +464,6 @@ Init_ossl_dsa(void) + */ + cDSA = rb_define_class_under(mPKey, "DSA", cPKey); + +- rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1); + rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1); + rb_define_method(cDSA, "initialize_copy", ossl_dsa_initialize_copy, 1); + +diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb +index 4bf8a7b374..85bb6ec0ae 100644 +--- a/test/openssl/test_pkey_dsa.rb ++++ b/test/openssl/test_pkey_dsa.rb +@@ -5,31 +5,26 @@ + + class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase + def test_private +- key = OpenSSL::PKey::DSA.new(256) +- assert(key.private?) ++ key = Fixtures.pkey("dsa1024") ++ assert_equal true, key.private? + key2 = OpenSSL::PKey::DSA.new(key.to_der) +- assert(key2.private?) ++ assert_equal true, key2.private? + key3 = key.public_key +- assert(!key3.private?) ++ assert_equal false, key3.private? + key4 = OpenSSL::PKey::DSA.new(key3.to_der) +- assert(!key4.private?) ++ assert_equal false, key4.private? + end + + def test_new +- key = OpenSSL::PKey::DSA.new 256 ++ key = OpenSSL::PKey::DSA.new(2048) + pem = key.public_key.to_pem + OpenSSL::PKey::DSA.new pem +- if $0 == __FILE__ +- assert_nothing_raised { +- key = OpenSSL::PKey::DSA.new 2048 +- } +- end + end + + def test_new_break +- assert_nil(OpenSSL::PKey::DSA.new(512) { break }) ++ assert_nil(OpenSSL::PKey::DSA.new(2048) { break }) + assert_raise(RuntimeError) do +- OpenSSL::PKey::DSA.new(512) { raise } ++ OpenSSL::PKey::DSA.new(2048) { raise } + end + end + +@@ -184,7 +179,7 @@ def test_read_DSAPublicKey_pem + end + + def test_dup +- key = OpenSSL::PKey::DSA.new(256) ++ key = Fixtures.pkey("dsa1024") + key2 = key.dup + assert_equal key.params, key2.params + key2.set_pqg(key2.p + 1, key2.q, key2.g) +-- +2.32.0 + + +From ba5a3a5c3eabf969f5cd2232b022e440af803b5b Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 5 Apr 2021 00:39:04 +0900 +Subject: [PATCH 5/5] pkey: remove unused ossl_generate_cb_2() helper function + +The previous series of commits re-implemented key generation with the +low level API with the EVP API. The BN_GENCB-based callback function is +no longer used. +--- + ext/openssl/extconf.rb | 3 -- + ext/openssl/openssl_missing.h | 12 ------ + ext/openssl/ossl_pkey.c | 73 +++++++---------------------------- + ext/openssl/ossl_pkey.h | 8 ---- + 4 files changed, 15 insertions(+), 81 deletions(-) + +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index 693e55cd97..b3c6647faf 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -136,9 +136,6 @@ def find_openssl_library + $defs.push("-DHAVE_OPAQUE_OPENSSL") + end + have_func("CRYPTO_lock") || $defs.push("-DHAVE_OPENSSL_110_THREADING_API") +-have_func("BN_GENCB_new") +-have_func("BN_GENCB_free") +-have_func("BN_GENCB_get_arg") + have_func("EVP_MD_CTX_new") + have_func("EVP_MD_CTX_free") + have_func("EVP_MD_CTX_pkey_ctx") +diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h +index 7d218f86f5..e575415f49 100644 +--- a/ext/openssl/openssl_missing.h ++++ b/ext/openssl/openssl_missing.h +@@ -34,18 +34,6 @@ int ossl_EC_curve_nist2nid(const char *); + #endif + + /* added in 1.1.0 */ +-#if !defined(HAVE_BN_GENCB_NEW) +-# define BN_GENCB_new() ((BN_GENCB *)OPENSSL_malloc(sizeof(BN_GENCB))) +-#endif +- +-#if !defined(HAVE_BN_GENCB_FREE) +-# define BN_GENCB_free(cb) OPENSSL_free(cb) +-#endif +- +-#if !defined(HAVE_BN_GENCB_GET_ARG) +-# define BN_GENCB_get_arg(cb) (cb)->arg +-#endif +- + #if !defined(HAVE_EVP_MD_CTX_NEW) + # define EVP_MD_CTX_new EVP_MD_CTX_create + #endif +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index d76f0600d1..f9282b9417 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -17,64 +17,6 @@ VALUE cPKey; + VALUE ePKeyError; + static ID id_private_q; + +-/* +- * callback for generating keys +- */ +-static VALUE +-call_check_ints0(VALUE arg) +-{ +- rb_thread_check_ints(); +- return Qnil; +-} +- +-static void * +-call_check_ints(void *arg) +-{ +- int state; +- rb_protect(call_check_ints0, Qnil, &state); +- return (void *)(VALUE)state; +-} +- +-int +-ossl_generate_cb_2(int p, int n, BN_GENCB *cb) +-{ +- VALUE ary; +- struct ossl_generate_cb_arg *arg; +- int state; +- +- arg = (struct ossl_generate_cb_arg *)BN_GENCB_get_arg(cb); +- if (arg->yield) { +- ary = rb_ary_new2(2); +- rb_ary_store(ary, 0, INT2NUM(p)); +- rb_ary_store(ary, 1, INT2NUM(n)); +- +- /* +- * can be break by raising exception or 'break' +- */ +- rb_protect(rb_yield, ary, &state); +- if (state) { +- arg->state = state; +- return 0; +- } +- } +- if (arg->interrupted) { +- arg->interrupted = 0; +- state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL); +- if (state) { +- arg->state = state; +- return 0; +- } +- } +- return 1; +-} +- +-void +-ossl_generate_cb_stop(void *ptr) +-{ +- struct ossl_generate_cb_arg *arg = (struct ossl_generate_cb_arg *)ptr; +- arg->interrupted = 1; +-} +- + static void + ossl_evp_pkey_free(void *ptr) + { +@@ -257,6 +199,21 @@ pkey_gen_cb_yield(VALUE ctx_v) + return rb_yield_values2(info_num, argv); + } + ++static VALUE ++call_check_ints0(VALUE arg) ++{ ++ rb_thread_check_ints(); ++ return Qnil; ++} ++ ++static void * ++call_check_ints(void *arg) ++{ ++ int state; ++ rb_protect(call_check_ints0, Qnil, &state); ++ return (void *)(VALUE)state; ++} ++ + static int + pkey_gen_cb(EVP_PKEY_CTX *ctx) + { +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index 7dbaed47bc..629c16ae1f 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -35,14 +35,6 @@ extern const rb_data_type_t ossl_evp_pkey_type; + } \ + } while (0) + +-struct ossl_generate_cb_arg { +- int yield; +- int interrupted; +- int state; +-}; +-int ossl_generate_cb_2(int p, int n, BN_GENCB *cb); +-void ossl_generate_cb_stop(void *ptr); +- + VALUE ossl_pkey_new(EVP_PKEY *); + void ossl_pkey_check_public_key(const EVP_PKEY *); + EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE); +-- +2.32.0 + diff --git a/ruby-3.1.0-Use-mmap-for-allocating-heap-pages-in-the-GC.patch b/ruby-3.1.0-Use-mmap-for-allocating-heap-pages-in-the-GC.patch new file mode 100644 index 0000000..512be18 --- /dev/null +++ b/ruby-3.1.0-Use-mmap-for-allocating-heap-pages-in-the-GC.patch @@ -0,0 +1,359 @@ +From bcab8c3cd877506de75f50e0f9ed98827ed554b0 Mon Sep 17 00:00:00 2001 +From: Peter Zhu +Date: Tue, 23 Feb 2021 16:28:56 -0500 +Subject: [PATCH] Use mmap for allocating heap pages + +--- + configure.ac | 16 ++++ + gc.c | 149 ++++++++++++++++++++++++++--------- + test/ruby/test_gc_compact.rb | 41 ++++++---- + 3 files changed, 155 insertions(+), 51 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 2dcebdde9f..b1b190004d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1944,6 +1944,7 @@ AC_CHECK_FUNCS(memmem) + AC_CHECK_FUNCS(mkfifo) + AC_CHECK_FUNCS(mknod) + AC_CHECK_FUNCS(mktime) ++AC_CHECK_FUNCS(mmap) + AC_CHECK_FUNCS(openat) + AC_CHECK_FUNCS(pipe2) + AC_CHECK_FUNCS(poll) +@@ -2666,6 +2667,21 @@ main(int argc, char *argv[]) + rb_cv_fork_with_pthread=yes)]) + test x$rb_cv_fork_with_pthread = xyes || AC_DEFINE(CANNOT_FORK_WITH_PTHREAD) + ]) ++ ++AC_CHECK_HEADERS([sys/user.h]) ++AS_IF([test "x$ac_cv_func_mmap" = xyes], [ ++ AC_CACHE_CHECK([whether PAGE_SIZE is compile-time const], rb_cv_const_page_size, ++ [malloc_headers=`sed -n '/MALLOC_HEADERS_BEGIN/,/MALLOC_HEADERS_END/p' ${srcdir}/gc.c` ++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$malloc_headers ++ typedef char conftest_page[PAGE_SIZE]; ++ ]], [[]])], ++ [rb_cv_const_page_size=yes], ++ [rb_cv_const_page_size=no])]) ++]) ++AS_IF([test "x$rb_cv_const_page_size" = xyes], ++ [AC_DEFINE(HAVE_CONST_PAGE_SIZE, 1)], ++ [AC_DEFINE(HAVE_CONST_PAGE_SIZE, 0)] ++) + } + + : "runtime section" && { +diff --git a/gc.c b/gc.c +index f6acf3e117..6f8e5f242d 100644 +--- a/gc.c ++++ b/gc.c +@@ -32,6 +32,7 @@ + #include + #include + ++/* MALLOC_HEADERS_BEGIN */ + #ifndef HAVE_MALLOC_USABLE_SIZE + # ifdef _WIN32 + # define HAVE_MALLOC_USABLE_SIZE +@@ -54,6 +55,12 @@ + # endif + #endif + ++#if !defined(PAGE_SIZE) && defined(HAVE_SYS_USER_H) ++/* LIST_HEAD conflicts with sys/queue.h on macOS */ ++# include ++#endif ++/* MALLOC_HEADERS_END */ ++ + #ifdef HAVE_SYS_TIME_H + # include + #endif +@@ -821,6 +828,25 @@ enum { + HEAP_PAGE_BITMAP_SIZE = (BITS_SIZE * HEAP_PAGE_BITMAP_LIMIT), + HEAP_PAGE_BITMAP_PLANES = 4 /* RGENGC: mark, unprotected, uncollectible, marking */ + }; ++#define HEAP_PAGE_ALIGN (1 << HEAP_PAGE_ALIGN_LOG) ++#define HEAP_PAGE_SIZE HEAP_PAGE_ALIGN ++ ++#ifdef HAVE_MMAP ++# if HAVE_CONST_PAGE_SIZE ++/* If we have the HEAP_PAGE and it is a constant, then we can directly use it. */ ++static const bool USE_MMAP_ALIGNED_ALLOC = (PAGE_SIZE <= HEAP_PAGE_SIZE); ++# elif defined(PAGE_MAX_SIZE) && (PAGE_MAX_SIZE <= HEAP_PAGE_SIZE) ++/* PAGE_SIZE <= HEAP_PAGE_SIZE */ ++static const bool USE_MMAP_ALIGNED_ALLOC = true; ++# else ++/* Otherwise, fall back to determining if we can use mmap during runtime. */ ++# define USE_MMAP_ALIGNED_ALLOC (use_mmap_aligned_alloc != false) ++ ++static bool use_mmap_aligned_alloc; ++# endif ++#elif !defined(__MINGW32__) && !defined(_WIN32) ++static const bool USE_MMAP_ALIGNED_ALLOC = false; ++#endif + + struct heap_page { + short total_slots; +@@ -1760,14 +1786,14 @@ heap_unlink_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *pag + heap->total_slots -= page->total_slots; + } + +-static void rb_aligned_free(void *ptr); ++static void rb_aligned_free(void *ptr, size_t size); + + static void + heap_page_free(rb_objspace_t *objspace, struct heap_page *page) + { + heap_allocated_pages--; + objspace->profile.total_freed_pages++; +- rb_aligned_free(GET_PAGE_BODY(page->start)); ++ rb_aligned_free(GET_PAGE_BODY(page->start), HEAP_PAGE_SIZE); + free(page); + } + +@@ -1819,7 +1845,7 @@ heap_page_allocate(rb_objspace_t *objspace) + /* assign heap_page entry */ + page = calloc1(sizeof(struct heap_page)); + if (page == 0) { +- rb_aligned_free(page_body); ++ rb_aligned_free(page_body, HEAP_PAGE_SIZE); + rb_memerror(); + } + +@@ -3159,15 +3185,18 @@ Init_heap(void) + { + rb_objspace_t *objspace = &rb_objspace; + +-#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE) +- /* If Ruby's heap pages are not a multiple of the system page size, we +- * cannot use mprotect for the read barrier, so we must disable automatic +- * compaction. */ +- int pagesize; +- pagesize = (int)sysconf(_SC_PAGE_SIZE); +- if ((HEAP_PAGE_SIZE % pagesize) != 0) { +- ruby_enable_autocompact = 0; +- } ++#if defined(HAVE_MMAP) && !HAVE_CONST_PAGE_SIZE && !defined(PAGE_MAX_SIZE) ++ /* Need to determine if we can use mmap at runtime. */ ++# ifdef PAGE_SIZE ++ /* If the PAGE_SIZE macro can be used. */ ++ use_mmap_aligned_alloc = PAGE_SIZE <= HEAP_PAGE_SIZE; ++# elif defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE) ++ /* If we can use sysconf to determine the page size. */ ++ use_mmap_aligned_alloc = sysconf(_SC_PAGE_SIZE) <= HEAP_PAGE_SIZE; ++# else ++ /* Otherwise we can't determine the system page size, so don't use mmap. */ ++ use_mmap_aligned_alloc = FALSE; ++# endif + #endif + + objspace->next_object_id = INT2FIX(OBJ_ID_INITIAL); +@@ -8533,6 +8562,14 @@ gc_start_internal(rb_execution_context_t *ec, VALUE self, VALUE full_mark, VALUE + + /* For now, compact implies full mark / sweep, so ignore other flags */ + if (RTEST(compact)) { ++ /* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for ++ * the read barrier, so we must disable compaction. */ ++#if !defined(__MINGW32__) && !defined(_WIN32) ++ if (!USE_MMAP_ALIGNED_ALLOC) { ++ rb_raise(rb_eNotImpError, "Compaction isn't available on this platform"); ++ } ++#endif ++ + reason |= GPR_FLAG_COMPACT; + } else { + if (!RTEST(full_mark)) reason &= ~GPR_FLAG_FULL_MARK; +@@ -9944,16 +9981,14 @@ gc_disable(rb_execution_context_t *ec, VALUE _) + static VALUE + gc_set_auto_compact(rb_execution_context_t *ec, VALUE _, VALUE v) + { +-#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE) +- /* If Ruby's heap pages are not a multiple of the system page size, we +- * cannot use mprotect for the read barrier, so we must disable automatic +- * compaction. */ +- int pagesize; +- pagesize = (int)sysconf(_SC_PAGE_SIZE); +- if ((HEAP_PAGE_SIZE % pagesize) != 0) { ++ /* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for ++ * the read barrier, so we must disable automatic compaction. */ ++#if !defined(__MINGW32__) && !defined(_WIN32) ++ if (!USE_MMAP_ALIGNED_ALLOC) { + rb_raise(rb_eNotImpError, "Automatic compaction isn't available on this platform"); + } + #endif ++ + ruby_enable_autocompact = RTEST(v); + return v; + } +@@ -10350,22 +10385,54 @@ rb_aligned_malloc(size_t alignment, size_t size) + #elif defined _WIN32 + void *_aligned_malloc(size_t, size_t); + res = _aligned_malloc(size, alignment); +-#elif defined(HAVE_POSIX_MEMALIGN) +- if (posix_memalign(&res, alignment, size) == 0) { +- return res; ++#else ++ if (USE_MMAP_ALIGNED_ALLOC) { ++ GC_ASSERT(alignment % sysconf(_SC_PAGE_SIZE) == 0); ++ ++ char *ptr = mmap(NULL, alignment + size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ++ if (ptr == MAP_FAILED) { ++ return NULL; ++ } ++ ++ char *aligned = ptr + alignment; ++ aligned -= ((VALUE)aligned & (alignment - 1)); ++ GC_ASSERT(aligned > ptr); ++ GC_ASSERT(aligned <= ptr + alignment); ++ ++ size_t start_out_of_range_size = aligned - ptr; ++ GC_ASSERT(start_out_of_range_size % sysconf(_SC_PAGE_SIZE) == 0); ++ if (start_out_of_range_size > 0) { ++ if (munmap(ptr, start_out_of_range_size)) { ++ rb_bug("rb_aligned_malloc: munmap failed for start"); ++ } ++ } ++ ++ size_t end_out_of_range_size = alignment - start_out_of_range_size; ++ GC_ASSERT(end_out_of_range_size % sysconf(_SC_PAGE_SIZE) == 0); ++ if (end_out_of_range_size > 0) { ++ if (munmap(aligned + size, end_out_of_range_size)) { ++ rb_bug("rb_aligned_malloc: munmap failed for end"); ++ } ++ } ++ ++ res = (void *)aligned; + } + else { +- return NULL; ++# if defined(HAVE_POSIX_MEMALIGN) ++ if (posix_memalign(&res, alignment, size) != 0) { ++ return NULL; ++ } ++# elif defined(HAVE_MEMALIGN) ++ res = memalign(alignment, size); ++# else ++ char* aligned; ++ res = malloc(alignment + size + sizeof(void*)); ++ aligned = (char*)res + alignment + sizeof(void*); ++ aligned -= ((VALUE)aligned & (alignment - 1)); ++ ((void**)aligned)[-1] = res; ++ res = (void*)aligned; ++# endif + } +-#elif defined(HAVE_MEMALIGN) +- res = memalign(alignment, size); +-#else +- char* aligned; +- res = malloc(alignment + size + sizeof(void*)); +- aligned = (char*)res + alignment + sizeof(void*); +- aligned -= ((VALUE)aligned & (alignment - 1)); +- ((void**)aligned)[-1] = res; +- res = (void*)aligned; + #endif + + /* alignment must be a power of 2 */ +@@ -10375,16 +10442,26 @@ rb_aligned_malloc(size_t alignment, size_t size) + } + + static void +-rb_aligned_free(void *ptr) ++rb_aligned_free(void *ptr, size_t size) + { + #if defined __MINGW32__ + __mingw_aligned_free(ptr); + #elif defined _WIN32 + _aligned_free(ptr); +-#elif defined(HAVE_MEMALIGN) || defined(HAVE_POSIX_MEMALIGN) +- free(ptr); + #else +- free(((void**)ptr)[-1]); ++ if (USE_MMAP_ALIGNED_ALLOC) { ++ GC_ASSERT(size % sysconf(_SC_PAGE_SIZE) == 0); ++ if (munmap(ptr, size)) { ++ rb_bug("rb_aligned_free: munmap failed"); ++ } ++ } ++ else { ++# if defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_MEMALIGN) ++ free(ptr); ++# else ++ free(((void**)ptr)[-1]); ++# endif ++ } + #endif + } + +diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb +index 4a8cff33f4..f5cab55ba7 100644 +--- a/test/ruby/test_gc_compact.rb ++++ b/test/ruby/test_gc_compact.rb +@@ -4,12 +4,32 @@ + require 'etc' + + class TestGCCompact < Test::Unit::TestCase +- class AutoCompact < Test::Unit::TestCase ++ module SupportsCompact + def setup + skip "autocompact not supported on this platform" unless supports_auto_compact? + super + end + ++ private ++ ++ def supports_auto_compact? ++ return true unless defined?(Etc::SC_PAGE_SIZE) ++ ++ begin ++ return GC::INTERNAL_CONSTANTS[:HEAP_PAGE_SIZE] % Etc.sysconf(Etc::SC_PAGE_SIZE) == 0 ++ rescue NotImplementedError ++ rescue ArgumentError ++ end ++ ++ true ++ end ++ end ++ ++ include SupportsCompact ++ ++ class AutoCompact < Test::Unit::TestCase ++ include SupportsCompact ++ + def test_enable_autocompact + before = GC.auto_compact + GC.auto_compact = true +@@ -59,26 +79,17 @@ def test_implicit_compaction_does_something + ensure + GC.auto_compact = before + end +- +- private +- +- def supports_auto_compact? +- return true unless defined?(Etc::SC_PAGE_SIZE) +- +- begin +- return GC::INTERNAL_CONSTANTS[:HEAP_PAGE_SIZE] % Etc.sysconf(Etc::SC_PAGE_SIZE) == 0 +- rescue NotImplementedError +- rescue ArgumentError +- end +- +- true +- end + end + + def os_page_size + return true unless defined?(Etc::SC_PAGE_SIZE) + end + ++ def setup ++ skip "autocompact not supported on this platform" unless supports_auto_compact? ++ super ++ end ++ + def test_gc_compact_stats + list = [] + +-- +2.30.1 (Apple Git-130) + diff --git a/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch b/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch new file mode 100644 index 0000000..b8f727d --- /dev/null +++ b/ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch @@ -0,0 +1,29 @@ +From a9977ba2f9863e3fb1b2346589ebbca67d80536c Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Sat, 14 Aug 2021 10:08:19 +0900 +Subject: [PATCH] Constified addr2line.c + +--- + addr2line.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/addr2line.c b/addr2line.c +index 8ee4416650d3..fed1a8da84e5 100644 +--- a/addr2line.c ++++ b/addr2line.c +@@ -1138,12 +1138,12 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa + set_uint_value(v, read_uleb128(reader)); + break; + case DW_FORM_ref_addr: +- if (reader->address_size == 4) { ++ if (reader->format == 4) { + set_uint_value(v, read_uint32(&reader->p)); +- } else if (reader->address_size == 8) { ++ } else if (reader->format == 8) { + set_uint_value(v, read_uint64(&reader->p)); + } else { +- fprintf(stderr,"unknown address_size:%d", reader->address_size); ++ fprintf(stderr,"unknown format:%d", reader->format); + abort(); + } + break; diff --git a/ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch b/ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch new file mode 100644 index 0000000..5f3445e --- /dev/null +++ b/ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch @@ -0,0 +1,29 @@ +From b4b5eab2a5fd0e9ac62c01102dd26d0a433c5683 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 18 May 2020 02:17:28 +0900 +Subject: [PATCH] test/openssl/test_digest: do not test constants for legacy + algorithms + +Remove availability test for MD4 and RIPEMD160 as they are considered +legacy and may be missing depending on the compile-time options of +OpenSSL. OpenSSL 3.0 by default disables them. +--- + test/openssl/test_digest.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/openssl/test_digest.rb b/test/openssl/test_digest.rb +index 8d7046e831..84c128c12f 100644 +--- a/test/openssl/test_digest.rb ++++ b/test/openssl/test_digest.rb +@@ -54,7 +54,7 @@ def test_reset + end + + def test_digest_constants +- %w{MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512}.each do |name| ++ %w{MD5 SHA1 SHA224 SHA256 SHA384 SHA512}.each do |name| + assert_not_nil(OpenSSL::Digest.new(name)) + klass = OpenSSL::Digest.const_get(name.tr('-', '_')) + assert_not_nil(klass.new) +-- +2.32.0 + diff --git a/ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch b/ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch new file mode 100644 index 0000000..80b73d2 --- /dev/null +++ b/ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch @@ -0,0 +1,439 @@ +From 9596788bdd2d061bef042485af14262e9fc4020c Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Thu, 13 Aug 2020 23:20:55 +0900 +Subject: [PATCH] test/openssl/test_pkcs12: fix test failures with OpenSSL 3.0 + +OpenSSL's PKCS12_create() by default uses pbewithSHAAnd40BitRC2-CBC for +encryption of the certificates. However, in OpenSSL 3.0, the algorithm +is part of the legacy provider and is not enabled by default. + +Specify another algorithm that is still in the default provider for +these test cases. +--- + test/openssl/test_pkcs12.rb | 297 ++++++++++++++++++------------------ + 1 file changed, 149 insertions(+), 148 deletions(-) + +diff --git a/test/openssl/test_pkcs12.rb b/test/openssl/test_pkcs12.rb +index fdbe753b17..ec676743bc 100644 +--- a/test/openssl/test_pkcs12.rb ++++ b/test/openssl/test_pkcs12.rb +@@ -5,6 +5,9 @@ + + module OpenSSL + class TestPKCS12 < OpenSSL::TestCase ++ DEFAULT_PBE_PKEYS = "PBE-SHA1-3DES" ++ DEFAULT_PBE_CERTS = "PBE-SHA1-3DES" ++ + def setup + super + ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") +@@ -14,47 +17,41 @@ def setup + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] +- @cacert = issue_cert(ca, Fixtures.pkey("rsa2048"), 1, ca_exts, nil, nil) ++ ca_key = Fixtures.pkey("rsa-1") ++ @cacert = issue_cert(ca, ca_key, 1, ca_exts, nil, nil) + + inter_ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Intermediate CA") +- inter_ca_key = OpenSSL::PKey.read <<-_EOS_ +------BEGIN RSA PRIVATE KEY----- +-MIICXAIBAAKBgQDp7hIG0SFMG/VWv1dBUWziAPrNmkMXJgTCAoB7jffzRtyyN04K +-oq/89HAszTMStZoMigQURfokzKsjpUp8OYCAEsBtt9d5zPndWMz/gHN73GrXk3LT +-ZsxEn7Xv5Da+Y9F/Hx2QZUHarV5cdZixq2NbzWGwrToogOQMh2pxN3Z/0wIDAQAB +-AoGBAJysUyx3olpsGzv3OMRJeahASbmsSKTXVLZvoIefxOINosBFpCIhZccAG6UV +-5c/xCvS89xBw8aD15uUfziw3AuT8QPEtHCgfSjeT7aWzBfYswEgOW4XPuWr7EeI9 +-iNHGD6z+hCN/IQr7FiEBgTp6A+i/hffcSdR83fHWKyb4M7TRAkEA+y4BNd668HmC +-G5MPRx25n6LixuBxrNp1umfjEI6UZgEFVpYOg4agNuimN6NqM253kcTR94QNTUs5 +-Kj3EhG1YWwJBAO5rUjiOyCNVX2WUQrOMYK/c1lU7fvrkdygXkvIGkhsPoNRzLPeA +-HGJszKtrKD8bNihWpWNIyqKRHfKVD7yXT+kCQGCAhVCIGTRoypcDghwljHqLnysf +-ci0h5ZdPcIqc7ODfxYhFsJ/Rql5ONgYsT5Ig/+lOQAkjf+TRYM4c2xKx2/8CQBvG +-jv6dy70qDgIUgqzONtlmHeYyFzn9cdBO5sShdVYHvRHjFSMEXsosqK9zvW2UqvuK +-FJx7d3f29gkzynCLJDkCQGQZlEZJC4vWmWJGRKJ24P6MyQn3VsPfErSKOg4lvyM3 +-Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= +------END RSA PRIVATE KEY----- +- _EOS_ +- @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, Fixtures.pkey("rsa2048")) ++ inter_ca_key = Fixtures.pkey("rsa-2") ++ @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, ca_key) + + exts = [ + ["keyUsage","digitalSignature",true], + ["subjectKeyIdentifier","hash",false], + ] + ee = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Ruby PKCS12 Test Certificate") +- @mykey = Fixtures.pkey("rsa1024") ++ @mykey = Fixtures.pkey("rsa-3") + @mycert = issue_cert(ee, @mykey, 3, exts, @inter_cacert, inter_ca_key) + end + +- def test_create ++ def test_create_single_key_single_cert + pkcs12 = OpenSSL::PKCS12.create( + "omg", + "hello", + @mykey, +- @mycert ++ @mycert, ++ nil, ++ DEFAULT_PBE_PKEYS, ++ DEFAULT_PBE_CERTS, + ) +- assert_equal @mycert.to_der, pkcs12.certificate.to_der ++ assert_equal @mycert, pkcs12.certificate + assert_equal @mykey.to_der, pkcs12.key.to_der + assert_nil pkcs12.ca_certs ++ ++ der = pkcs12.to_der ++ decoded = OpenSSL::PKCS12.new(der, "omg") ++ assert_equal @mykey.to_der, decoded.key.to_der ++ assert_equal @mycert, decoded.certificate ++ assert_equal [], Array(decoded.ca_certs) + end + + def test_create_no_pass +@@ -62,14 +59,17 @@ def test_create_no_pass + nil, + "hello", + @mykey, +- @mycert ++ @mycert, ++ nil, ++ DEFAULT_PBE_PKEYS, ++ DEFAULT_PBE_CERTS, + ) +- assert_equal @mycert.to_der, pkcs12.certificate.to_der ++ assert_equal @mycert, pkcs12.certificate + assert_equal @mykey.to_der, pkcs12.key.to_der + assert_nil pkcs12.ca_certs + + decoded = OpenSSL::PKCS12.new(pkcs12.to_der) +- assert_cert @mycert, decoded.certificate ++ assert_equal @mycert, decoded.certificate + end + + def test_create_with_chain +@@ -80,7 +80,9 @@ def test_create_with_chain + "hello", + @mykey, + @mycert, +- chain ++ chain, ++ DEFAULT_PBE_PKEYS, ++ DEFAULT_PBE_CERTS, + ) + assert_equal chain, pkcs12.ca_certs + end +@@ -95,14 +97,16 @@ def test_create_with_chain_decode + "hello", + @mykey, + @mycert, +- chain ++ chain, ++ DEFAULT_PBE_PKEYS, ++ DEFAULT_PBE_CERTS, + ) + + decoded = OpenSSL::PKCS12.new(pkcs12.to_der, passwd) + assert_equal chain.size, decoded.ca_certs.size +- assert_include_cert @cacert, decoded.ca_certs +- assert_include_cert @inter_cacert, decoded.ca_certs +- assert_cert @mycert, decoded.certificate ++ assert_include decoded.ca_certs, @cacert ++ assert_include decoded.ca_certs, @inter_cacert ++ assert_equal @mycert, decoded.certificate + assert_equal @mykey.to_der, decoded.key.to_der + end + +@@ -126,8 +130,8 @@ def test_create_with_itr + @mykey, + @mycert, + [], +- nil, +- nil, ++ DEFAULT_PBE_PKEYS, ++ DEFAULT_PBE_CERTS, + 2048 + ) + +@@ -138,8 +142,8 @@ def test_create_with_itr + @mykey, + @mycert, + [], +- nil, +- nil, ++ DEFAULT_PBE_PKEYS, ++ DEFAULT_PBE_CERTS, + "omg" + ) + end +@@ -152,7 +156,8 @@ def test_create_with_mac_itr + @mykey, + @mycert, + [], +- nil, ++ DEFAULT_PBE_PKEYS, ++ DEFAULT_PBE_CERTS, + nil, + nil, + 2048 +@@ -165,148 +170,144 @@ def test_create_with_mac_itr + @mykey, + @mycert, + [], +- nil, +- nil, ++ DEFAULT_PBE_PKEYS, ++ DEFAULT_PBE_CERTS, + nil, + "omg" + ) + end + end + +- def test_new_with_one_key_and_one_cert +- # generated with: +- # openssl version #=> OpenSSL 1.0.2h 3 May 2016 +- # openssl pkcs12 -in <@mycert> -inkey -export -out +- str = <<~EOF.unpack("m").first +-MIIGQQIBAzCCBgcGCSqGSIb3DQEHAaCCBfgEggX0MIIF8DCCAu8GCSqGSIb3DQEH +-BqCCAuAwggLcAgEAMIIC1QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIeZPM +-Rh6KiXgCAggAgIICqL6O+LCZmBzdIg6mozPF3FpY0hVbWHvTNMiDHieW3CrAanhN +-YCH2/wHqH8WpFpEWwF0qEEXAWjHsIlYB4Cfqo6b7XpuZe5eVESsjNTOTMF1JCUJj +-A6iNefXmCFLync1JK5LUodRDhTlKLU1WPK20X9X4vuEwHn8wt5RUb8P0E+Xh6rpS +-XC4LkZKT45zF3cJa/n5+dW65ohVGNVnF9D1bCNEKHMOllK1V9omutQ9slW88hpga +-LGiFsJoFOb/ESGb78KO+bd6zbX1MdKdBV+WD6t1uF/cgU65y+2A4nXs1urda+MJ7 +-7iVqiB7Vnc9cANTbAkTSGNyoUDVM/NZde782/8IvddLAzUZ2EftoRDke6PvuBOVL +-ljBhNWmdamrtBqzuzVZCRdWq44KZkF2Xoc9asepwIkdVmntzQF7f1Z+Ta5yg6HFp +-xnr7CuM+MlHEShXkMgYtHnwAq10fDMSXIvjhi/AA5XUAusDO3D+hbtcRDcJ4uUes +-dm5dhQE2qJ02Ysn4aH3o1F3RYNOzrxejHJwl0D2TCE8Ww2X342xib57+z9u03ufj +-jswhiMKxy67f1LhUMq3XrT3uV6kCVXk/KUOUPcXPlPVNA5JmZeFhMp6GrtB5xJJ9 +-wwBZD8UL5A2U2Mxi2OZsdUBv8eo3jnjZ284aFpt+mCjIHrLW5O0jwY8OCwSlYUoY +-IY00wlabX0s82kBcIQNZbC1RSV2267ro/7A0MClc8YQ/zWN0FKY6apgtUkHJI1cL +-1dc77mhnjETjwW94iLMDFy4zQfVu7IfCBqOBzygRNnqqUG66UhTs1xFnWM0mWXl/ +-Zh9+AMpbRLIPaKCktIjl5juzzm+KEgkhD+707XRCFIGUYGP5bSHzGaz8PK9hj0u1 +-E2SpZHUvYOcawmxtA7pmpSxl5uQjMIIC+QYJKoZIhvcNAQcBoIIC6gSCAuYwggLi +-MIIC3gYLKoZIhvcNAQwKAQKgggKmMIICojAcBgoqhkiG9w0BDAEDMA4ECKB338m8 +-qSzHAgIIAASCAoACFhJeqA3xx+s1qIH6udNQYY5hAL6oz7SXoGwFhDiceSyJjmAD +-Dby9XWM0bPl1Gj5nqdsuI/lAM++fJeoETk+rxw8q6Ofk2zUaRRE39qgpwBwSk44o +-0SAFJ6bzHpc5CFh6sZmDaUX5Lm9GtjnGFmmsPTSJT5an5JuJ9WczGBEd0nSBQhJq +-xHbTGZiN8i3SXcIH531Sub+CBIFWy5lyCKgDYh/kgJFGQAaWUOjLI+7dCEESonXn +-F3Jh2uPbnDF9MGJyAFoNgWFhgSpi1cf6AUi87GY4Oyur88ddJ1o0D0Kz2uw8/bpG +-s3O4PYnIW5naZ8mozzbnYByEFk7PoTwM7VhoFBfYNtBoAI8+hBnPY/Y71YUojEXf +-SeX6QbtkIANfzS1XuFNKElShC3DPQIHpKzaatEsfxHfP+8VOav6zcn4mioao7NHA +-x7Dp6R1enFGoQOq4UNjBT8YjnkG5vW8zQHW2dAHLTJBq6x2Fzm/4Pjo/8vM1FiGl +-BQdW5vfDeJ/l6NgQm3xR9ka2E2HaDqIcj1zWbN8jy/bHPFJYuF/HH8MBV/ngMIXE +-vFEW/ToYv8eif0+EpUtzBsCKD4a7qYYYh87RmEVoQU96q6m+UbhpD2WztYfAPkfo +-OSL9j2QHhVczhL7OAgqNeM95pOsjA9YMe7exTeqK31LYnTX8oH8WJD1xGbRSJYgu +-SY6PQbumcJkc/TFPn0GeVUpiDdf83SeG50lo/i7UKQi2l1hi5Y51fQhnBnyMr68D +-llSZEvSWqfDxBJkBpeg6PIYvkTpEwKRJpVQoM3uYvdqVSSnW6rydqIb+snfOrlhd +-f+xCtq9xr+kHeTSqLIDRRAnMfgFRhY3IBlj6MSUwIwYJKoZIhvcNAQkVMRYEFBdb +-8XGWehZ6oPj56Pf/uId46M9AMDEwITAJBgUrDgMCGgUABBRvSCB04/f8f13pp2PF +-vyl2WuMdEwQIMWFFphPkIUICAggA +- EOF +- p12 = OpenSSL::PKCS12.new(str, "abc123") +- +- assert_equal @mykey.to_der, p12.key.to_der +- assert_equal @mycert.subject.to_der, p12.certificate.subject.to_der +- assert_equal [], Array(p12.ca_certs) +- end +- + def test_new_with_no_keys + # generated with: +- # openssl pkcs12 -in <@mycert> -nokeys -export -out ++ # openssl pkcs12 -certpbe PBE-SHA1-3DES -in <@mycert> -nokeys -export + str = <<~EOF.unpack("m").first +-MIIDHAIBAzCCAuIGCSqGSIb3DQEHAaCCAtMEggLPMIICyzCCAscGCSqGSIb3DQEH +-BqCCArgwggK0AgEAMIICrQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIX4+W +-irqwH40CAggAgIICgOaCyo+5+6IOVoGCCL80c50bkkzAwqdXxvkKExJSdcJz2uMU +-0gRrKnZEjL5wrUsN8RwZu8DvgQTEhNEkKsUgM7AWainmN/EnwohIdHZAHpm6WD67 +-I9kLGp0/DHrqZrV9P2dLfhXLUSQE8PI0tqZPZ8UEABhizkViw4eISTkrOUN7pGbN +-Qtx/oqgitXDuX2polbxYYDwt9vfHZhykHoKgew26SeJyZfeMs/WZ6olEI4cQUAFr +-mvYGuC1AxEGTo9ERmU8Pm16j9Hr9PFk50WYe+rnk9oX3wJogQ7XUWS5kYf7XRycd +-NDkNiwV/ts94bbuaGZp1YA6I48FXpIc8b5fX7t9tY0umGaWy0bARe1L7o0Y89EPe +-lMg25rOM7j3uPtFG8whbSfdETSy57UxzzTcJ6UwexeaK6wb2jqEmj5AOoPLWeaX0 +-LyOAszR3v7OPAcjIDYZGdrbb3MZ2f2vo2pdQfu9698BrWhXuM7Odh73RLhJVreNI +-aezNOAtPyBlvGiBQBGTzRIYHSLL5Y5aVj2vWLAa7hjm5qTL5C5mFdDIo6TkEMr6I +-OsexNQofEGs19kr8nARXDlcbEimk2VsPj4efQC2CEXZNzURsKca82pa62MJ8WosB +-DTFd8X06zZZ4nED50vLopZvyW4fyW60lELwOyThAdG8UchoAaz2baqP0K4de44yM +-Y5/yPFDu4+GoimipJfbiYviRwbzkBxYW8+958ILh0RtagLbvIGxbpaym9PqGjOzx +-ShNXjLK2aAFZsEizQ8kd09quJHU/ogq2cUXdqqhmOqPnUWrJVi/VCoRB3Pv1/lE4 +-mrUgr2YZ11rYvBw6g5XvNvFcSc53OKyV7SLn0dwwMTAhMAkGBSsOAwIaBQAEFEWP +-1WRQykaoD4uJCpTx/wv0SLLBBAiDKI26LJK7xgICCAA= ++MIIGJAIBAzCCBeoGCSqGSIb3DQEHAaCCBdsEggXXMIIF0zCCBc8GCSqGSIb3 ++DQEHBqCCBcAwggW8AgEAMIIFtQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQMw ++DgQIjv5c3OHvnBgCAggAgIIFiMJa8Z/w7errRvCQPXh9dGQz3eJaFq3S2gXD ++rh6oiwsgIRJZvYAWgU6ll9NV7N5SgvS2DDNVuc3tsP8TPWjp+bIxzS9qmGUV ++kYWuURWLMKhpF12ZRDab8jcIwBgKoSGiDJk8xHjx6L613/XcRM6ln3VeQK+C ++hlW5kXniNAUAgTft25Fn61Xa8xnhmsz/fk1ycGnyGjKCnr7Mgy7KV0C1vs23 ++18n8+b1ktDWLZPYgpmXuMFVh0o+HJTV3O86mkIhJonMcnOMgKZ+i8KeXaocN ++JQlAPBG4+HOip7FbQT/h6reXv8/J+hgjLfqAb5aV3m03rUX9mXx66nR1tQU0 ++Jq+XPfDh5+V4akIczLlMyyo/xZjI1/qupcMjr+giOGnGd8BA3cuXW+ueLQiA ++PpTp+DQLVHRfz9XTZbyqOReNEtEXvO9gOlKSEY5lp65ItXVEs2Oqyf9PfU9y ++DUltN6fCMilwPyyrsIBKXCu2ZLM5h65KVCXAYEX9lNqj9zrQ7vTqvCNN8RhS ++ScYouTX2Eqa4Z+gTZWLHa8RCQFoyP6hd+97/Tg2Gv2UTH0myQxIVcnpdi1wy ++cqb+er7tyKbcO96uSlUjpj/JvjlodtjJcX+oinEqGb/caj4UepbBwiG3vv70 ++63bS3jTsOLNjDRsR9if3LxIhLa6DW8zOJiGC+EvMD1o4dzHcGVpQ/pZWCHZC +++YiNJpQOBApiZluE+UZ0m3XrtHFQYk7xblTrh+FJF91wBsok0rZXLAKd8m4p ++OJsc7quCq3cuHRRTzJQ4nSe01uqbwGDAYwLvi6VWy3svU5qa05eDRmgzEFTG ++e84Gp/1LQCtpQFr4txkjFchO2whWS80KoQKqmLPyGm1D9Lv53Q4ZsKMgNihs ++rEepuaOZMKHl4yMAYFoOXZCAYzfbhN6b2phcFAHjMUHUw9e3F0QuDk9D0tsr ++riYTrkocqlOKfK4QTomx27O0ON2J6f1rtEojGgfl9RNykN7iKGzjS3914QjW ++W6gGiZejxHsDPEAa4gUp0WiSUSXtD5WJgoyAzLydR2dKWsQ4WlaUXi01CuGy +++xvncSn2nO3bbot8VD5H6XU1CjREVtnIfbeRYO/uofyLUP3olK5RqN6ne6Xo ++eXnJ/bjYphA8NGuuuvuW1SCITmINkZDLC9cGlER9+K65RR/DR3TigkexXMeN ++aJ70ivZYAl0OuhZt3TGIlAzS64TIoyORe3z7Ta1Pp9PZQarYJpF9BBIZIFor ++757PHHuQKRuugiRkp8B7v4eq1BQ+VeAxCKpyZ7XrgEtbY/AWDiaKcGPKPjc3 ++AqQraVeQm7kMBT163wFmZArCphzkDOI3bz2oEO8YArMgLq2Vto9jAZlqKyWr ++pi2bSJxuoP1aoD58CHcWMrf8/j1LVdQhKgHQXSik2ID0H2Wc/XnglhzlVFuJ ++JsNIW/EGJlZh/5WDez9U0bXqnBlu3uasPEOezdoKlcCmQlmTO5+uLHYLEtNA ++EH9MtnGZebi9XS5meTuS6z5LILt8O9IHZxmT3JRPHYj287FEzotlLdcJ4Ee5 ++enW41UHjLrfv4OaITO1hVuoLRGdzjESx/fHMWmxroZ1nVClxECOdT42zvIYJ ++J3xBZ0gppzQ5fjoYiKjJpxTflRxUuxshk3ih6VUoKtqj/W18tBQ3g5SOlkgT ++yCW8r74yZlfYmNrPyDMUQYpLUPWj2n71GF0KyPfTU5yOatRgvheh262w5BG3 ++omFY7mb3tCv8/U2jdMIoukRKacpZiagofz3SxojOJq52cHnCri+gTHBMX0cO ++j58ygfntHWRzst0pV7Ze2X3fdCAJ4DokH6bNJNthcgmolFJ/y3V1tJjgsdtQ ++7Pjn/vE6xUV0HXE2x4yoVYNirbAMIvkN/X+atxrN0dA4AchN+zGp8TAxMCEw ++CQYFKw4DAhoFAAQUQ+6XXkyhf6uYgtbibILN2IjKnOAECLiqoY45MPCrAgII ++AA== + EOF + p12 = OpenSSL::PKCS12.new(str, "abc123") + + assert_equal nil, p12.key + assert_equal nil, p12.certificate + assert_equal 1, p12.ca_certs.size +- assert_equal @mycert.subject.to_der, p12.ca_certs[0].subject.to_der ++ assert_equal @mycert.subject, p12.ca_certs[0].subject + end + + def test_new_with_no_certs + # generated with: +- # openssl pkcs12 -inkey -nocerts -export -out ++ # openssl pkcs12 -inkey fixtures/openssl/pkey/rsa-1.pem -nocerts -export + str = <<~EOF.unpack("m").first +-MIIDJwIBAzCCAu0GCSqGSIb3DQEHAaCCAt4EggLaMIIC1jCCAtIGCSqGSIb3DQEH +-AaCCAsMEggK/MIICuzCCArcGCyqGSIb3DQEMCgECoIICpjCCAqIwHAYKKoZIhvcN +-AQwBAzAOBAg6AaYnJs84SwICCAAEggKAQzZH+fWSpcQYD1J7PsGSune85A++fLCQ +-V7tacp2iv95GJkxwYmfTP176pJdgs00mceB9UJ/u9EX5nD0djdjjQjwo6sgKjY0q +-cpVhZw8CMxw7kBD2dhtui0zT8z5hy03LePxsjEKsGiSbeVeeGbSfw/I6AAYbv+Uh +-O/YPBGumeHj/D2WKnfsHJLQ9GAV3H6dv5VKYNxjciK7f/JEyZCuUQGIN64QFHDhJ +-7fzLqd/ul3FZzJZO6a+dwvcgux09SKVXDRSeFmRCEX4b486iWhJJVspCo9P2KNne +-ORrpybr3ZSwxyoICmjyo8gj0OSnEfdx9790Ej1takPqSA1wIdSdBLekbZqB0RBQg +-DEuPOsXNo3QFi8ji1vu0WBRJZZSNC2hr5NL6lNR+DKxG8yzDll2j4W4BBIp22mAE +-7QRX7kVxu17QJXQhOUac4Dd1qXmzebP8t6xkAxD9L7BWEN5OdiXWwSWGjVjMBneX +-nYObi/3UT/aVc5WHMHK2BhCI1bwH51E6yZh06d5m0TQpYGUTWDJdWGBSrp3A+8jN +-N2PMQkWBFrXP3smHoTEN4oZC4FWiPsIEyAkQsfKRhcV9lGKl2Xgq54ROTFLnwKoj +-Z3zJScnq9qmNzvVZSMmDLkjLyDq0pxRxGKBvgouKkWY7VFFIwwBIJM39iDJ5NbBY +-i1AQFTRsRSsZrNVPasCXrIq7bhMoJZb/YZOGBLNyJVqKUoYXhtwsajzSq54VlWft +-JxsPayEd4Vi6O9EU1ahnj6qFEZiKFzsicgK2J1Rb8cYagrp0XWjHW0SBn5GVUWCg +-GUokSFG/0JTdeYTo/sQuG4qNgJkOolRjpeI48Fciq5VUWLvVdKioXzAxMCEwCQYF +-Kw4DAhoFAAQUYAuwVtGD1TdgbFK4Yal2XBgwUR4ECEawsN3rNaa6AgIIAA== ++MIIJ7wIBAzCCCbUGCSqGSIb3DQEHAaCCCaYEggmiMIIJnjCCCZoGCSqGSIb3 ++DQEHAaCCCYsEggmHMIIJgzCCCX8GCyqGSIb3DQEMCgECoIIJbjCCCWowHAYK ++KoZIhvcNAQwBAzAOBAjX5nN8jyRKwQICCAAEgglIBIRLHfiY1mNHpl3FdX6+ ++72L+ZOVXnlZ1MY9HSeg0RMkCJcm0mJ2UD7INUOGXvwpK9fr6WJUZM1IqTihQ ++1dM0crRC2m23aP7KtAlXh2DYD3otseDtwoN/NE19RsiJzeIiy5TSW1d47weU +++D4Ig/9FYVFPTDgMzdCxXujhvO/MTbZIjqtcS+IOyF+91KkXrHkfkGjZC7KS ++WRmYw9BBuIPQEewdTI35sAJcxT8rK7JIiL/9mewbSE+Z28Wq1WXwmjL3oZm9 ++lw6+f515b197GYEGomr6LQqJJamSYpwQbTGHonku6Tf3ylB4NLFqOnRCKE4K ++zRSSYIqJBlKHmQ4pDm5awoupHYxMZLZKZvXNYyYN3kV8r1iiNVlY7KBR4CsX ++rqUkXehRmcPnuqEMW8aOpuYe/HWf8PYI93oiDZjcEZMwW2IZFFrgBbqUeNCM ++CQTkjAYxi5FyoaoTnHrj/aRtdLOg1xIJe4KKcmOXAVMmVM9QEPNfUwiXJrE7 ++n42gl4NyzcZpxqwWBT++9TnQGZ/lEpwR6dzkZwICNQLdQ+elsdT7mumywP+1 ++WaFqg9kpurimaiBu515vJNp9Iqv1Nmke6R8Lk6WVRKPg4Akw0fkuy6HS+LyN ++ofdCfVUkPGN6zkjAxGZP9ZBwvXUbLRC5W3N5qZuAy5WcsS75z+oVeX9ePV63 ++cue23sClu8JSJcw3HFgPaAE4sfkQ4MoihPY5kezgT7F7Lw/j86S0ebrDNp4N ++Y685ec81NRHJ80CAM55f3kGCOEhoifD4VZrvr1TdHZY9Gm3b1RYaJCit2huF ++nlOfzeimdcv/tkjb6UsbpXx3JKkF2NFFip0yEBERRCdWRYMUpBRcl3ad6XHy ++w0pVTgIjTxGlbbtOCi3siqMOK0GNt6UgjoEFc1xqjsgLwU0Ta2quRu7RFPGM ++GoEwoC6VH23p9Hr4uTFOL0uHfkKWKunNN+7YPi6LT6IKmTQwrp+fTO61N6Xh ++KlqTpwESKsIJB2iMnc8wBkjXJtmG/e2n5oTqfhICIrxYmEb7zKDyK3eqeTj3 ++FhQh2t7cUIiqcT52AckUqniPmlE6hf82yBjhaQUPfi/ExTBtTDSmFfRPUzq+ ++Rlla4OHllPRzUXJExyansgCxZbPqlw46AtygSWRGcWoYAKUKwwoYjerqIV5g ++JoZICV9BOU9TXco1dHXZQTs/nnTwoRmYiL/Ly5XpvUAnQOhYeCPjBeFnPSBR ++R/hRNqrDH2MOV57v5KQIH2+mvy26tRG+tVGHmLMaOJeQkjLdxx+az8RfXIrH ++7hpAsoBb+g9jUDY1mUVavPk1T45GMpQH8u3kkzRvChfOst6533GyIZhE7FhN ++KanC6ACabVFDUs6P9pK9RPQMp1qJfpA0XJFx5TCbVbPkvnkZd8K5Tl/tzNM1 ++n32eRao4MKr9KDwoDL93S1yJgYTlYjy1XW/ewdedtX+B4koAoz/wSXDYO+GQ ++Zu6ZSpKSEHTRPhchsJ4oICvpriVaJkn0/Z7H3YjNMB9U5RR9+GiIg1wY1Oa1 ++S3WfuwrrI6eqfbQwj6PDNu3IKy6srEgvJwaofQALNBPSYWbauM2brc8qsD+t ++n8jC/aD1aMcy00+9t3H/RVCjEOb3yKfUpAldIkEA2NTTnZpoDQDXeNYU2F/W ++yhmFjJy8A0O4QOk2xnZK9kcxSRs0v8vI8HivvgWENoVPscsDC4742SSIe6SL ++f/T08reIX11f0K70rMtLhtFMQdHdYOTNl6JzhkHPLr/f9MEZsBEQx52depnF ++ARb3gXGbCt7BAi0OeCEBSbLr2yWuW4r55N0wRZSOBtgqgjsiHP7CDQSkbL6p ++FPlQS1do9gBSHiNYvsmN1LN5bG+mhcVb0UjZub4mL0EqGadjDfDdRJmWqlX0 ++r5dyMcOWQVy4O2cPqYFlcP9lk8buc5otcyVI2isrAFdlvBK29oK6jc52Aq5Q ++0b2ESDlgX8WRgiOPPxK8dySKEeuIwngCtJyNTecP9Ug06TDsu0znZGCXJ+3P ++8JOpykgA8EQdOZOYHbo76ZfB2SkklI5KeRA5IBjGs9G3TZ4PHLy2DIwsbWzS ++H1g01o1x264nx1cJ+eEgUN/KIiGFIib42RS8Af4D5e+Vj54Rt3axq+ag3kI+ ++53p8uotyu+SpvvXUP7Kv4xpQ/L6k41VM0rfrd9+DrlDVvSfxP2uh6I1TKF7A ++CT5n8zguMbng4PGjxvyPBM5k62t6hN5fuw6Af0aZFexh+IjB/5wFQ6onSz23 ++fBzMW4St7RgSs8fDg3lrM+5rwXiey1jxY1ddaxOoUsWRMvvdd7rZxRZQoN5v ++AcI5iMkK/vvpQgC/sfzhtXtrJ2XOPZ+GVgi7VcuDLKSkdFMcPbGzO8SdxUnS ++SLV5XTKqKND+Lrfx7DAoKi5wbDFHu5496/MHK5qP4tBe6sJ5bZc+KDJIH46e ++wTV1oWtB5tV4q46hOb5WRcn/Wjz3HSKaGZgx5QbK1MfKTzD5CTUn+ArMockX ++2wJhPnFK85U4rgv8iBuh9bRjyw+YaKf7Z3loXRiE1eRG6RzuPF0ZecFiDumk ++AC/VUXynJhzePBLqzrQj0exanACdullN+pSfHiRWBxR2VFUkjoFP5X45GK3z ++OstSH6FOkMVU4afqEmjsIwozDFIyin5EyWTtdhJe3szdJSGY23Tut+9hUatx ++9FDFLESOd8z3tyQSNiLk/Hib+e/lbjxqbXBG/p/oyvP3N999PLUPtpKqtYkV ++H0+18sNh9CVfojiJl44fzxe8yCnuefBjut2PxEN0EFRBPv9P2wWlmOxkPKUq ++NrCJP0rDj5aONLrNZPrR8bZNdIShkZ/rKkoTuA0WMZ+xUlDRxAupdMkWAlrz ++8IcwNcdDjPnkGObpN5Ctm3vK7UGSBmPeNqkXOYf3QTJ9gStJEd0F6+DzTN5C ++KGt1IyuGwZqL2Yk51FDIIkr9ykEnBMaA39LS7GFHEDNGlW+fKC7AzA0zfoOr ++fXZlHMBuqHtXqk3zrsHRqGGoocigg4ctrhD1UREYKj+eIj1TBiRdf7c6+COf ++NIOmej8pX3FmZ4ui+dDA8r2ctgsWHrb4A6iiH+v1DRA61GtoaA/tNRggewXW ++VXCZCGWyyTuyHGOqq5ozrv5MlzZLWD/KV/uDsAWmy20RAed1C4AzcXlpX25O ++M4SNl47g5VRNJRtMqokc8j6TjZrzMDEwITAJBgUrDgMCGgUABBRrkIRuS5qg ++BC8fv38mue8LZVcbHQQIUNrWKEnskCoCAggA + EOF + p12 = OpenSSL::PKCS12.new(str, "abc123") + +- assert_equal @mykey.to_der, p12.key.to_der ++ assert_equal Fixtures.pkey("rsa-1").to_der, p12.key.to_der + assert_equal nil, p12.certificate + assert_equal [], Array(p12.ca_certs) + end + + def test_dup +- p12 = OpenSSL::PKCS12.create("pass", "name", @mykey, @mycert) ++ p12 = OpenSSL::PKCS12.create( ++ "pass", ++ "name", ++ @mykey, ++ @mycert, ++ nil, ++ DEFAULT_PBE_PKEYS, ++ DEFAULT_PBE_CERTS, ++ ) + assert_equal p12.to_der, p12.dup.to_der + end +- +- private +- def assert_cert expected, actual +- [ +- :subject, +- :issuer, +- :serial, +- :not_before, +- :not_after, +- ].each do |attribute| +- assert_equal expected.send(attribute), actual.send(attribute) +- end +- assert_equal expected.to_der, actual.to_der +- end +- +- def assert_include_cert cert, ary +- der = cert.to_der +- ary.each do |candidate| +- if candidate.to_der == der +- return true +- end +- end +- false +- end + end + end + +-- +2.32.0 + diff --git a/ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch b/ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch new file mode 100644 index 0000000..ac45842 --- /dev/null +++ b/ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch @@ -0,0 +1,67 @@ +From 10d2216b2f35a31777a099d9f765b0b6ea34a63e Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 18 May 2020 02:35:35 +0900 +Subject: [PATCH] test/openssl/test_pkey: use EC keys for + PKey.generate_parameters tests + +OpenSSL 3.0 refuses to generate DSA parameters shorter than 2048 bits, +but generating 2048 bits parameters takes very long time. Let's use EC +in these test cases instead. +--- + test/openssl/test_pkey.rb | 27 +++++++++++---------------- + 1 file changed, 11 insertions(+), 16 deletions(-) + +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index 3630458b3c..88a6e04581 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -27,20 +27,16 @@ def test_generic_oid_inspect + end + + def test_s_generate_parameters +- # 512 is non-default; 1024 is used if 'dsa_paramgen_bits' is not specified +- # with OpenSSL 1.1.0. +- pkey = OpenSSL::PKey.generate_parameters("DSA", { +- "dsa_paramgen_bits" => 512, +- "dsa_paramgen_q_bits" => 256, ++ pkey = OpenSSL::PKey.generate_parameters("EC", { ++ "ec_paramgen_curve" => "secp384r1", + }) +- assert_instance_of OpenSSL::PKey::DSA, pkey +- assert_equal 512, pkey.p.num_bits +- assert_equal 256, pkey.q.num_bits +- assert_equal nil, pkey.priv_key ++ assert_instance_of OpenSSL::PKey::EC, pkey ++ assert_equal "secp384r1", pkey.group.curve_name ++ assert_equal nil, pkey.private_key + + # Invalid options are checked + assert_raise(OpenSSL::PKey::PKeyError) { +- OpenSSL::PKey.generate_parameters("DSA", "invalid" => "option") ++ OpenSSL::PKey.generate_parameters("EC", "invalid" => "option") + } + + # Parameter generation callback is called +@@ -59,14 +55,13 @@ def test_s_generate_key + # DSA key pair cannot be generated without parameters + OpenSSL::PKey.generate_key("DSA") + } +- pkey_params = OpenSSL::PKey.generate_parameters("DSA", { +- "dsa_paramgen_bits" => 512, +- "dsa_paramgen_q_bits" => 256, ++ pkey_params = OpenSSL::PKey.generate_parameters("EC", { ++ "ec_paramgen_curve" => "secp384r1", + }) + pkey = OpenSSL::PKey.generate_key(pkey_params) +- assert_instance_of OpenSSL::PKey::DSA, pkey +- assert_equal 512, pkey.p.num_bits +- assert_not_equal nil, pkey.priv_key ++ assert_instance_of OpenSSL::PKey::EC, pkey ++ assert_equal "secp384r1", pkey.group.curve_name ++ assert_not_equal nil, pkey.private_key + end + + def test_hmac_sign_verify +-- +2.32.0 + diff --git a/ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch b/ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch new file mode 100644 index 0000000..c9421bc --- /dev/null +++ b/ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch @@ -0,0 +1,31 @@ +From 05fd14aea7eff2a6911a6f529f1237276482c6e7 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 10 Jul 2020 13:56:38 +0900 +Subject: [PATCH] test/openssl/test_ssl: relax regex to match OpenSSL's error + message + +OpenSSL 3.0 slightly changed the error message for a certificate +verification failure when an untrusted self-signed certificate is found +in the chain. +--- + test/openssl/test_ssl.rb | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb +index 6095d545b5..9e9b8b9b69 100644 +--- a/test/openssl/test_ssl.rb ++++ b/test/openssl/test_ssl.rb +@@ -964,7 +964,9 @@ def test_connect_certificate_verify_failed_exception_message + start_server(ignore_listener_error: true) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params +- assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed/) { ++ # OpenSSL <= 1.1.0: "self signed certificate in certificate chain" ++ # OpenSSL >= 3.0.0: "self-signed certificate in certificate chain" ++ assert_raise_with_message(OpenSSL::SSL::SSLError, /self.signed/) { + server_connect(port, ctx) + } + } +-- +2.32.0 + diff --git a/ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch b/ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch new file mode 100644 index 0000000..2019380 --- /dev/null +++ b/ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch @@ -0,0 +1,265 @@ +From 2c6797bc97d7c92284dc3c0ed27f97ace4e5cfb9 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 31 May 2021 11:44:05 +0900 +Subject: [PATCH] test/openssl/utils: remove dup_public helper method + +It uses deprecated PKey::{RSA,DSA,DH}#set_* methods, which will not +work with OpenSSL 3.0. The same can easily be achieved using +PKey#public_to_der regardless of the key kind. +--- + test/openssl/test_pkey_dh.rb | 8 +++++--- + test/openssl/test_pkey_dsa.rb | 15 +++++++++++---- + test/openssl/test_pkey_ec.rb | 15 +++++++++++---- + test/openssl/test_pkey_rsa.rb | 31 +++++++++++++++++-------------- + test/openssl/utils.rb | 26 -------------------------- + 5 files changed, 44 insertions(+), 51 deletions(-) + +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index f80af8f841..757704caf6 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -40,12 +40,14 @@ def test_derive_key + + def test_DHparams + dh1024 = Fixtures.pkey("dh1024") ++ dh1024params = dh1024.public_key ++ + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Integer(dh1024.p), + OpenSSL::ASN1::Integer(dh1024.g) + ]) + key = OpenSSL::PKey::DH.new(asn1.to_der) +- assert_same_dh dup_public(dh1024), key ++ assert_same_dh dh1024params, key + + pem = <<~EOF + -----BEGIN DH PARAMETERS----- +@@ -55,9 +57,9 @@ def test_DHparams + -----END DH PARAMETERS----- + EOF + key = OpenSSL::PKey::DH.new(pem) +- assert_same_dh dup_public(dh1024), key ++ assert_same_dh dh1024params, key + key = OpenSSL::PKey.read(pem) +- assert_same_dh dup_public(dh1024), key ++ assert_same_dh dh1024params, key + + assert_equal asn1.to_der, dh1024.to_der + assert_equal pem, dh1024.export +diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb +index 147e50176b..0994607f21 100644 +--- a/test/openssl/test_pkey_dsa.rb ++++ b/test/openssl/test_pkey_dsa.rb +@@ -138,6 +138,8 @@ def test_DSAPrivateKey_encrypted + + def test_PUBKEY + dsa512 = Fixtures.pkey("dsa512") ++ dsa512pub = OpenSSL::PKey::DSA.new(dsa512.public_to_der) ++ + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::ObjectId("DSA"), +@@ -153,7 +155,7 @@ def test_PUBKEY + ]) + key = OpenSSL::PKey::DSA.new(asn1.to_der) + assert_not_predicate key, :private? +- assert_same_dsa dup_public(dsa512), key ++ assert_same_dsa dsa512pub, key + + pem = <<~EOF + -----BEGIN PUBLIC KEY----- +@@ -166,10 +168,15 @@ def test_PUBKEY + -----END PUBLIC KEY----- + EOF + key = OpenSSL::PKey::DSA.new(pem) +- assert_same_dsa dup_public(dsa512), key ++ assert_same_dsa dsa512pub, key ++ ++ assert_equal asn1.to_der, key.to_der ++ assert_equal pem, key.export + +- assert_equal asn1.to_der, dup_public(dsa512).to_der +- assert_equal pem, dup_public(dsa512).export ++ assert_equal asn1.to_der, dsa512.public_to_der ++ assert_equal asn1.to_der, key.public_to_der ++ assert_equal pem, dsa512.public_to_pem ++ assert_equal pem, key.public_to_pem + end + + def test_read_DSAPublicKey_pem +diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb +index 4b6df0290f..d62f1b5eb8 100644 +--- a/test/openssl/test_pkey_ec.rb ++++ b/test/openssl/test_pkey_ec.rb +@@ -210,6 +210,8 @@ def test_ECPrivateKey_encrypted + + def test_PUBKEY + p256 = Fixtures.pkey("p256") ++ p256pub = OpenSSL::PKey::EC.new(p256.public_to_der) ++ + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::ObjectId("id-ecPublicKey"), +@@ -221,7 +223,7 @@ def test_PUBKEY + ]) + key = OpenSSL::PKey::EC.new(asn1.to_der) + assert_not_predicate key, :private? +- assert_same_ec dup_public(p256), key ++ assert_same_ec p256pub, key + + pem = <<~EOF + -----BEGIN PUBLIC KEY----- +@@ -230,10 +232,15 @@ def test_PUBKEY + -----END PUBLIC KEY----- + EOF + key = OpenSSL::PKey::EC.new(pem) +- assert_same_ec dup_public(p256), key ++ assert_same_ec p256pub, key ++ ++ assert_equal asn1.to_der, key.to_der ++ assert_equal pem, key.export + +- assert_equal asn1.to_der, dup_public(p256).to_der +- assert_equal pem, dup_public(p256).export ++ assert_equal asn1.to_der, p256.public_to_der ++ assert_equal asn1.to_der, key.public_to_der ++ assert_equal pem, p256.public_to_pem ++ assert_equal pem, key.public_to_pem + end + + def test_ec_group +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index 5e127f5407..4548bdb2cf 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -201,7 +201,7 @@ def test_sign_verify_pss + + def test_encrypt_decrypt + rsapriv = Fixtures.pkey("rsa-1") +- rsapub = dup_public(rsapriv) ++ rsapub = OpenSSL::PKey.read(rsapriv.public_to_der) + + # Defaults to PKCS #1 v1.5 + raw = "data" +@@ -216,7 +216,7 @@ def test_encrypt_decrypt + + def test_encrypt_decrypt_legacy + rsapriv = Fixtures.pkey("rsa-1") +- rsapub = dup_public(rsapriv) ++ rsapub = OpenSSL::PKey.read(rsapriv.public_to_der) + + # Defaults to PKCS #1 v1.5 + raw = "data" +@@ -346,13 +346,15 @@ def test_RSAPrivateKey_encrypted + + def test_RSAPublicKey + rsa1024 = Fixtures.pkey("rsa1024") ++ rsa1024pub = OpenSSL::PKey::RSA.new(rsa1024.public_to_der) ++ + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Integer(rsa1024.n), + OpenSSL::ASN1::Integer(rsa1024.e) + ]) + key = OpenSSL::PKey::RSA.new(asn1.to_der) + assert_not_predicate key, :private? +- assert_same_rsa dup_public(rsa1024), key ++ assert_same_rsa rsa1024pub, key + + pem = <<~EOF + -----BEGIN RSA PUBLIC KEY----- +@@ -362,11 +364,13 @@ def test_RSAPublicKey + -----END RSA PUBLIC KEY----- + EOF + key = OpenSSL::PKey::RSA.new(pem) +- assert_same_rsa dup_public(rsa1024), key ++ assert_same_rsa rsa1024pub, key + end + + def test_PUBKEY + rsa1024 = Fixtures.pkey("rsa1024") ++ rsa1024pub = OpenSSL::PKey::RSA.new(rsa1024.public_to_der) ++ + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::ObjectId("rsaEncryption"), +@@ -381,7 +385,7 @@ def test_PUBKEY + ]) + key = OpenSSL::PKey::RSA.new(asn1.to_der) + assert_not_predicate key, :private? +- assert_same_rsa dup_public(rsa1024), key ++ assert_same_rsa rsa1024pub, key + + pem = <<~EOF + -----BEGIN PUBLIC KEY----- +@@ -392,10 +396,15 @@ def test_PUBKEY + -----END PUBLIC KEY----- + EOF + key = OpenSSL::PKey::RSA.new(pem) +- assert_same_rsa dup_public(rsa1024), key ++ assert_same_rsa rsa1024pub, key ++ ++ assert_equal asn1.to_der, key.to_der ++ assert_equal pem, key.export + +- assert_equal asn1.to_der, dup_public(rsa1024).to_der +- assert_equal pem, dup_public(rsa1024).export ++ assert_equal asn1.to_der, rsa1024.public_to_der ++ assert_equal asn1.to_der, key.public_to_der ++ assert_equal pem, rsa1024.public_to_pem ++ assert_equal pem, key.public_to_pem + end + + def test_pem_passwd +@@ -482,12 +491,6 @@ def test_private_encoding_encrypted + assert_same_rsa rsa1024, OpenSSL::PKey.read(pem, "abcdef") + end + +- def test_public_encoding +- rsa1024 = Fixtures.pkey("rsa1024") +- assert_equal dup_public(rsa1024).to_der, rsa1024.public_to_der +- assert_equal dup_public(rsa1024).to_pem, rsa1024.public_to_pem +- end +- + def test_dup + key = Fixtures.pkey("rsa1024") + key2 = key.dup +diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb +index c1d737b2ab..f664bd3074 100644 +--- a/test/openssl/utils.rb ++++ b/test/openssl/utils.rb +@@ -313,32 +313,6 @@ def check_component(base, test, keys) + assert_equal base.send(comp), test.send(comp) + } + end +- +- def dup_public(key) +- case key +- when OpenSSL::PKey::RSA +- rsa = OpenSSL::PKey::RSA.new +- rsa.set_key(key.n, key.e, nil) +- rsa +- when OpenSSL::PKey::DSA +- dsa = OpenSSL::PKey::DSA.new +- dsa.set_pqg(key.p, key.q, key.g) +- dsa.set_key(key.pub_key, nil) +- dsa +- when OpenSSL::PKey::DH +- dh = OpenSSL::PKey::DH.new +- dh.set_pqg(key.p, nil, key.g) +- dh +- else +- if defined?(OpenSSL::PKey::EC) && OpenSSL::PKey::EC === key +- ec = OpenSSL::PKey::EC.new(key.group) +- ec.public_key = key.public_key +- ec +- else +- raise "unknown key type" +- end +- end +- end + end + + module OpenSSL::Certs +-- +2.32.0 + diff --git a/ruby-3.1.1-ossl_ocsp-use-null.patch b/ruby-3.1.1-ossl_ocsp-use-null.patch new file mode 100644 index 0000000..d6d39ef --- /dev/null +++ b/ruby-3.1.1-ossl_ocsp-use-null.patch @@ -0,0 +1,31 @@ +--- ext/openssl/ossl_ocsp.c.orig 2022-04-07 16:40:13.263752886 +0200 ++++ ext/openssl/ossl_ocsp.c 2022-04-07 16:45:56.818971187 +0200 +@@ -382,7 +382,7 @@ + if (!NIL_P(flags)) + flg = NUM2INT(flags); + if (NIL_P(digest)) +- md = EVP_sha1(); ++ md = NULL; + else + md = ossl_evp_get_digestbyname(digest); + if (NIL_P(certs)) +@@ -1033,7 +1033,7 @@ + if (!NIL_P(flags)) + flg = NUM2INT(flags); + if (NIL_P(digest)) +- md = EVP_sha1(); ++ md = NULL; + else + md = ossl_evp_get_digestbyname(digest); + if (NIL_P(certs)) +--- test/openssl/test_ocsp.rb.orig 2022-04-08 08:20:31.400739869 +0200 ++++ test/openssl/test_ocsp.rb 2022-04-08 08:20:37.208727488 +0200 +@@ -99,7 +99,7 @@ + request.sign(@cert, @cert_key, [@ca_cert], 0) + asn1 = OpenSSL::ASN1.decode(request.to_der) + assert_equal cid.to_der, asn1.value[0].value.find { |a| a.tag_class == :UNIVERSAL }.value[0].value[0].to_der +- assert_equal OpenSSL::ASN1.ObjectId("sha1WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der ++ assert_equal OpenSSL::ASN1.ObjectId("sha256WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der + assert_equal @cert.to_der, asn1.value[1].value[0].value[2].value[0].value[0].to_der + assert_equal @ca_cert.to_der, asn1.value[1].value[0].value[2].value[0].value[1].to_der + assert_equal asn1.to_der, OpenSSL::OCSP::Request.new(asn1.to_der).to_der diff --git a/ruby-3.1.2-ossl-tests-replace-sha1.patch b/ruby-3.1.2-ossl-tests-replace-sha1.patch new file mode 100644 index 0000000..176101c --- /dev/null +++ b/ruby-3.1.2-ossl-tests-replace-sha1.patch @@ -0,0 +1,647 @@ +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index fedcb93..53ad621 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -174,6 +174,7 @@ have_func("SSL_CTX_set_post_handshake_auth") + + # added in 1.1.1 + have_func("EVP_PKEY_check") ++have_func("SSL_CTX_set_ciphersuites") + + # added in 3.0.0 + have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", "openssl/ts.h") +diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h +index 4b51268..2ab8aea 100644 +--- a/ext/openssl/ossl.h ++++ b/ext/openssl/ossl.h +@@ -43,13 +43,13 @@ + #ifndef LIBRESSL_VERSION_NUMBER + # define OSSL_IS_LIBRESSL 0 + # define OSSL_OPENSSL_PREREQ(maj, min, pat) \ +- (OPENSSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12)) ++ (OPENSSL_VERSION_NUMBER >= ((maj << 28) | (min << 20) | (pat << 12))) + # define OSSL_LIBRESSL_PREREQ(maj, min, pat) 0 + #else + # define OSSL_IS_LIBRESSL 1 + # define OSSL_OPENSSL_PREREQ(maj, min, pat) 0 + # define OSSL_LIBRESSL_PREREQ(maj, min, pat) \ +- (LIBRESSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12)) ++ (LIBRESSL_VERSION_NUMBER >= ((maj << 28) | (min << 20) | (pat << 12))) + #endif + + #if !defined(OPENSSL_NO_ENGINE) && !OSSL_OPENSSL_PREREQ(3, 0, 0) +diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c +index a61d3ee..0d3fa9a 100644 +--- a/ext/openssl/ossl_asn1.c ++++ b/ext/openssl/ossl_asn1.c +@@ -1510,7 +1510,7 @@ Init_ossl_asn1(void) + * + * An Array that stores the name of a given tag number. These names are + * the same as the name of the tag constant that is additionally defined, +- * e.g. UNIVERSAL_TAG_NAME[2] = "INTEGER" and OpenSSL::ASN1::INTEGER = 2. ++ * e.g. UNIVERSAL_TAG_NAME[2] = "INTEGER" and OpenSSL::ASN1::INTEGER = 2. + * + * == Example usage + * +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 2a4835a..24d0da4 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -649,7 +649,7 @@ ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der) + } + } + else { +-#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER) ++#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_LIBRESSL_PREREQ(3, 5, 0) + if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0, + ossl_pem_passwd_cb, + (void *)pass)) { +diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c +index 9a0682a..af262d9 100644 +--- a/ext/openssl/ossl_ssl.c ++++ b/ext/openssl/ossl_ssl.c +@@ -1025,27 +1025,13 @@ ossl_sslctx_get_ciphers(VALUE self) + return ary; + } + +-/* +- * call-seq: +- * ctx.ciphers = "cipher1:cipher2:..." +- * ctx.ciphers = [name, ...] +- * ctx.ciphers = [[name, version, bits, alg_bits], ...] +- * +- * Sets the list of available cipher suites for this context. Note in a server +- * context some ciphers require the appropriate certificates. For example, an +- * RSA cipher suite can only be chosen when an RSA certificate is available. +- */ + static VALUE +-ossl_sslctx_set_ciphers(VALUE self, VALUE v) ++build_cipher_string(VALUE v) + { +- SSL_CTX *ctx; + VALUE str, elem; + int i; + +- rb_check_frozen(self); +- if (NIL_P(v)) +- return v; +- else if (RB_TYPE_P(v, T_ARRAY)) { ++ if (RB_TYPE_P(v, T_ARRAY)) { + str = rb_str_new(0, 0); + for (i = 0; i < RARRAY_LEN(v); i++) { + elem = rb_ary_entry(v, i); +@@ -1059,14 +1059,67 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v) + StringValue(str); + } + ++ return str; ++} ++ ++/* ++ * call-seq: ++ * ctx.ciphers = "cipher1:cipher2:..." ++ * ctx.ciphers = [name, ...] ++ * ctx.ciphers = [[name, version, bits, alg_bits], ...] ++ * ++ * Sets the list of available cipher suites for this context. Note in a server ++ * context some ciphers require the appropriate certificates. For example, an ++ * RSA cipher suite can only be chosen when an RSA certificate is available. ++ */ ++static VALUE ++ossl_sslctx_set_ciphers(VALUE self, VALUE v) ++{ ++ SSL_CTX *ctx; ++ VALUE str; ++ ++ rb_check_frozen(self); ++ if (NIL_P(v)) ++ return v; ++ ++ str = build_cipher_string(v); ++ + GetSSLCTX(self, ctx); +- if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str))) { ++ if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str))) + ossl_raise(eSSLError, "SSL_CTX_set_cipher_list"); +- } + + return v; + } + ++#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES ++/* ++ * call-seq: ++ * ctx.ciphersuites = "cipher1:cipher2:..." ++ * ctx.ciphersuites = [name, ...] ++ * ctx.ciphersuites = [[name, version, bits, alg_bits], ...] ++ * ++ * Sets the list of available TLSv1.3 cipher suites for this context. ++ */ ++static VALUE ++ossl_sslctx_set_ciphersuites(VALUE self, VALUE v) ++{ ++ SSL_CTX *ctx; ++ VALUE str; ++ ++ rb_check_frozen(self); ++ if (NIL_P(v)) ++ return v; ++ ++ str = build_cipher_string(v); ++ ++ GetSSLCTX(self, ctx); ++ if (!SSL_CTX_set_ciphersuites(ctx, StringValueCStr(str))) ++ ossl_raise(eSSLError, "SSL_CTX_set_ciphersuites"); ++ ++ return v; ++} ++#endif ++ + #if !defined(OPENSSL_NO_EC) + /* + * call-seq: +@@ -2818,6 +2857,9 @@ Init_ossl_ssl(void) + ossl_sslctx_set_minmax_proto_version, 2); + rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0); + rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1); ++#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES ++ rb_define_method(cSSLContext, "ciphersuites=", ossl_sslctx_set_ciphersuites, 1); ++#endif + rb_define_method(cSSLContext, "ecdh_curves=", ossl_sslctx_set_ecdh_curves, 1); + rb_define_method(cSSLContext, "security_level", ossl_sslctx_get_security_level, 0); + rb_define_method(cSSLContext, "security_level=", ossl_sslctx_set_security_level, 1); +diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb +index 0fd7971..c79bc14 100644 +--- a/test/openssl/test_asn1.rb ++++ b/test/openssl/test_asn1.rb +@@ -14,7 +14,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ] +- dgst = OpenSSL::Digest.new('SHA1') ++ dgst = OpenSSL::Digest.new('SHA256') + cert = OpenSSL::TestUtils.issue_cert( + subj, key, s, exts, nil, nil, digest: dgst, not_before: now, not_after: now+3600) + +@@ -42,7 +42,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase + assert_equal(OpenSSL::ASN1::Sequence, sig.class) + assert_equal(2, sig.value.size) + assert_equal(OpenSSL::ASN1::ObjectId, sig.value[0].class) +- assert_equal("1.2.840.113549.1.1.5", sig.value[0].oid) ++ assert_equal("1.2.840.113549.1.1.11", sig.value[0].oid) + assert_equal(OpenSSL::ASN1::Null, sig.value[1].class) + + dn = tbs_cert.value[3] # issuer +@@ -189,7 +189,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase + assert_equal(OpenSSL::ASN1::Null, pkey.value[0].value[1].class) + + assert_equal(OpenSSL::ASN1::BitString, sig_val.class) +- cululated_sig = key.sign(OpenSSL::Digest.new('SHA1'), tbs_cert.to_der) ++ cululated_sig = key.sign(OpenSSL::Digest.new('SHA256'), tbs_cert.to_der) + assert_equal(cululated_sig, sig_val.value) + end + +diff --git a/test/openssl/test_ns_spki.rb b/test/openssl/test_ns_spki.rb +index ed3be86..383931b 100644 +--- a/test/openssl/test_ns_spki.rb ++++ b/test/openssl/test_ns_spki.rb +@@ -22,7 +22,7 @@ class OpenSSL::TestNSSPI < OpenSSL::TestCase + spki = OpenSSL::Netscape::SPKI.new + spki.challenge = "RandomString" + spki.public_key = key1.public_key +- spki.sign(key1, OpenSSL::Digest.new('SHA1')) ++ spki.sign(key1, OpenSSL::Digest.new('SHA256')) + assert(spki.verify(spki.public_key)) + assert(spki.verify(key1.public_key)) + assert(!spki.verify(key2.public_key)) +diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb +index 726b7db..08213df 100644 +--- a/test/openssl/test_pkey_dsa.rb ++++ b/test/openssl/test_pkey_dsa.rb +@@ -36,8 +36,8 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase + assert_equal true, dsa512.verify(OpenSSL::Digest.new('DSS1'), signature, data) + end + +- signature = dsa512.sign("SHA1", data) +- assert_equal true, dsa512.verify("SHA1", signature, data) ++ signature = dsa512.sign("SHA256", data) ++ assert_equal true, dsa512.verify("SHA256", signature, data) + + signature0 = (<<~'end;').unpack("m")[0] + MCwCFH5h40plgU5Fh0Z4wvEEpz0eE9SnAhRPbkRB8ggsN/vsSEYMXvJwjGg/ +diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb +index ffe5a94..c06fe6f 100644 +--- a/test/openssl/test_pkey_ec.rb ++++ b/test/openssl/test_pkey_ec.rb +@@ -98,8 +98,8 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase + def test_sign_verify + p256 = Fixtures.pkey("p256") + data = "Sign me!" +- signature = p256.sign("SHA1", data) +- assert_equal true, p256.verify("SHA1", signature, data) ++ signature = p256.sign("SHA256", data) ++ assert_equal true, p256.verify("SHA256", signature, data) + + signature0 = (<<~'end;').unpack("m")[0] + MEQCIEOTY/hD7eI8a0qlzxkIt8LLZ8uwiaSfVbjX2dPAvN11AiAQdCYx56Fq +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index 4bb39ed..9e06e43 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -80,8 +80,8 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase + def test_sign_verify + rsa1024 = Fixtures.pkey("rsa1024") + data = "Sign me!" +- signature = rsa1024.sign("SHA1", data) +- assert_equal true, rsa1024.verify("SHA1", signature, data) ++ signature = rsa1024.sign("SHA256", data) ++ assert_equal true, rsa1024.verify("SHA256", signature, data) + + signature0 = (<<~'end;').unpack("m")[0] + oLCgbprPvfhM4pjFQiDTFeWI9Sk+Og7Nh9TmIZ/xSxf2CGXQrptlwo7NQ28+ +@@ -113,10 +113,10 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase + def test_sign_verify_raw + key = Fixtures.pkey("rsa-1") + data = "Sign me!" +- hash = OpenSSL::Digest.digest("SHA1", data) +- signature = key.sign_raw("SHA1", hash) +- assert_equal true, key.verify_raw("SHA1", signature, hash) +- assert_equal true, key.verify("SHA1", signature, data) ++ hash = OpenSSL::Digest.digest("SHA256", data) ++ signature = key.sign_raw("SHA256", hash) ++ assert_equal true, key.verify_raw("SHA256", signature, hash) ++ assert_equal true, key.verify("SHA256", signature, data) + + # Too long data + assert_raise(OpenSSL::PKey::PKeyError) { +@@ -129,9 +129,9 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase + "rsa_pss_saltlen" => 20, + "rsa_mgf1_md" => "SHA256" + } +- sig_pss = key.sign_raw("SHA1", hash, pssopts) +- assert_equal true, key.verify("SHA1", sig_pss, data, pssopts) +- assert_equal true, key.verify_raw("SHA1", sig_pss, hash, pssopts) ++ sig_pss = key.sign_raw("SHA256", hash, pssopts) ++ assert_equal true, key.verify("SHA256", sig_pss, data, pssopts) ++ assert_equal true, key.verify_raw("SHA256", sig_pss, hash, pssopts) + end + + def test_sign_verify_raw_legacy +diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb +index a7607da..3ba8b39 100644 +--- a/test/openssl/test_ssl.rb ++++ b/test/openssl/test_ssl.rb +@@ -669,10 +669,16 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase + # buzz.example.net, respectively). ... + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:baz*.example.com'), 'baz1.example.com')) ++ ++ # LibreSSL 3.5.0+ doesn't support other wildcard certificates ++ # (it isn't required to, as RFC states MAY, not MUST) ++ return if libressl?(3, 5, 0) ++ + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:*baz.example.com'), 'foobaz.example.com')) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( + create_cert_with_san('DNS:b*z.example.com'), 'buzz.example.com')) ++ + # Section 6.4.3 of RFC6125 states that client should NOT match identifier + # where wildcard is other than left-most label. + # +@@ -1556,8 +1562,101 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase + end + end + ++ def test_ciphersuites_method_tls_connection ++ ssl_ctx = OpenSSL::SSL::SSLContext.new ++ if !tls13_supported? || !ssl_ctx.respond_to?(:ciphersuites=) ++ pend 'TLS 1.3 not supported' ++ end ++ ++ csuite = ['TLS_AES_128_GCM_SHA256', 'TLSv1.3', 128, 128] ++ inputs = [csuite[0], [csuite[0]], [csuite]] ++ ++ start_server do |port| ++ inputs.each do |input| ++ cli_ctx = OpenSSL::SSL::SSLContext.new ++ cli_ctx.min_version = cli_ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION ++ cli_ctx.ciphersuites = input ++ ++ server_connect(port, cli_ctx) do |ssl| ++ assert_equal('TLSv1.3', ssl.ssl_version) ++ if libressl?(3, 4, 0) && !libressl?(3, 5, 0) ++ assert_equal("AEAD-AES128-GCM-SHA256", ssl.cipher[0]) ++ else ++ assert_equal(csuite[0], ssl.cipher[0]) ++ end ++ ssl.puts('abc'); assert_equal("abc\n", ssl.gets) ++ end ++ end ++ end ++ end ++ ++ def test_ciphersuites_method_nil_argument ++ ssl_ctx = OpenSSL::SSL::SSLContext.new ++ pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=) ++ ++ assert_nothing_raised { ssl_ctx.ciphersuites = nil } ++ end ++ ++ def test_ciphersuites_method_frozen_object ++ ssl_ctx = OpenSSL::SSL::SSLContext.new ++ pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=) ++ ++ ssl_ctx.freeze ++ assert_raise(FrozenError) { ssl_ctx.ciphersuites = 'TLS_AES_256_GCM_SHA384' } ++ end ++ ++ def test_ciphersuites_method_bogus_csuite ++ ssl_ctx = OpenSSL::SSL::SSLContext.new ++ pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=) ++ ++ assert_raise_with_message( ++ OpenSSL::SSL::SSLError, ++ /SSL_CTX_set_ciphersuites: no cipher match/i ++ ) { ssl_ctx.ciphersuites = 'BOGUS' } ++ end ++ ++ def test_ciphers_method_tls_connection ++ csuite = ['ECDHE-RSA-AES256-GCM-SHA384', 'TLSv1.2', 256, 256] ++ inputs = [csuite[0], [csuite[0]], [csuite]] ++ ++ start_server do |port| ++ inputs.each do |input| ++ cli_ctx = OpenSSL::SSL::SSLContext.new ++ cli_ctx.min_version = cli_ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION ++ cli_ctx.ciphers = input ++ ++ server_connect(port, cli_ctx) do |ssl| ++ assert_equal('TLSv1.2', ssl.ssl_version) ++ assert_equal(csuite[0], ssl.cipher[0]) ++ ssl.puts('abc'); assert_equal("abc\n", ssl.gets) ++ end ++ end ++ end ++ end ++ ++ def test_ciphers_method_nil_argument ++ ssl_ctx = OpenSSL::SSL::SSLContext.new ++ assert_nothing_raised { ssl_ctx.ciphers = nil } ++ end ++ ++ def test_ciphers_method_frozen_object ++ ssl_ctx = OpenSSL::SSL::SSLContext.new ++ ++ ssl_ctx.freeze ++ assert_raise(FrozenError) { ssl_ctx.ciphers = 'ECDHE-RSA-AES128-SHA' } ++ end ++ ++ def test_ciphers_method_bogus_csuite ++ ssl_ctx = OpenSSL::SSL::SSLContext.new ++ ++ assert_raise_with_message( ++ OpenSSL::SSL::SSLError, ++ /SSL_CTX_set_cipher_list: no cipher match/i ++ ) { ssl_ctx.ciphers = 'BOGUS' } ++ end ++ + def test_connect_works_when_setting_dh_callback_to_nil + pend "TLS 1.2 is not supported" unless tls12_supported? + + ctx_proc = -> ctx { + ctx.ssl_version = :TLSv1_2 +diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb +index d696b98..4e2bd0c 100644 +--- a/test/openssl/test_x509cert.rb ++++ b/test/openssl/test_x509cert.rb +@@ -180,6 +180,7 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase + assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) + cert.serial = 2 + assert_equal(false, cert.verify(@rsa2048)) ++ rescue OpenSSL::X509::CertificateError # RHEL 9 disables SHA1 + end + + def test_sign_and_verify_rsa_md5 +@@ -226,9 +227,8 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase + assert_equal("dsa_with_SHA256", cert.signature_algorithm) + # TODO: need more tests for dsa + sha2 + +- # SHA1 is allowed from OpenSSL 1.0.0 (0.9.8 requires DSS1) +- cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha1") +- assert_equal("dsaWithSHA1", cert.signature_algorithm) ++ cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha512") ++ assert_equal("dsa_with_SHA512", cert.signature_algorithm) + end + + def test_check_private_key +diff --git a/test/openssl/test_x509crl.rb b/test/openssl/test_x509crl.rb +index bcdb0a6..146ee07 100644 +--- a/test/openssl/test_x509crl.rb ++++ b/test/openssl/test_x509crl.rb +@@ -20,7 +20,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase + + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) + crl = issue_crl([], 1, now, now+1600, [], +- cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + assert_equal(1, crl.version) + assert_equal(cert.issuer.to_der, crl.issuer.to_der) + assert_equal(now, crl.last_update) +@@ -57,7 +57,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase + ] + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) + crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], +- cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + revoked = crl.revoked + assert_equal(5, revoked.size) + assert_equal(1, revoked[0].serial) +@@ -98,7 +98,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase + + revoke_info = (1..1000).collect{|i| [i, now, 0] } + crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], +- cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + revoked = crl.revoked + assert_equal(1000, revoked.size) + assert_equal(1, revoked[0].serial) +@@ -124,7 +124,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase + + cert = issue_cert(@ca, @rsa2048, 1, cert_exts, nil, nil) + crl = issue_crl([], 1, Time.now, Time.now+1600, crl_exts, +- cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + exts = crl.extensions + assert_equal(3, exts.size) + assert_equal("1", exts[0].value) +@@ -160,24 +160,24 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase + assert_equal(false, exts[2].critical?) + + no_ext_crl = issue_crl([], 1, Time.now, Time.now+1600, [], +- cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + assert_equal nil, no_ext_crl.authority_key_identifier + end + + def test_crlnumber + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) + crl = issue_crl([], 1, Time.now, Time.now+1600, [], +- cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + assert_match(1.to_s, crl.extensions[0].value) + assert_match(/X509v3 CRL Number:\s+#{1}/m, crl.to_text) + + crl = issue_crl([], 2**32, Time.now, Time.now+1600, [], +- cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + assert_match((2**32).to_s, crl.extensions[0].value) + assert_match(/X509v3 CRL Number:\s+#{2**32}/m, crl.to_text) + + crl = issue_crl([], 2**100, Time.now, Time.now+1600, [], +- cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + assert_match(/X509v3 CRL Number:\s+#{2**100}/m, crl.to_text) + assert_match((2**100).to_s, crl.extensions[0].value) + end +@@ -185,7 +185,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase + def test_sign_and_verify + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) + crl = issue_crl([], 1, Time.now, Time.now+1600, [], +- cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + assert_equal(false, crl.verify(@rsa1024)) + assert_equal(true, crl.verify(@rsa2048)) + assert_equal(false, crl_error_returns_false { crl.verify(@dsa256) }) +@@ -195,7 +195,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase + + cert = issue_cert(@ca, @dsa512, 1, [], nil, nil) + crl = issue_crl([], 1, Time.now, Time.now+1600, [], +- cert, @dsa512, OpenSSL::Digest.new('SHA1')) ++ cert, @dsa512, OpenSSL::Digest.new('SHA256')) + assert_equal(false, crl_error_returns_false { crl.verify(@rsa1024) }) + assert_equal(false, crl_error_returns_false { crl.verify(@rsa2048) }) + assert_equal(false, crl.verify(@dsa256)) +diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb +index ee9c678..a84b162 100644 +--- a/test/openssl/test_x509req.rb ++++ b/test/openssl/test_x509req.rb +@@ -23,31 +23,31 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase + end + + def test_public_key +- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) ++ req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) + assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) + +- req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA1')) ++ req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA256')) + assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) + end + + def test_version +- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) ++ req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) + assert_equal(0, req.version) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(0, req.version) + +- req = issue_csr(1, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) ++ req = issue_csr(1, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) + assert_equal(1, req.version) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(1, req.version) + end + + def test_subject +- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) ++ req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) + assert_equal(@dn.to_der, req.subject.to_der) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(@dn.to_der, req.subject.to_der) +@@ -78,9 +78,9 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase + OpenSSL::X509::Attribute.new("msExtReq", attrval), + ] + +- req0 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) ++ req0 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) + attrs.each{|attr| req0.add_attribute(attr) } +- req1 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) ++ req1 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) + req1.attributes = attrs + assert_equal(req0.to_der, req1.to_der) + +@@ -101,7 +101,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase + end + + def test_sign_and_verify_rsa_sha1 +- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) ++ req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) + assert_equal(true, req.verify(@rsa1024)) + assert_equal(false, req.verify(@rsa2048)) + assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) +@@ -122,7 +122,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase + end + + def test_sign_and_verify_dsa +- req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA1')) ++ req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA256')) + assert_equal(false, request_error_returns_false { req.verify(@rsa1024) }) + assert_equal(false, request_error_returns_false { req.verify(@rsa2048) }) + assert_equal(false, req.verify(@dsa256)) +@@ -137,13 +137,13 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase + end + + def test_dup +- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) ++ req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) + assert_equal(req.to_der, req.dup.to_der) + end + + def test_eq +- req1 = issue_csr(0, @dn, @rsa1024, "sha1") +- req2 = issue_csr(0, @dn, @rsa1024, "sha1") ++ req1 = issue_csr(0, @dn, @rsa1024, "sha512") ++ req2 = issue_csr(0, @dn, @rsa1024, "sha512") + req3 = issue_csr(0, @dn, @rsa1024, "sha256") + + assert_equal false, req1 == 12345 +--- a/test/openssl/test_x509store.rb.orig 2022-07-14 14:07:32.468809273 +0200 ++++ b/test/openssl/test_x509store.rb 2022-07-13 17:27:58.115363595 +0200 +@@ -72,16 +72,16 @@ + + revoke_info = [] + crl1 = issue_crl(revoke_info, 1, now, now+1800, [], +- ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + revoke_info = [ [2, now, 1], ] + crl1_2 = issue_crl(revoke_info, 2, now, now+1800, [], +- ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + revoke_info = [ [20, now, 1], ] + crl2 = issue_crl(revoke_info, 1, now, now+1800, [], +- ca2_cert, @rsa1024, OpenSSL::Digest.new('SHA1')) ++ ca2_cert, @rsa1024, OpenSSL::Digest.new('SHA256')) + revoke_info = [] + crl2_2 = issue_crl(revoke_info, 2, now-100, now-1, [], +- ca2_cert, @rsa1024, OpenSSL::Digest.new('SHA1')) ++ ca2_cert, @rsa1024, OpenSSL::Digest.new('SHA256')) + + assert_equal(true, ca1_cert.verify(ca1_cert.public_key)) # self signed + assert_equal(true, ca2_cert.verify(ca1_cert.public_key)) # issued by ca1 +@@ -220,10 +220,10 @@ + + revoke_info = [] + crl1 = issue_crl(revoke_info, 1, now, now+1800, [], +- ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + revoke_info = [ [2, now, 1], ] + crl2 = issue_crl(revoke_info, 2, now+1800, now+3600, [], +- ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1')) ++ ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA256')) + store.add_crl(crl1) + assert_raise(OpenSSL::X509::StoreError){ + store.add_crl(crl2) # add CRL issued by same CA twice. diff --git a/ruby-exercise.stp b/ruby-exercise.stp new file mode 100644 index 0000000..df9df41 --- /dev/null +++ b/ruby-exercise.stp @@ -0,0 +1,39 @@ +/* Example tapset file. + * + * You can execute the tapset using following command (please adjust the path + * prior running the command, if needed): + * + * stap /usr/share/doc/ruby-2.0.0.0/ruby-exercise.stp -c "ruby -e \"puts 'test'\"" + */ + +probe ruby.cmethod.entry { + printf("%d -> %s::%s %s:%d\n", tid(), classname, methodname, file, line); +} + +probe ruby.cmethod.return { + printf("%d <- %s::%s %s:%d\n", tid(), classname, methodname, file, line); +} + +probe ruby.method.entry { + printf("%d -> %s::%s %s:%d\n", tid(), classname, methodname, file, line); +} + +probe ruby.method.return { + printf("%d <- %s::%s %s:%d\n", tid(), classname, methodname, file, line); +} + +probe ruby.gc.mark.begin { printf("%d gc.mark.begin\n", tid()); } + +probe ruby.gc.mark.end { printf("%d gc.mark.end\n", tid()); } + +probe ruby.gc.sweep.begin { printf("%d gc.sweep.begin\n", tid()); } + +probe ruby.gc.sweep.end { printf("%d gc.sweep.end\n", tid()); } + +probe ruby.object.create{ + printf("%d obj.create %s %s:%d\n", tid(), classname, file, line); +} + +probe ruby.raise { + printf("%d raise %s %s:%d\n", tid(), classname, file, line); +} diff --git a/ruby.rpmlintrc b/ruby.rpmlintrc new file mode 100644 index 0000000..bc72c06 --- /dev/null +++ b/ruby.rpmlintrc @@ -0,0 +1,56 @@ +# Keep matching patterns enough not to hide unintended errors and warnings. + +# There is no way to implement this with `%{SOURCE0}` without `%{_sourcedir}`. +# The order in the .spec file could be possibly different. +addFilter(r'ruby\.(spec|src):20: E: use-of-RPM_SOURCE_DIR$') + +# The used version is not obvious. +addFilter(r'ruby\.(spec|src):\d+: W: unversioned-explicit-provides bundled\(ccan-build_assert\)$') +addFilter(r'ruby\.(spec|src):\d+: W: unversioned-explicit-provides bundled\(ccan-check_type\)$') +addFilter(r'ruby\.(spec|src):\d+: W: unversioned-explicit-provides bundled\(ccan-container_of\)$') +addFilter(r'ruby\.(spec|src):\d+: W: unversioned-explicit-provides bundled\(ccan-list\)$') + +# The template files do not have to have executable bits. +addFilter(r'^rubygem-bundler\.noarch: E: non-executable-script /usr/share/gems/gems/bundler-[\d\.]+/lib/bundler/templates/[\w/\.]+ 644 /usr/bin/env ') + +# The bundled gem files permissions are overridden as 644 by `make install`. +# https://bugs.ruby-lang.org/issues/17840 +# power_assert +# https://github.com/ruby/power_assert/issues/35 +addFilter(r'^rubygem-power_assert\.noarch: E: non-executable-script /usr/share/gems/gems/power_assert-[\d\.]+/bin/console 644 ') +addFilter(r'^rubygem-power_assert\.noarch: E: non-executable-script /usr/share/gems/gems/power_assert-[\d\.]+/bin/setup 644 ') +# rake +# https://github.com/ruby/rake/issues/385 +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/bundle 644 ') +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/console 644 ') +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/rake 644 ') +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/rdoc 644 ') +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/rubocop 644 ') +addFilter(r'^rubygem-rake\.noarch: E: non-executable-script /usr/share/gems/gems/rake-[\d\.]+/bin/setup 644 ') +# rbs +# https://github.com/ruby/rbs/issues/673 +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/annotate-with-rdoc 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/console 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/query-rdoc 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/rbs-prof 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/setup 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/sort 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/steep 644 ') +addFilter(r'^rubygem-rbs\.noarch: E: non-executable-script /usr/share/gems/gems/rbs-[\d\.]+/bin/test_runner.rb 644 ') +# test-unit +addFilter(r'^rubygem-test-unit\.noarch: E: non-executable-script /usr/share/gems/gems/test-unit-[\d\.]+/test/run-test.rb 644 ') + +# The function `chroot` without using `chdir` is detected by rpmlint with the +# following message. However it looks a false positive as the `chroot` in the +# `dir.c` is just used as a Ruby binding `Dir.chroot` for the function. +# +# ruby-libs.x86_64: E: missing-call-to-chdir-with-chroot /usr/lib64/libruby.so.3.0.1 +# This executable appears to call chroot without using chdir to change the +# current directory. This is likely an error and permits an attacker to break +# out of the chroot by using fchdir. While that's not always a security issue, +# this has to be checked. +addFilter(r'^ruby-libs\.\w+: E: missing-call-to-chdir-with-chroot /usr/lib(64)?/libruby.so.[\d/.]+$') + +# Nothing referred and no dependency information should be no problem. +# https://bugs.ruby-lang.org/issues/16558#note-2 +addFilter(r'^ruby-libs\.\w+: E: shared-lib-without-dependency-information /usr/lib(64)?/ruby/enc/gb2312.so$') diff --git a/ruby.spec b/ruby.spec new file mode 100644 index 0000000..99e14b5 --- /dev/null +++ b/ruby.spec @@ -0,0 +1,2851 @@ +%global major_version 3 +%global minor_version 0 +%global teeny_version 4 +%global major_minor_version %{major_version}.%{minor_version} + +%global ruby_version %{major_minor_version}.%{teeny_version} +%global ruby_release %{ruby_version} + +# Specify the named version. It has precedense to revision. +#%%global milestone rc1 + +# Keep the revision enabled for pre-releases from GIT. +#%%global revision 684649ea05 + +%global ruby_archive %{name}-%{ruby_version} + +# If revision and milestone are removed/commented out, the official release build is expected. +%if 0%{?milestone:1}%{?revision:1} != 0 +%global ruby_archive %{ruby_archive}-%{?milestone}%{?!milestone:%{?revision}} +%define ruby_archive_timestamp %(stat --printf='@%Y' %{_sourcedir}/%{ruby_archive}.tar.xz | date -f - +"%Y%m%d") +%define development_release %{?milestone}%{?!milestone:%{?revision:%{ruby_archive_timestamp}git%{revision}}} +%endif + + +%global release 141 +%{!?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 +# RubyGems should be share by all Ruby implementations. +%global rubygems_dir %{_datadir}/rubygems + +# Bundled libraries versions +%global rubygems_version 3.2.33 +%global rubygems_molinillo_version 0.7.0 + +# Default gems. +%global bundler_version 2.2.33 +%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 + +%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 + +# 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 rexml_version 3.2.5 +%global rss_version 0.2.9 +%global typeprof_version 0.15.2 + +%global tapset_libdir %(echo %{_libdir} | sed 's/64//')* + +%if 0%{?fedora} >= 19 +%bcond_without rubypick +%endif + +%bcond_without cmake +%bcond_without git +%bcond_without gmp +%bcond_without hostname +%bcond_without systemtap + +%if 0%{?fedora} +%bcond_without hardening_test +%endif + +%bcond_with tests + +# 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} +Release: %{release_string} +# Public Domain for example for: include/ruby/st.h, strftime.c, missing/*, ... +# MIT and CCO: ccan/* +# zlib: ext/digest/md5/md5.*, ext/nkf/nkf-utf8/nkf.c +# UCD: some of enc/trans/**/*.src +License: (Ruby or BSD) and Public Domain and MIT and CC0 and zlib and UCD +URL: https://www.ruby-lang.org/ +Source0: https://cache.ruby-lang.org/pub/%{name}/%{major_minor_version}/%{ruby_archive}.tar.xz +Source1: operating_system.rb +# TODO: Try to push SystemTap support upstream. +Source2: libruby.stp +Source3: ruby-exercise.stp +Source4: macros.ruby +Source5: macros.rubygems +# RPM dependency generators. +Source8: rubygems.attr +Source9: rubygems.req +Source10: rubygems.prov +Source11: rubygems.con +# ABRT hoook test case. +Source13: test_abrt.rb +# SystemTap tests. +Source14: test_systemtap.rb + +# The load directive is supported since RPM 4.12, i.e. F21+. The build process +# fails on older Fedoras. +%{load:%{SOURCE4}} +%{load:%{SOURCE5}} + +# Fix ruby_version abuse. +# https://bugs.ruby-lang.org/issues/11002 +Patch0: ruby-2.3.0-ruby_version.patch +# http://bugs.ruby-lang.org/issues/7807 +Patch1: ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch +# Allows to override libruby.so placement. Hopefully we will be able to return +# to plain --with-rubyarchprefix. +# http://bugs.ruby-lang.org/issues/8973 +Patch2: ruby-2.1.0-Enable-configuration-of-archlibdir.patch +# Force multiarch directories for i.86 to be always named i386. This solves +# some differencies in build between Fedora and RHEL. +Patch3: ruby-2.1.0-always-use-i386.patch +# Allows to install RubyGems into custom directory, outside of Ruby's tree. +# http://bugs.ruby-lang.org/issues/5617 +Patch4: ruby-2.1.0-custom-rubygems-location.patch +# Make mkmf verbose by default +Patch5: ruby-1.9.3-mkmf-verbose.patch +# 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 +# Unfortunately, due to https://bugs.ruby-lang.org/issues/16254 +# and especially since https://github.com/ruby/ruby/pull/2735 +# this would require boostrapping: +# 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 +# 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 +# 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 /test_\(ast_compacts\|compact_count\|complex_hash_keys\|gc_compact_stats\)/ +# test failures on ppc64le. +# https://bugs.ruby-lang.org/issues/18746 +# https://bugs.ruby-lang.org/issues/18394 +Patch20: ruby-3.1.0-Use-mmap-for-allocating-heap-pages-in-the-GC.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 + +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Suggests: rubypick +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 +BuildRequires: libyaml-devel +BuildRequires: readline-devel +# Needed to pass test_set_program_name(TestRubyOptions) +BuildRequires: procps +%{?with_systemtap:BuildRequires: %{_bindir}/dtrace} +# RubyGems test suite optional dependencies. +%{?with_git:BuildRequires: git} +%{?with_cmake:BuildRequires: %{_bindir}/cmake} +# Required to test hardening. +%{?with_hardening_test:BuildRequires: %{_bindir}/checksec} +%{?with_hostname:BuildRequires: %{_bindir}/hostname} +BuildRequires: multilib-rpm-config +BuildRequires: gcc +BuildRequires: make +BuildRequires: zlib-devel + +# This package provides %%{_bindir}/ruby-mri therefore it is marked by this +# virtual provide. It can be installed as dependency of rubypick. +Provides: ruby(runtime_executable) = %{ruby_release} + +%description +Ruby is the interpreted scripting language for quick and easy +object-oriented programming. It has many features to process text +files and to do system management tasks (as in Perl). It is simple, +straight-forward, and extensible. + + +%package devel +Summary: A Ruby development environment +Requires: %{name}%{?_isa} = %{version}-%{release} +# This would not be needed if ~50 packages depending on -devel used +# --disable-gems +Requires: rubygems +# Users need CFLAGS from /usr/lib/rpm/redhat/redhat-hardened-cc1 +# for building gems with binary extensions (rhbz#1905222). +Recommends: redhat-rpm-config + +%description devel +Header files and libraries for building an extension library for the +Ruby or an application embedding Ruby. + +%package libs +Summary: Libraries necessary to run Ruby +License: Ruby or BSD +Provides: ruby(release) = %{ruby_release} + +# Virtual provides for CCAN copylibs. +# https://fedorahosted.org/fpc/ticket/364 +Provides: bundled(ccan-build_assert) +Provides: bundled(ccan-check_type) +Provides: bundled(ccan-container_of) +Provides: bundled(ccan-list) + +# StdLib default gems. +Provides: bundled(rubygem-did_you_mean) = %{did_you_mean_version} +Provides: bundled(rubygem-openssl) = %{openssl_version} +Provides: bundled(rubygem-racc) = %{racc_version} + +%description libs +This package includes the libruby, necessary to run Ruby. + + +# TODO: Rename or not rename to ruby-rubygems? +%package -n rubygems +Summary: The Ruby standard for packaging ruby libraries +Version: %{rubygems_version} +License: Ruby or MIT +Requires: ruby(release) +Recommends: rubygem(bundler) >= %{bundler_version} +Recommends: rubygem(rdoc) >= %{rdoc_version} +Recommends: rubygem(io-console) >= %{io_console_version} +Requires: rubygem(psych) >= %{psych_version} +Provides: gem = %{version}-%{release} +Provides: ruby(rubygems) = %{version}-%{release} +# https://github.com/rubygems/rubygems/pull/1189#issuecomment-121600910 +Provides: bundled(rubygem-molinillo) = %{rubygems_molinillo_version} +BuildArch: noarch + +%description -n rubygems +RubyGems is the Ruby standard for publishing and managing third party +libraries. + + +%package -n rubygems-devel +Summary: Macros and development tools for packaging RubyGems +Version: %{rubygems_version} +License: Ruby or MIT +Requires: ruby(rubygems) >= %{version}-%{release} +# Needed for RDoc documentation format generation. +Requires: rubygem(json) >= %{json_version} +Requires: rubygem(rdoc) >= %{rdoc_version} +BuildArch: noarch + +%description -n rubygems-devel +Macros and development tools for packaging RubyGems. + + +# Default gems +# +# These packages are part of Ruby StdLib and are expected to be loadable even +# with disabled RubyGems. + +%package default-gems +Summary: Default gems which are part of Ruby StdLib +Requires: ruby(rubygems) >= %{rubygems_version} +Supplements: ruby(rubygems) +# Include the io-console dependency for reline. +Requires: rubygem(io-console) +# Obsoleted by Ruby 2.7 in F32 timeframe. +Obsoletes: rubygem-did_you_mean < 1.4.0-130 +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} +BuildArch: noarch + +%description default-gems +The .gemspec files and executables of default gems, which are part of Ruby +StdLib. + + +%package -n rubygem-irb +Summary: The Interactive Ruby +Version: %{irb_version} +Requires: ruby(release) +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} +Provides: irb = %{version}-%{release} +Provides: rubygem(irb) = %{version}-%{release} +# Obsoleted by Ruby 2.6 in F30 timeframe. +Provides: ruby(irb) = %{ruby_version}-%{release} +Provides: ruby-irb = %{ruby_version}-%{release} +Obsoletes: ruby-irb < %{ruby_version}-%{release} +BuildArch: noarch + +%description -n rubygem-irb +The irb is acronym for Interactive Ruby. It evaluates ruby expression +from the terminal. + + +%package -n rubygem-rdoc +Summary: A tool to generate HTML and command-line documentation for Ruby projects +Version: %{rdoc_version} +# SIL: lib/rdoc/generator/template/darkfish/css/fonts.css +License: GPLv2 and Ruby and MIT and OFL +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Requires: rubygem(io-console) >= %{io_console_version} +Requires: rubygem(json) >= %{json_version} +Provides: rdoc = %{version}-%{release} +Provides: ri = %{version}-%{release} +Provides: rubygem(rdoc) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-rdoc +RDoc produces HTML and command-line documentation for Ruby projects. RDoc +includes the 'rdoc' and 'ri' tools for generating and displaying online +documentation. + + +%package doc +Summary: Documentation for %{name} +Requires: %{_bindir}/ri +BuildArch: noarch + +%description doc +This package contains documentation for %{name}. + + +%package -n rubygem-bigdecimal +Summary: BigDecimal provides arbitrary-precision floating point decimal arithmetic +Version: %{bigdecimal_version} +License: Ruby or BSD +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(bigdecimal) = %{version}-%{release} + +%description -n rubygem-bigdecimal +Ruby provides built-in support for arbitrary precision integer arithmetic. +For example: + +42**13 -> 1265437718438866624512 + +BigDecimal provides similar support for very large or very accurate floating +point numbers. Decimal arithmetic is also useful for general calculation, +because it provides the correct answers people expect–whereas normal binary +floating point arithmetic often introduces subtle errors because of the +conversion between base 10 and base 2. + + +%package -n rubygem-io-console +Summary: IO/Console is a simple console utilizing library +Version: %{io_console_version} +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(io-console) = %{version}-%{release} + +%description -n rubygem-io-console +IO/Console provides very simple and portable access to console. It doesn't +provide higher layer features, such like curses and readline. + + +%package -n rubygem-json +Summary: This is a JSON implementation as a Ruby extension in C +Version: %{json_version} +# UCD: ext/json/generator/generator.c +License: (Ruby or GPLv2) and UCD +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(json) = %{version}-%{release} + +%description -n rubygem-json +This is a implementation of the JSON specification according to RFC 4627. +You can think of it as a low fat alternative to XML, if you want to store +data to disk or transmit it over a network rather than use a verbose +markup language. + + +%package -n rubygem-psych +Summary: A libyaml wrapper for Ruby +Version: %{psych_version} +License: MIT +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(psych) = %{version}-%{release} + +%description -n rubygem-psych +Psych is a YAML parser and emitter. Psych leverages +libyaml[http://pyyaml.org/wiki/LibYAML] for its YAML parsing and emitting +capabilities. In addition to wrapping libyaml, Psych also knows how to +serialize and de-serialize most Ruby objects to and from the YAML format. + + +%package -n rubygem-bundler +Summary: Library and utilities to manage a Ruby application's gem dependencies +Version: %{bundler_version} +License: MIT +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Requires: rubygem(io-console) +Provides: rubygem(bundler) = %{version}-%{release} +# https://github.com/bundler/bundler/issues/3647 +Provides: bundled(rubygem-connection_pool) = %{bundler_connection_pool_version} +Provides: bundled(rubygem-fileutils) = %{bundler_fileutils_version} +Provides: bundled(rubygem-molinillo) = %{bundler_molinillo_version} +Provides: bundled(rubygem-net-http-persisntent) = %{bundler_net_http_persistent_version} +Provides: bundled(rubygem-thor) = %{bundler_thor_version} +Provides: bundled(rubygem-tmpdir) = %{bundler_tmpdir_version} +Provides: bundled(rubygem-uri) = %{bundler_uri_version} +BuildArch: noarch + +%description -n rubygem-bundler +Bundler manages an application's dependencies through its entire life, across +many machines, systematically and repeatably. + + +# Bundled gems +# +# These are regular packages, which might be installed just optionally. Users +# should list them among their dependencies (in Gemfile). + +%package -n rubygem-minitest +Summary: Minitest provides a complete suite of testing facilities +Version: %{minitest_version} +License: MIT +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(minitest) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-minitest +minitest/unit is a small and incredibly fast unit testing framework. + +minitest/spec is a functionally complete spec engine. + +minitest/benchmark is an awesome way to assert the performance of your +algorithms in a repeatable manner. + +minitest/mock by Steven Baker, is a beautifully tiny mock object +framework. + +minitest/pride shows pride in testing and adds coloring to your test +output. + + +%package -n rubygem-power_assert +Summary: Power Assert for Ruby +Version: %{power_assert_version} +License: Ruby or BSD +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(power_assert) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-power_assert +Power Assert shows each value of variables and method calls in the expression. +It is useful for testing, providing which value wasn't correct when the +condition is not satisfied. + + +%package -n rubygem-rake +Summary: Ruby based make-like utility +Version: %{rake_version} +License: MIT +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rake = %{version}-%{release} +Provides: rubygem(rake) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-rake +Rake is a Make-like program implemented in Ruby. Tasks and dependencies are +specified in standard Ruby syntax. + + +%package -n rubygem-rbs +Summary: Type signature for Ruby +Version: %{rbs_version} +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 +definitions. + + +%package -n rubygem-test-unit +Summary: An xUnit family unit testing framework for Ruby +Version: %{test_unit_version} +# lib/test/unit/diff.rb is a double license of the Ruby license and PSF license. +# lib/test-unit.rb is a dual license of the Ruby license and LGPLv2.1 or later. +License: (Ruby or BSD) and (Ruby or BSD or Python) and (Ruby or BSD or LGPLv2+) +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Requires: rubygem(power_assert) +Provides: rubygem(test-unit) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-test-unit +Test::Unit (test-unit) is unit testing framework for Ruby, based on xUnit +principles. These were originally designed by Kent Beck, creator of extreme +programming software development methodology, for Smalltalk's SUnit. It allows +writing tests, checking results and automated testing in Ruby. + + +%package -n rubygem-rexml +Summary: An XML toolkit for Ruby +Version: %{rexml_version} +License: BSD +URL: https://github.com/ruby/rexml +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(rexml) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-rexml +REXML was inspired by the Electric XML library for Java, which features an +easy-to-use API, small size, and speed. Hopefully, REXML, designed with the same +philosophy, has these same features. I've tried to keep the API as intuitive as +possible, and have followed the Ruby methodology for method naming and code +flow, rather than mirroring the Java API. + +REXML supports both tree and stream document parsing. Stream parsing is faster +(about 1.5 times as fast). However, with stream parsing, you don't get access to +features such as XPath. + + +%package -n rubygem-rss +Summary: Family of libraries that support various formats of XML "feeds" +Version: %{rss_version} +License: BSD +URL: https://github.com/ruby/rss +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Provides: rubygem(rss) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-rss +Really Simple Syndication (RSS) is a family of formats that describe 'feeds', +specially constructed XML documents that allow an interested person to subscribe +and receive updates from a particular web service. This library provides tooling +to read and create these feeds. + + +%package -n rubygem-typeprof +Summary: TypeProf is a type analysis tool for Ruby code based on abstract interpretation +Version: %{typeprof_version} +License: MIT +URL: https://github.com/ruby/typeprof +Requires: ruby(release) +Requires: ruby(rubygems) >= %{rubygems_version} +Requires: rubygem(rbs) >= %{rbs_version} +Provides: rubygem(typeprof) = %{version}-%{release} +BuildArch: noarch + +%description -n rubygem-typeprof +TypeProf performs a type analysis of non-annotated Ruby code. +It abstractly executes input Ruby code in a level of types instead of values, +gathers what types are passed to and returned by methods, and prints the +analysis result in RBS format, a standard type description format for Ruby +3.0. + + +%prep +%setup -q -n %{ruby_archive} + +# Remove bundled libraries to be sure they are not used. +rm -rf ext/psych/yaml +rm -rf ext/fiddle/libffi* + +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch15 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 + +# Provide an example of usage of the tapset: +cp -a %{SOURCE3} . + +%build +autoconf + +%configure \ + --with-rubylibprefix='%{ruby_libdir}' \ + --with-archlibdir='%{_libdir}' \ + --with-rubyarchprefix='%{ruby_libarchdir}' \ + --with-sitedir='%{ruby_sitelibdir}' \ + --with-sitearchdir='%{ruby_sitearchdir}' \ + --with-vendordir='%{ruby_vendorlibdir}' \ + --with-vendorarchdir='%{ruby_vendorarchdir}' \ + --with-rubyhdrdir='%{_includedir}' \ + --with-rubyarchhdrdir='%{_includedir}' \ + --with-sitearchhdrdir='$(sitehdrdir)/$(arch)' \ + --with-vendorarchhdrdir='$(vendorhdrdir)/$(arch)' \ + --with-rubygemsdir='%{rubygems_dir}' \ + --with-ruby-pc='%{name}.pc' \ + --with-compress-debug-sections=no \ + --disable-rpath \ + --enable-shared \ + --with-ruby-version='' \ + --enable-multiarch \ + +# Q= makes the build output more verbose and allows to check Fedora +# compiler options. +%make_build COPY="cp -p" Q= + +%install +rm -rf %{buildroot} +%make_install + +# TODO: Regenerate RBS parser in lib/rbs/parser.rb + +# Rename ruby/config.h to ruby/config-.h to avoid file conflicts on +# multilib systems and install config.h wrapper +%multilib_fix_c_header --file %{_includedir}/%{name}/config.h +# TODO: The correct patch should be %%{_includedir}/%%{name}/rb_mjit_min_header-%%{ruby_version}.h +# https://bugs.ruby-lang.org/issues/15425 +%multilib_fix_c_header --file %{_includedir}/rb_mjit_min_header-%{ruby_version}.h + +# Rename the ruby executable. It is replaced by RubyPick. +%{?with_rubypick:mv %{buildroot}%{_bindir}/%{name}{,-mri}} + +# Version is empty if --with-ruby-version is specified. +# http://bugs.ruby-lang.org/issues/7807 +sed -i 's/Version: \${ruby_version}/Version: %{ruby_version}/' %{buildroot}%{_libdir}/pkgconfig/%{name}.pc + +# Kill bundled certificates, as they should be part of ca-certificates. +for cert in \ + rubygems.org/GlobalSignRootCA.pem \ + rubygems.org/GlobalSignRootCA_R3.pem +do + rm %{buildroot}%{rubygems_dir}/rubygems/ssl_certs/$cert + rm -d $(dirname %{buildroot}%{rubygems_dir}/rubygems/ssl_certs/$cert) || : +done +# Ensure there is not forgotten any certificate. +test ! "$(ls -A %{buildroot}%{rubygems_dir}/rubygems/ssl_certs/ 2>/dev/null)" + +# Move macros file into proper place and replace the %%{name} macro, since it +# would be wrongly evaluated during build of other packages. +mkdir -p %{buildroot}%{_rpmconfigdir}/macros.d +install -m 644 %{SOURCE4} %{buildroot}%{_rpmconfigdir}/macros.d/macros.ruby +sed -i "s/%%{name}/%{name}/" %{buildroot}%{_rpmconfigdir}/macros.d/macros.ruby +install -m 644 %{SOURCE5} %{buildroot}%{_rpmconfigdir}/macros.d/macros.rubygems +sed -i "s/%%{name}/%{name}/" %{buildroot}%{_rpmconfigdir}/macros.d/macros.rubygems + +# Install dependency generators. +mkdir -p %{buildroot}%{_rpmconfigdir}/fileattrs +install -m 644 %{SOURCE8} %{buildroot}%{_rpmconfigdir}/fileattrs +install -m 755 %{SOURCE9} %{buildroot}%{_rpmconfigdir} +install -m 755 %{SOURCE10} %{buildroot}%{_rpmconfigdir} +install -m 755 %{SOURCE11} %{buildroot}%{_rpmconfigdir} + +# Install custom operating_system.rb. +mkdir -p %{buildroot}%{rubygems_dir}/rubygems/defaults +cp %{SOURCE1} %{buildroot}%{rubygems_dir}/rubygems/defaults + +# Move gems root into common direcotry, out of Ruby directory structure. +mv %{buildroot}%{ruby_libdir}/gems %{buildroot}%{gem_dir} + +# Create folders for gem binary extensions. +# TODO: These folders should go into rubygem-filesystem but how to achieve it, +# since noarch package cannot provide arch dependent subpackages? +# http://rpm.org/ticket/78 +mkdir -p %{buildroot}%{_exec_prefix}/lib{,64}/gems/%{name} + +# Move bundled rubygems to %%gem_dir and %%gem_extdir_mri +# make symlinks for io-console and bigdecimal, which are considered to be part of stdlib by other Gems +mkdir -p %{buildroot}%{gem_dir}/gems/irb-%{irb_version}/lib +mv %{buildroot}%{ruby_libdir}/irb* %{buildroot}%{gem_dir}/gems/irb-%{irb_version}/lib +mv %{buildroot}%{gem_dir}/specifications/default/irb-%{irb_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/irb-%{irb_version}/lib/irb.rb %{buildroot}%{ruby_libdir}/irb.rb +# TODO: This should be possible to replaced by simple directory symlink +# after ~ F31 EOL (rhbz#1691039). +mkdir -p %{buildroot}%{ruby_libdir}/irb +pushd %{buildroot}%{gem_dir}/gems/irb-%{irb_version}/lib +find irb -type d -mindepth 1 -exec mkdir %{buildroot}%{ruby_libdir}/'{}' \; +find irb -type f -exec ln -s %{gem_dir}/gems/irb-%{irb_version}/lib/'{}' %{buildroot}%{ruby_libdir}/'{}' \; +popd + +mkdir -p %{buildroot}%{gem_dir}/gems/rdoc-%{rdoc_version}/lib +mv %{buildroot}%{ruby_libdir}/rdoc* %{buildroot}%{gem_dir}/gems/rdoc-%{rdoc_version}/lib +mv %{buildroot}%{gem_dir}/specifications/default/rdoc-%{rdoc_version}.gemspec %{buildroot}%{gem_dir}/specifications + +mkdir -p %{buildroot}%{gem_dir}/gems/bigdecimal-%{bigdecimal_version}/lib +mkdir -p %{buildroot}%{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version}/bigdecimal +mv %{buildroot}%{ruby_libdir}/bigdecimal %{buildroot}%{gem_dir}/gems/bigdecimal-%{bigdecimal_version}/lib +mv %{buildroot}%{ruby_libarchdir}/bigdecimal.so %{buildroot}%{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version} +touch %{buildroot}%{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version}/gem.build_complete +mv %{buildroot}%{gem_dir}/specifications/default/bigdecimal-%{bigdecimal_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/bigdecimal-%{bigdecimal_version}/lib/bigdecimal %{buildroot}%{ruby_libdir}/bigdecimal +ln -s %{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version}/bigdecimal.so %{buildroot}%{ruby_libarchdir}/bigdecimal.so + +# TODO: Put help files into proper location. +# https://bugs.ruby-lang.org/issues/15359 +mkdir -p %{buildroot}%{gem_dir}/gems/bundler-%{bundler_version}/lib +mv %{buildroot}%{ruby_libdir}/bundler.rb %{buildroot}%{gem_dir}/gems/bundler-%{bundler_version}/lib +mv %{buildroot}%{ruby_libdir}/bundler %{buildroot}%{gem_dir}/gems/bundler-%{bundler_version}/lib +mv %{buildroot}%{gem_dir}/specifications/default/bundler-%{bundler_version}.gemspec %{buildroot}%{gem_dir}/specifications + +mkdir -p %{buildroot}%{gem_dir}/gems/io-console-%{io_console_version}/lib +mkdir -p %{buildroot}%{_libdir}/gems/%{name}/io-console-%{io_console_version}/io +mv %{buildroot}%{ruby_libdir}/io %{buildroot}%{gem_dir}/gems/io-console-%{io_console_version}/lib +mv %{buildroot}%{ruby_libarchdir}/io/console.so %{buildroot}%{_libdir}/gems/%{name}/io-console-%{io_console_version}/io +touch %{buildroot}%{_libdir}/gems/%{name}/io-console-%{io_console_version}/gem.build_complete +mv %{buildroot}%{gem_dir}/specifications/default/io-console-%{io_console_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/io-console-%{io_console_version}/lib/io %{buildroot}%{ruby_libdir}/io +ln -s %{_libdir}/gems/%{name}/io-console-%{io_console_version}/io/console.so %{buildroot}%{ruby_libarchdir}/io/console.so + +mkdir -p %{buildroot}%{gem_dir}/gems/json-%{json_version}/lib +mkdir -p %{buildroot}%{_libdir}/gems/%{name}/json-%{json_version} +mv %{buildroot}%{ruby_libdir}/json* %{buildroot}%{gem_dir}/gems/json-%{json_version}/lib +mv %{buildroot}%{ruby_libarchdir}/json/ %{buildroot}%{_libdir}/gems/%{name}/json-%{json_version}/ +touch %{buildroot}%{_libdir}/gems/%{name}/json-%{json_version}/gem.build_complete +mv %{buildroot}%{gem_dir}/specifications/default/json-%{json_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/json-%{json_version}/lib/json.rb %{buildroot}%{ruby_libdir}/json.rb +ln -s %{gem_dir}/gems/json-%{json_version}/lib/json %{buildroot}%{ruby_libdir}/json +ln -s %{_libdir}/gems/%{name}/json-%{json_version}/json/ %{buildroot}%{ruby_libarchdir}/json + +mkdir -p %{buildroot}%{gem_dir}/gems/psych-%{psych_version}/lib +mkdir -p %{buildroot}%{_libdir}/gems/%{name}/psych-%{psych_version} +mv %{buildroot}%{ruby_libdir}/psych* %{buildroot}%{gem_dir}/gems/psych-%{psych_version}/lib +mv %{buildroot}%{ruby_libarchdir}/psych.so %{buildroot}%{_libdir}/gems/%{name}/psych-%{psych_version}/ +touch %{buildroot}%{_libdir}/gems/%{name}/psych-%{psych_version}/gem.build_complete +mv %{buildroot}%{gem_dir}/specifications/default/psych-%{psych_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/psych-%{psych_version}/lib/psych %{buildroot}%{ruby_libdir}/psych +ln -s %{gem_dir}/gems/psych-%{psych_version}/lib/psych.rb %{buildroot}%{ruby_libdir}/psych.rb +ln -s %{_libdir}/gems/%{name}/psych-%{psych_version}/psych.so %{buildroot}%{ruby_libarchdir}/psych.so + +# Move the binary extensions into proper place (if no gem has binary extension, +# the extensions directory might be empty). +find %{buildroot}%{gem_dir}/extensions/*-%{_target_os}/%{ruby_version}/* -maxdepth 0 \ + -exec mv '{}' %{buildroot}%{_libdir}/gems/%{name}/ \; \ + || echo "No gem binary extensions to move." + +# 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 +# https://bugs.ruby-lang.org/issues/17778 +cp -a %{buildroot}%{gem_dir}/gems/bundler-%{bundler_version}/lib/bundler/man/*.1 %{buildroot}%{_mandir}/man1 +cp -a %{buildroot}%{gem_dir}/gems/bundler-%{bundler_version}/lib/bundler/man/*.5 %{buildroot}%{_mandir}/man5 + +%if %{with systemtap} +# Install a tapset and fix up the path to the library. +mkdir -p %{buildroot}%{_systemtap_tapsetdir} +sed -e "s|@LIBRARY_PATH@|%{tapset_libdir}/libruby.so.%{major_minor_version}|" \ + %{SOURCE2} > %{buildroot}%{_systemtap_tapsetdir}/libruby.so.%{major_minor_version}.stp +# Escape '*/' in comment. +sed -i -r "s|( \*.*\*)\/(.*)|\1\\\/\2|" %{buildroot}%{_systemtap_tapsetdir}/libruby.so.%{major_minor_version}.stp +%endif + +# Prepare -doc subpackage file lists. +find doc -maxdepth 1 -type f ! -name '.*' ! -name '*.ja*' > .ruby-doc.en +echo 'doc/images' >> .ruby-doc.en +echo 'doc/syntax' >> .ruby-doc.en + +find doc -maxdepth 1 -type f -name '*.ja*' > .ruby-doc.ja +echo 'doc/irb' >> .ruby-doc.ja +echo 'doc/pty' >> .ruby-doc.ja + +sed -i 's/^/%doc /' .ruby-doc.* +sed -i 's/^/%lang(ja) /' .ruby-doc.ja + +# Remove useless .github directory from Rake. +# https://github.com/ruby/rake/pull/333 +rm -rf %{buildroot}%{gem_dir}/gems/rake-%{rake_version}/.github + +%check +%if %{with tests} +%if 0%{?with_hardening_test} +# Check Ruby hardening. +checksec --file=libruby.so.%{ruby_version} | \ + grep "Full RELRO.*Canary found.*NX enabled.*DSO.*No RPATH.*No RUNPATH.*Yes.*\d*.*\d*.*libruby.so.%{ruby_version}" +%endif + +# Check RubyGems version. +[ "`make runruby TESTRUN_SCRIPT='bin/gem -v' | tail -1`" == '%{rubygems_version}' ] + +# Check Rubygems bundled dependencies versions. + +# Molinillo. +[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ + module Gem; module Resolver; end; end; \ + require 'rubygems/resolver/molinillo/lib/molinillo/gem_metadata'; \ + puts Gem::Resolver::Molinillo::VERSION\\\"\" | tail -1`" \ + == '%{rubygems_molinillo_version}' ] + +# Check Bundler bundled dependencies versions. + +# connection_pool. +[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ + module Bundler; end; \ + require 'bundler/vendor/connection_pool/lib/connection_pool/version'; \ + puts Bundler::ConnectionPool::VERSION\\\"\" | tail -1`" \ + == '%{bundler_connection_pool_version}' ] + +# FileUtils. +[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ + module Bundler; end; \ + require 'bundler/vendor/fileutils/lib/fileutils'; \ + puts Bundler::FileUtils::VERSION\\\"\" | tail -1`" \ + == '%{bundler_fileutils_version}' ] + +# Molinillo. +[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ + module Bundler; end; \ + require 'bundler/vendor/molinillo/lib/molinillo/gem_metadata'; \ + puts Bundler::Molinillo::VERSION\\\"\" | tail -1`" \ + == '%{bundler_molinillo_version}' ] + +# Net::HTTP::Persistent. +[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ + module Bundler; module Persistent; module Net; module HTTP; \ + end; end; end; end; \ + require 'bundler/vendor/net-http-persistent/lib/net/http/persistent'; \ + puts Bundler::Persistent::Net::HTTP::Persistent::VERSION\\\"\" | tail -1`" \ + == '%{bundler_net_http_persistent_version}' ] + +# Thor. +[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ + module Bundler; end; \ + require 'bundler/vendor/thor/lib/thor/version'; \ + puts Bundler::Thor::VERSION\\\"\" | tail -1`" \ + == '%{bundler_thor_version}' ] + +# tmpdir. +# TODO: There is no version in bundled tmpdir yet. +#%%{global bundler_tmpdir_version} + +# URI. +[ "`make runruby TESTRUN_SCRIPT=\"-e \\\" \ + module Bundler; end; \ + require 'bundler/vendor/uri/lib/uri/version'; \ + puts Bundler::URI::VERSION\\\"\" | tail -1`" \ + == '%{bundler_uri_version}' ] + + +# test_debug(TestRubyOptions) fails due to LoadError reported in debug mode, +# when abrt.rb cannot be required (seems to be easier way then customizing +# the test suite). +touch abrt.rb + +# Check if abrt hook is required (RubyGems are disabled by default when using +# runruby, so re-enable them). +make runruby TESTRUN_SCRIPT="--enable-gems %{SOURCE13}" + +# Check if systemtap is supported. +%{?with_systemtap:make runruby TESTRUN_SCRIPT=%{SOURCE14}} + +DISABLE_TESTS="" +MSPECOPTS="" + +# Avoid `hostname' dependency. +%{!?with_hostname:MSPECOPTS="-P 'Socket.gethostname returns the host name'"} + +# 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}"} \ + make check TESTS="-v $DISABLE_TESTS" MSPECOPT="-fs $MSPECOPTS" + +%endif + +%files +%license BSDL +%license COPYING +%lang(ja) %license COPYING.ja +%license GPL +%license LEGAL +%{_bindir}/erb +%{_bindir}/%{name}%{?with_rubypick:-mri} +%{_mandir}/man1/erb* +%{_mandir}/man1/ruby* + +%files devel +%license BSDL +%license COPYING +%lang(ja) %license COPYING.ja +%license GPL +%license LEGAL + +%{_rpmconfigdir}/macros.d/macros.ruby + +%{_includedir}/* +%{_libdir}/libruby.so +%{_libdir}/pkgconfig/%{name}.pc + +%files libs +%license COPYING +%lang(ja) %license COPYING.ja +%license GPL +%license LEGAL +%doc README.md +%doc NEWS.md +# Exclude /usr/local directory since it is supposed to be managed by +# local system administrator. +%exclude %{ruby_sitelibdir} +%exclude %{ruby_sitearchdir} +%dir %{ruby_vendorlibdir} +%dir %{ruby_vendorarchdir} + +# List all these files explicitly to prevent surprises +# Platform independent libraries. +%dir %{ruby_libdir} +%exclude %{ruby_libdir}/bigdecimal* +%exclude %{ruby_libdir}/irb* +%exclude %{ruby_libdir}/json* +%exclude %{ruby_libdir}/psych* +%{ruby_libdir}/abbrev.rb +%{ruby_libdir}/base64.rb +%{ruby_libdir}/benchmark* +%{ruby_libdir}/cgi* +%{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}/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}/observer* +%{ruby_libdir}/open-uri.rb +%{ruby_libdir}/open3* +%{ruby_libdir}/optionparser.rb +%{ruby_libdir}/optparse* +%{ruby_libdir}/ostruct* +%{ruby_libdir}/pathname.rb +%{ruby_libdir}/pp.rb +%{ruby_libdir}/prettyprint.rb +%{ruby_libdir}/prime.rb +%{ruby_libdir}/pstore* +%{ruby_libdir}/readline.rb +%{ruby_libdir}/reline* +%{ruby_libdir}/resolv.rb +%{ruby_libdir}/resolv-replace.rb +%{ruby_libdir}/rinda +%{ruby_libdir}/ripper* +%{ruby_libdir}/securerandom.rb +%{ruby_libdir}/set* +%{ruby_libdir}/shellwords.rb +%{ruby_libdir}/singleton* +%{ruby_libdir}/socket.rb +%{ruby_libdir}/syslog +%{ruby_libdir}/tempfile.rb +%{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 +%{ruby_libdir}/uri* +%{ruby_libdir}/weakref* +%{ruby_libdir}/yaml* + +# Platform specific libraries. +%{_libdir}/libruby.so.* +%dir %{ruby_libarchdir} +%dir %{ruby_libarchdir}/cgi +%{ruby_libarchdir}/cgi/escape.so +%{ruby_libarchdir}/continuation.so +%{ruby_libarchdir}/coverage.so +%{ruby_libarchdir}/date_core.so +%{ruby_libarchdir}/dbm.so +%dir %{ruby_libarchdir}/digest +%{ruby_libarchdir}/digest.so +%{ruby_libarchdir}/digest/bubblebabble.so +%{ruby_libarchdir}/digest/md5.so +%{ruby_libarchdir}/digest/rmd160.so +%{ruby_libarchdir}/digest/sha1.so +%{ruby_libarchdir}/digest/sha2.so +%dir %{ruby_libarchdir}/enc +%{ruby_libarchdir}/enc/big5.so +%{ruby_libarchdir}/enc/cesu_8.so +%{ruby_libarchdir}/enc/cp949.so +%{ruby_libarchdir}/enc/emacs_mule.so +%{ruby_libarchdir}/enc/encdb.so +%{ruby_libarchdir}/enc/euc_jp.so +%{ruby_libarchdir}/enc/euc_kr.so +%{ruby_libarchdir}/enc/euc_tw.so +%{ruby_libarchdir}/enc/gb18030.so +%{ruby_libarchdir}/enc/gb2312.so +%{ruby_libarchdir}/enc/gbk.so +%{ruby_libarchdir}/enc/iso_8859_1.so +%{ruby_libarchdir}/enc/iso_8859_10.so +%{ruby_libarchdir}/enc/iso_8859_11.so +%{ruby_libarchdir}/enc/iso_8859_13.so +%{ruby_libarchdir}/enc/iso_8859_14.so +%{ruby_libarchdir}/enc/iso_8859_15.so +%{ruby_libarchdir}/enc/iso_8859_16.so +%{ruby_libarchdir}/enc/iso_8859_2.so +%{ruby_libarchdir}/enc/iso_8859_3.so +%{ruby_libarchdir}/enc/iso_8859_4.so +%{ruby_libarchdir}/enc/iso_8859_5.so +%{ruby_libarchdir}/enc/iso_8859_6.so +%{ruby_libarchdir}/enc/iso_8859_7.so +%{ruby_libarchdir}/enc/iso_8859_8.so +%{ruby_libarchdir}/enc/iso_8859_9.so +%{ruby_libarchdir}/enc/koi8_r.so +%{ruby_libarchdir}/enc/koi8_u.so +%{ruby_libarchdir}/enc/shift_jis.so +%dir %{ruby_libarchdir}/enc/trans +%{ruby_libarchdir}/enc/trans/big5.so +%{ruby_libarchdir}/enc/trans/cesu_8.so +%{ruby_libarchdir}/enc/trans/chinese.so +%{ruby_libarchdir}/enc/trans/ebcdic.so +%{ruby_libarchdir}/enc/trans/emoji.so +%{ruby_libarchdir}/enc/trans/emoji_iso2022_kddi.so +%{ruby_libarchdir}/enc/trans/emoji_sjis_docomo.so +%{ruby_libarchdir}/enc/trans/emoji_sjis_kddi.so +%{ruby_libarchdir}/enc/trans/emoji_sjis_softbank.so +%{ruby_libarchdir}/enc/trans/escape.so +%{ruby_libarchdir}/enc/trans/gb18030.so +%{ruby_libarchdir}/enc/trans/gbk.so +%{ruby_libarchdir}/enc/trans/iso2022.so +%{ruby_libarchdir}/enc/trans/japanese.so +%{ruby_libarchdir}/enc/trans/japanese_euc.so +%{ruby_libarchdir}/enc/trans/japanese_sjis.so +%{ruby_libarchdir}/enc/trans/korean.so +%{ruby_libarchdir}/enc/trans/single_byte.so +%{ruby_libarchdir}/enc/trans/transdb.so +%{ruby_libarchdir}/enc/trans/utf8_mac.so +%{ruby_libarchdir}/enc/trans/utf_16_32.so +%{ruby_libarchdir}/enc/utf_16be.so +%{ruby_libarchdir}/enc/utf_16le.so +%{ruby_libarchdir}/enc/utf_32be.so +%{ruby_libarchdir}/enc/utf_32le.so +%{ruby_libarchdir}/enc/windows_1250.so +%{ruby_libarchdir}/enc/windows_1251.so +%{ruby_libarchdir}/enc/windows_1252.so +%{ruby_libarchdir}/enc/windows_1253.so +%{ruby_libarchdir}/enc/windows_1254.so +%{ruby_libarchdir}/enc/windows_1257.so +%{ruby_libarchdir}/enc/windows_31j.so +%{ruby_libarchdir}/etc.so +%{ruby_libarchdir}/fcntl.so +%{ruby_libarchdir}/fiber.so +%{ruby_libarchdir}/fiddle.so +%{ruby_libarchdir}/gdbm.so +%dir %{ruby_libarchdir}/io +%{ruby_libarchdir}/io/nonblock.so +%{ruby_libarchdir}/io/wait.so +%{ruby_libarchdir}/monitor.so +%{ruby_libarchdir}/nkf.so +%{ruby_libarchdir}/objspace.so +%{ruby_libarchdir}/pathname.so +%{ruby_libarchdir}/pty.so +%dir %{ruby_libarchdir}/rbconfig +%{ruby_libarchdir}/rbconfig.rb +%{ruby_libarchdir}/rbconfig/sizeof.so +%{ruby_libarchdir}/readline.so +%{ruby_libarchdir}/ripper.so +%{ruby_libarchdir}/socket.so +%{ruby_libarchdir}/stringio.so +%{ruby_libarchdir}/strscan.so +%{ruby_libarchdir}/syslog.so +%{ruby_libarchdir}/zlib.so + +# Default gems +%{ruby_libdir}/did_you_mean* +%{ruby_libdir}/openssl* +%{ruby_libarchdir}/openssl.so +%{ruby_libdir}/racc* +%dir %{ruby_libarchdir}/racc +%{ruby_libarchdir}/racc/cparse.so + +%{?with_systemtap:%{_systemtap_datadir}} + +%files -n rubygems +%{_bindir}/gem +%dir %{rubygems_dir} +%{rubygems_dir}/rubygems +%{rubygems_dir}/rubygems.rb + +# Explicitly include only RubyGems directory strucure to avoid accidentally +# packaged content. +%dir %{gem_dir} +%dir %{gem_dir}/build_info +%dir %{gem_dir}/cache +%dir %{gem_dir}/doc +%dir %{gem_dir}/extensions +%dir %{gem_dir}/gems +%dir %{gem_dir}/plugins +%dir %{gem_dir}/specifications +%dir %{gem_dir}/specifications/default +%dir %{_exec_prefix}/lib*/gems +%dir %{_exec_prefix}/lib*/gems/ruby + +%exclude %{gem_dir}/cache/* + +%files -n rubygems-devel +%{_rpmconfigdir}/macros.d/macros.rubygems +%{_rpmconfigdir}/fileattrs/rubygems.attr +%{_rpmconfigdir}/rubygems.req +%{_rpmconfigdir}/rubygems.prov +%{_rpmconfigdir}/rubygems.con + +%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/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/english-0.7.1.gemspec +%{gem_dir}/specifications/default/erb-%{erb_version}.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.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/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/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/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/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.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/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/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/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/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}/gems/erb-%{erb_version} +# Use standalone rubygem-racc if Racc binary is required. Shipping this +# executable in both packages might possibly cause conflicts. The situation +# could be better if Ruby generated these files: +# https://github.com/ruby/ruby/pull/2545 +%exclude %{_bindir}/racc +%exclude %{gem_dir}/gems/racc-%{racc_version}/bin + +%files -n rubygem-irb +%{_bindir}/irb +%{ruby_libdir}/irb* +%{gem_dir}/gems/irb-%{irb_version} +%{gem_dir}/specifications/irb-%{irb_version}.gemspec +%{_mandir}/man1/irb.1* + +%files -n rubygem-rdoc +%{_bindir}/rdoc +%{_bindir}/ri +%{gem_dir}/gems/rdoc-%{rdoc_version} +%{gem_dir}/specifications/rdoc-%{rdoc_version}.gemspec +%{_mandir}/man1/ri* + +%files doc -f .ruby-doc.en -f .ruby-doc.ja +%doc README.md +%doc ChangeLog +%{?with_systemtap:%doc ruby-exercise.stp} +%{_datadir}/ri + +%files -n rubygem-bigdecimal +%{ruby_libdir}/bigdecimal* +%{ruby_libarchdir}/bigdecimal* +%{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version} +%{gem_dir}/gems/bigdecimal-%{bigdecimal_version} +%{gem_dir}/specifications/bigdecimal-%{bigdecimal_version}.gemspec + +%files -n rubygem-io-console +%{ruby_libdir}/io +%{ruby_libarchdir}/io/console.so +%{_libdir}/gems/%{name}/io-console-%{io_console_version} +%{gem_dir}/gems/io-console-%{io_console_version} +%{gem_dir}/specifications/io-console-%{io_console_version}.gemspec + +%files -n rubygem-json +%{ruby_libdir}/json* +%{ruby_libarchdir}/json* +%{_libdir}/gems/%{name}/json-%{json_version} +%{gem_dir}/gems/json-%{json_version} +%{gem_dir}/specifications/json-%{json_version}.gemspec + +%files -n rubygem-psych +%{ruby_libdir}/psych +%{ruby_libdir}/psych.rb +%{ruby_libarchdir}/psych.so +%{_libdir}/gems/%{name}/psych-%{psych_version} +%{gem_dir}/gems/psych-%{psych_version} +%{gem_dir}/specifications/psych-%{psych_version}.gemspec + +%files -n rubygem-bundler +%{_bindir}/bundle +%{_bindir}/bundler +%{gem_dir}/gems/bundler-%{bundler_version} +%{gem_dir}/specifications/bundler-%{bundler_version}.gemspec +%{_mandir}/man1/bundle*.1* +%{_mandir}/man5/gemfile.5* + +%files -n rubygem-minitest +%{gem_dir}/gems/minitest-%{minitest_version} +%exclude %{gem_dir}/gems/minitest-%{minitest_version}/.* +%{gem_dir}/specifications/minitest-%{minitest_version}.gemspec + +%files -n rubygem-power_assert +%{gem_dir}/gems/power_assert-%{power_assert_version} +%exclude %{gem_dir}/gems/power_assert-%{power_assert_version}/.* +%{gem_dir}/specifications/power_assert-%{power_assert_version}.gemspec + +%files -n rubygem-rake +%{_bindir}/rake +%{gem_dir}/gems/rake-%{rake_version} +%{gem_dir}/specifications/rake-%{rake_version}.gemspec +%{_mandir}/man1/rake.1* + +%files -n rubygem-rbs +%{_bindir}/rbs +%dir %{gem_dir}/gems/rbs-%{rbs_version} +%exclude %{gem_dir}/gems/rbs-%{rbs_version}/.* +%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 +%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}/core +%doc %{gem_dir}/gems/rbs-%{rbs_version}/docs +%{gem_dir}/gems/rbs-%{rbs_version}/exe +%{gem_dir}/gems/rbs-%{rbs_version}/goodcheck.yml +%{gem_dir}/gems/rbs-%{rbs_version}/lib +%{gem_dir}/gems/rbs-%{rbs_version}/schema +%{gem_dir}/gems/rbs-%{rbs_version}/sig +%{gem_dir}/gems/rbs-%{rbs_version}/stdlib +%{gem_dir}/gems/rbs-%{rbs_version}/steep +%{gem_dir}/specifications/rbs-%{rbs_version}.gemspec + +%files -n rubygem-test-unit +%{gem_dir}/gems/test-unit-%{test_unit_version} +%{gem_dir}/specifications/test-unit-%{test_unit_version}.gemspec + +%files -n rubygem-rexml +%dir %{gem_dir}/gems/rexml-%{rexml_version} +%license %{gem_dir}/gems/rexml-%{rexml_version}/LICENSE.txt +%doc %{gem_dir}/gems/rexml-%{rexml_version}/NEWS.md +%doc %{gem_dir}/gems/rexml-%{rexml_version}/doc +%{gem_dir}/gems/rexml-%{rexml_version}/lib +%{gem_dir}/specifications/rexml-%{rexml_version}.gemspec +%doc %{gem_dir}/gems/rexml-%{rexml_version}/README.md + +%files -n rubygem-rss +%dir %{gem_dir}/gems/rss-%{rss_version} +%exclude %{gem_dir}/gems/rss-%{rss_version}/.* +%license %{gem_dir}/gems/rss-%{rss_version}/LICENSE.txt +%doc %{gem_dir}/gems/rss-%{rss_version}/NEWS.md +%{gem_dir}/gems/rss-%{rss_version}/lib +%{gem_dir}/specifications/rss-%{rss_version}.gemspec +%doc %{gem_dir}/gems/rss-%{rss_version}/Gemfile +%doc %{gem_dir}/gems/rss-%{rss_version}/README.md +%doc %{gem_dir}/gems/rss-%{rss_version}/Rakefile +%doc %{gem_dir}/gems/rss-%{rss_version}/test + +%files -n rubygem-typeprof +%dir %{gem_dir}/gems/typeprof-%{typeprof_version} +%{_bindir}/typeprof +%exclude %{gem_dir}/gems/typeprof-%{typeprof_version}/.* +%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 +%{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 Jul 26 2022 Jarek Prokop - 3.0.4-141 +- Upgrade to Ruby 3.0.4. + Resolves: rhbz#2109431 + Resolves: rhbz#2110981 +- Fix double free in Regexp compilation. + Resolves: CVE-2022-28738 +- Fix buffer overrun in String-to-Float conversion. + Resolves: CVE-2022-28739 + +* Tue Oct 05 2021 Jarek Prokop - 3.0.2-140 +- Fix rubygem-irb upgrade not working due to directory -> symlink conversion. + Resolves: rhbz#2010949 + +* Tue Jul 13 2021 Jarek Prokop - 3.0.2-139 +- Upgrade to Ruby 3.0.2. + Related: rhbz#1938942 +- Fix command injection vulnerability in RDoc. (CVE-2021-31799) +- Fix FTP PASV command response can cause Net::FTP to connect to arbitrary host. + (CVE-2021-31810) +- Fix StartTLS stripping vulnerability in Net::IMAP (CVE-2021-32066) +- Fix dependencies of gems with explicit source installed from a + different source. (CVE-2020-36327) +- Pass ldflags to gem install via CONFIGURE_ARGS. + The same comment on the changelog 3.0.1-138 was wrong. + +* Mon Jun 07 2021 Jarek Prokop - 3.0.1-138 +- Upgrade to Ruby 3.0.1 by merging Fedora rawhide branch (commit: 6b2ff68). + * Add missing `rubygem-` prefix for bundled provide of 'connection_pool'. + * Pass ldflags to gem install via CONFIGURE_ARGS + * Remove IRB dependency from rubygem-rdoc. + * Fix flaky excon test suite. + * Properly support DWARF5 debug information. + Related: rhbz#1920533 + * Bundle OpenSSL into StdLib. + * Fix SEGFAULT in rubygem-shoulda-matchers test suite. + * Provide `gem.build_complete` file for binary gems. + * Re-enable test suite. + * ruby-default-gems have to depend on rubygem(io-console) due to reline. + * Fix SEGFAULT preventing rubygem-unicode to build on armv7hl. + * Add support for reworked RubyGems plugins. + * Use proper path for plugin wrappers. + * Extract RSS and REXML into separate subpackages, because they were moved from + default gems to bundled gems. + * Drop Net::Telnet and XMLRPC packages, because they were dropped from Ruby. + Resolves: rhbz#1938942 +- Fix FTBFS due to an incompatible load directive. + +* Wed Apr 07 2021 Pavel Valena - 2.7.3-136 +- Upgrade to Ruby 2.7.3. + Resolves: rhbz#1947938 +- Resolv::DNS: timeouts if multiple IPv6 name servers are given and address + contains leading zero + Resolves: rhbz#1944227 + +* Tue Oct 13 2020 Vít Ondruch - 2.7.2-135 +- Upgrade to Ruby 2.7.2. +- Avoid possible timeout errors in TestBugReporter#test_bug_reporter_add. + +* Fri Jun 26 2020 Vít Ondruch - 2.7.1-133 +- Fix `require` behavior allowing to load libraries multiple times. + Resolves: rhbz#1842989 +- Add ruby-default-gems dependency on irb. + +* Fri Jun 26 2020 Jun Aruga - 2.7.1-133 +- Ship racc binary. + Resolves: rhbz#1851388 + +* Fri May 29 2020 Jun Aruga - 2.7.1-132 +- Update to Ruby 2.7.1 by merging Fedora master branch (commit: 2981648) + * Skip unstable tests on s390x. + * Skip JIT tests in RHEL 8. + Resolves: rhbz#1817135 + +* Thu Jul 04 2019 Jun Aruga - 2.6.3-106 +- Use ffi_closure_alloc to avoid segmentation fault by libffi on aarch64. + Resolves: rhbz#1727832 +- Properly support %%prerelease in %%gemspec_ macros. + Related: rhbz#1672575 + +* Tue Jun 11 2019 Jun Aruga - 2.6.3-105 +- Update to Ruby 2.6.3 by merging Fedora master branch (commit: 1cc2a49) + * Properly generate "ruby(rubygems)" versioned dependencies. + * Extract composition of dependecy strings into helper. + * Loosen RDoc dependency. + * Upstream fix adding -C flag instead of changing directory for gem build. + * Remove obsolete Group tag + * Fix ".include =" support in openssl.cnf. + * Link IRB back to StdLib. + * Link IRB files instead of directories. + * Exclude irb.rb from ruby-libs. + Resolves: rhbz#1672575 + +* Wed Apr 17 2019 Vít Ondruch - 2.5.5-104 +- Update to Ruby 2.5.5. + * Remove Patch25: ruby-2.6.0-Update-for-tzdata-2018f.patch; subsumed + * Remove Patch11: ruby-2.6.0-Try-to-update-cert.patch; subsumed + * Remove Patch19: ruby-2.6.0-net-http-net-ftp-fix-session-resumption-with + -TLS-1.3.patch; subsumed + Resolves: rhbz#1688758 +- Don't ship .stp files when SystemTap support is disabled. + Related: rhbz#1657915 +- Fix CovScan issues. + Resolves: rhbz#1628592 + +* Fri Jan 11 2019 Jun Aruga - 2.5.3-103 +- Refresh expired certificates to fix FTBFS. + +* Tue Nov 13 2018 Vít Ondruch - 2.5.3-102 +- Fix Tokyo TZ tests. + +* Fri Oct 19 2018 Jun Aruga - 2.5.3-101 +- Update to Ruby 2.5.3. + Resolves: rhbz#1643092 + +* Mon Sep 03 2018 Vít Ondruch - 2.5.1-100 +- Properly harden package using -fstack-protector-strong. + * ruby-2.6.0-configure-fstack-protector-strong.patch + Resolves: rhbz#1624168 + +* Wed Aug 29 2018 Vít Ondruch - 2.5.1-99 +- Additional OpenSSL 1.1.1 fixes. + * ruby-2.6.0-fix-test-failure-with-TLS-1.3-maint.patch + * ruby-2.6.0-config-support-include-directive.patch + * ruby-2.6.0-use-larger-keys-for-SSL-tests.patch + Related: rhbz#1616213 + +* Tue Aug 28 2018 Jun Aruga - 2.5.1-99 +- Fix generated rdoc template issues. + * ruby-2.6.0-rdoc-6.0.1-fix-template-typo.patch + Resolves: rhbz#1612026 + +* Mon Aug 13 2018 Vít Ondruch - 2.5.1-97 +- Fix TLS 1.3 issues. + * ruby-2.6.0-fix-test-failure-with-TLS-1.3.patch + * ruby-2.6.0-net-http-net-ftp-fix-session-resumption-with-TLS-1.3.patch + Related: rhbz#1616213 + +* Sat Aug 11 2018 Troy Dawson - 2.5.1-96 +- turn off tests +- Related: bug#1614611 + +* Tue Jul 31 2018 Florian Weimer - 2.5.1-96 +- Rebuild with fixed binutils + +* Fri Jul 27 2018 Igor Gnatenko - 2.5.1-95 +- Rebuild for new binutils + +* Thu Jul 26 2018 Vít Ondruch - 2.5.1-94 +- Disable some test failing with OpenSSL 1.1.1. + +* Sat Jul 14 2018 Fedora Release Engineering - 2.5.1-94 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Thu May 10 2018 Pavel Valena - 2.5.1-93 +- Add macros to edit files lists in .gemspec + (gemspec_add_file and gemspec_remove_file). + +* Wed May 02 2018 Vít Ondruch - 2.5.1-93 +- Make %%gemspec_{add,remove}_dep modify .gemspec provided by %%setup macro. + +* Tue Apr 10 2018 Vít Ondruch - 2.5.1-92 +- Conflict requirement needs to generate dependency. +- Stop using --with-setjmp-type=setjmp on aarch64 (rhbz#1545239). + +* Thu Mar 29 2018 Pavel Valena - 2.5.1-92 +- Update to Ruby 2.5.1. + +* Mon Mar 05 2018 Vít Ondruch - 2.5.0-91 +- Don't force libraries used to build Ruby to its dependencies. +- Re-enable GMP dependency. + +* Thu Mar 01 2018 Vít Ondruch - 2.5.0-90 +- Drop GMP dependency. + +* Sat Feb 24 2018 Florian Weimer - 2.5.0-89 +- Rebuild with new LDFLAGS from redhat-rpm-config +- Use --with-setjmp-type=setjmp on aarch64 to work around gcc issue (#1545239) + +* Wed Feb 21 2018 Pavel Valena - 2.5.0-89 +- Fix: Multiple vulnerabilities in RubyGems + https://bugzilla.redhat.com/show_bug.cgi?id=1547431 + https://www.ruby-lang.org/en/news/2018/02/17/multiple-vulnerabilities-in-rubygems/ + +* Tue Feb 13 2018 Vít Ondruch - 2.5.0-89 +- Drop obsolete ldconfig scriptlets. +- Add GMP dependency. +- Use 'with' operator in RPM dependency generator. +- Add conflicts RPM generator. +- Fix thread_safe test suite segfaults. +- Fix invalid licenses. + +* Fri Feb 09 2018 Fedora Release Engineering - 2.5.0-89 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Sat Jan 20 2018 Björn Esser - 2.5.0-88 +- Rebuilt for switch to libxcrypt + +* Tue Jan 09 2018 Vít Ondruch - 2.5.0-87 +- Fix segfaults during generating of documentation. + +* Tue Jan 02 2018 Vít Ondruch - 2.5.0-86 +- Upgrade to Ruby 2.5.0. + +* Fri Oct 27 2017 Jun Aruga - 2.4.2-86 +- Add macro to remove rubypick dependency. +- Improve "with" conditional statement as inline. + +* Thu Oct 19 2017 Jun Aruga - 2.4.2-85 +- Add macros to remove systemtap, git and cmake dependencies. + +* Mon Sep 18 2017 Pavel Valena - 2.4.2-84 +- Update to Ruby 2.4.2. + +* Fri Sep 08 2017 Vít Ondruch - 2.4.1-84 +- Drop ruby-devel dependency on rubypick, which is pulled in transtitively. + +* Fri Aug 11 2017 Vít Ondruch - 2.4.1-83 +- Fix "IOError: stream closed" errors affecting Puma. +- Temporary disable checksec on PPC64LE (rhbz#1479302). + +* Thu Aug 03 2017 Fedora Release Engineering - 2.4.1-82 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Thu Jul 27 2017 Fedora Release Engineering - 2.4.1-81 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Thu Jul 20 2017 Vít Ondruch - 2.4.1-80 +- OpenSSL 1.1.0f-3 disables some weak ciphers. Adjust the package to pass + the tests suite. + +* Mon Apr 03 2017 Vít Ondruch - 2.4.1-79 +- Update to Ruby 2.4.1. + +* Thu Feb 23 2017 Vít Ondruch - 2.4.0-78 +- Fix OpenSSL symlinks. + +* Sat Feb 11 2017 Fedora Release Engineering - 2.4.0-77 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Fri Feb 03 2017 Vít Ondruch - 2.4.0-76 +- Fix GCC 7.x compatibility (rhbz#1417590). +- Use standardized multilib solution (rhbz#1412274). + +* Tue Jan 17 2017 Vít Ondruch - 2.4.0-75 +- Apply patch fixing rubygem-mongo build failures. + +* Fri Jan 13 2017 Mamoru TASAKA - 2.4.0-74 +- Rebuild again for f26-ruby24 sidetag + +* Thu Jan 12 2017 Igor Gnatenko - 2.4.0-73 +- Rebuild for readline 7.x + +* Wed Jan 11 2017 Vít Ondruch - 2.4.0-72 +- Link files into directory to avoid dir => symlink isues. + +* Mon Jan 09 2017 Vít Ondruch - 2.4.0-71 +- Add rubygem-io-console dependency for rubygem-rdoc. + +* Mon Jan 02 2017 Vít Ondruch - 2.4.0-70 +- Upgrade to Ruby 2.4.0. +- Move gemified xmlrpc into subpackage. +- Move gemified openssl into subpackage. +- Tk is removed from stdlib. +- Extend 'gem_' macros for pre-release version support. + +* Tue Nov 22 2016 Vít Ondruch - 2.3.3-61 +- Update to Ruby 2.3.3. +- Exclude json.rb from ruby-libs (rhbz#1397370). + +* Fri Nov 18 2016 Vít Ondruch - 2.3.2-60 +- Update to Ruby 2.3.2. + +* Fri Oct 21 2016 Vít Ondruch - 2.3.1-59 +- Continue to use OpenSSL 1.0 for the moment. +- Add gemspec_add_dep and gemspec_remove_dep macros. +- Harden package. + +* Wed Aug 10 2016 Vít Ondruch - 2.3.1-58 +- Workaround "an invalid stdio handle" error on PPC (rhbz#1361037). + +* Tue Jul 12 2016 Vít Ondruch - 2.3.1-57 +- Make symlinks for json gem. + +* Mon May 23 2016 Vít Ondruch - 2.3.1-56 +- Requires rubygem(json) for rubygem-rdoc (rhbz#1325022). + +* Fri Apr 29 2016 Vít Ondruch - 2.3.1-55 +- Update to Ruby 2.3.1. + +* Wed Feb 3 2016 Peter Robinson 2.3.0-54 +- Add rubypick and rubygems requires to ruby-devel to deal with BuildRequires + +* Fri Jan 15 2016 Mamoru TASAKA - 2.3.0-53 +- Backport trunk@53455 to make ruby-qt build + +* Wed Jan 06 2016 Vít Ondruch - 2.3.0-52 +- Explicitly require RDoc, since weak dependencies are ignored by default. + +* Wed Jan 06 2016 Vít Ondruch - 2.3.0-51 +- Load RubyGems prior ABRT hook to properly rescue RubyGems exceptions. + +* Mon Jan 04 2016 Vít Ondruch - 2.3.0-50 +- Upgrade to Ruby 2.3.0. +- Move gemified net-telnet into subpackage. +- Add did_you_mean subpackage. +- Add virtual provides for CCAN copylibs. +- Use weak dependencies. + +* Tue Dec 22 2015 Pavel Valena - 2.3.0-0.7.preview2 +- Add systemtap tests. + +* Mon Dec 21 2015 Vít Ondruch - 2.2.4-47 +- Update to Ruby 2.2.4. + +* Thu Dec 10 2015 Vít Ondruch - 2.2.3-46 +- Fix ABRT hook autoloading. + +* Fri Sep 04 2015 Michal Toman - 2.2.3-45 +- Add support for MIPS architecture to config.h + +* Tue Sep 01 2015 Vít Ondruch - 2.2.3-44 +- Update to Ruby 2.2.3. + +* Tue Jun 23 2015 Vít Ondruch - 2.2.2-43 +- Fix for "dh key too small" error of OpenSSL 1.0.2+. + +* Thu Jun 18 2015 Fedora Release Engineering - 2.2.2-42 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed Jun 10 2015 Vít Ondruch - 2.2.2-41 +- Fix the git BR following the git package split. + +* Mon May 04 2015 Vít Ondruch - 2.2.2-40 +- Fix upgrade path (rubygem-io-console's version was recently bumped in F21 + and makes the higher release to win). + +* Tue Apr 14 2015 Josef Stribny - 2.2.2-11 +- Bump release because of gems + +* Tue Apr 14 2015 Josef Stribny - 2.2.2-1 +- Update to Ruby 2.2.2 + +* Fri Mar 20 2015 Vít Ondruch - 2.2.1-10 +- Fix libruby.so versions in SystemTap scripts (rhbz#1202232). + +* Wed Mar 04 2015 Vít Ondruch - 2.2.1-9 +- Update to Ruby 2.2.1. + +* Sat Feb 21 2015 Till Maas - 2.2.0-8 +- Rebuilt for Fedora 23 Change + https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code + +* Thu Feb 05 2015 Vít Ondruch - 2.2.0-7 +- Fix directory ownership. + +* Wed Feb 04 2015 Vít Ondruch - 2.2.0-6 +- Initialize all load paths in operating_system.rb. + +* Tue Feb 03 2015 Vít Ondruch - 2.2.0-5 +- Make operating_system.rb more robust. +- Add RubyGems stub headers for bundled gems. + +* Thu Jan 29 2015 Vít Ondruch - 2.2.0-4 +- Add missing rubygem-test-unit dependency on rubygem-power_assert. + +* Thu Jan 15 2015 Mamoru TASAKA - 2.2.0-3 +- Bump release to avoid EVR issue on rubygem-test-unit + +* Fri Jan 02 2015 Vít Ondruch - 2.2.0-1 +- Upgrade to Ruby 2.2.0. +- Explicitly list RubyGems directories to avoid accidentaly packaged content. +- Split test-unit and power_assert gems into separate sub-packages. +- Drop libdb dependency in favor of gdbm. + +* Fri Dec 26 2014 Orion Poplwski - 2.1.5-26 +- Disbable sse2 on i668 (bug #1101811) + +* Thu Nov 20 2014 Vít Ondruch - 2.1.5-25 +- Update to Ruby 2.1.5. + +* Fri Oct 31 2014 Vít Ondruch - 2.1.4-24 +- Update to Ruby 2.1.4. +- Include only vendor directories, not their content (rhbz#1114071). +- Fix "invalid regex" warning for non-rubygem packages (rhbz#1154067). +- Use load macro introduced in RPM 4.12. + +* Mon Aug 18 2014 Fedora Release Engineering +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Tue Jun 24 2014 Peter Robinson 2.1.2-23 +- Fix FTBFS +- Specify tcl/tk 8.6 +- Add upstream patch to build with libffi 3.1 + +* Sun Jun 08 2014 Fedora Release Engineering +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Wed May 21 2014 Jaroslav Škarvada +- Rebuilt for https://fedoraproject.org/wiki/Changes/f21tcl86 + +* Tue May 20 2014 Josef Stribny - 2.1.2-21 +- Update to Ruby 2.1.2 + +* Tue May 06 2014 Vít Ondruch - 2.1.1-20 +- Remove useless exclude (rhbz#1065897). +- Extract load macro into external file and include it. +- Kill bundled certificates. + +* Wed Apr 23 2014 Vít Ondruch - 2.1.1-19 +- Correctly expand $(prefix) in some Makefiles, e.g. eruby. + +* Tue Apr 08 2014 Vít Ondruch - 2.1.1-18 +- Update to Ruby 2.1.1. +- Revert regression of Hash#reject. + +* Mon Mar 03 2014 Vít Ondruch - 2.1.0-19 +- Add RPM dependency generators for RubyGems. + +* Mon Feb 10 2014 Josef Stribny - 2.1.0-19 +- Don't link cert.pem explicitely + +* Wed Jan 15 2014 Vít Ondruch - 2.1.0-18 +- Don't generate documentation on unexpected places. +- Detect if rubygems are running under rpmbuild and install gem binary + extensions into appropriate place. +- Add support for ppc64le arch (rhbz#1053263). +- Re-enable some test cases, which are passing now with Kernel 3.12.8+. +- Backport fix for floating point issues on i686. + +* Thu Jan 02 2014 Vít Ondruch - 2.1.0-17 +- Upgrade to Ruby 2.1.0. +- Move RPM macros into /usr/lib/rpm/macros.d directory. +- Allow MD5 in OpenSSL for tests. + +* Tue Jul 30 2013 Vít Ondruch - 2.0.0.247-15 +- Move Psych symlinks to vendor dir, to prevent F18 -> F19 upgrade issues + (rhbz#988490). + +* Mon Jul 15 2013 Vít Ondruch - 2.0.0.247-14 +- Add forgotten psych.rb link into rubygem-psych to fix "private method `load' + called for Psych:Moduler" error (rhbz#979133). + +* Thu Jul 11 2013 Vít Ondruch - 2.0.0.247-13 +- Fixes multilib conlicts of .gemspec files. +- Make symlinks for psych gem to ruby stdlib dirs (rhbz#979133). +- Use system-wide cert.pem. + +* Thu Jul 04 2013 Vít Ondruch - 2.0.0.247-12 +- Fix RubyGems search paths when building gems with native extension + (rhbz#979133). + +* Tue Jul 02 2013 Vít Ondruch - 2.0.0.247-11 +- Fix RubyGems version. + +* Tue Jul 02 2013 Vít Ondruch - 2.0.0.247-10 +- Better support for build without configuration (rhbz#977941). + +* Mon Jul 01 2013 Vít Ondruch - 2.0.0.247-9 +- Update to Ruby 2.0.0-p247 (rhbz#979605). +- Fix CVE-2013-4073. +- Fix for wrong makefiles created by mkmf (rhbz#921650). +- Add support for ABRT autoloading. + +* Fri May 17 2013 Vít Ondruch - 2.0.0.195-8 +- Update to Ruby 2.0.0-p195 (rhbz#917374). +- Fix object taint bypassing in DL and Fiddle (CVE-2013-2065). +- Fix build against OpenSSL with enabled ECC curves. +- Add aarch64 support (rhbz#926463). + +* Fri Apr 19 2013 Vít Ondruch - 2.0.0.0-7 +- Macro definition moved into macros.ruby and macros.rubygems files. +- Added filtering macros. +- Filter automatically generated provides of private libraries (rhbz#947408). + +* Fri Mar 22 2013 Vít Ondruch - 2.0.0.0-6 +- Fix RbConfig::CONFIG['exec_prefix'] returns empty string (rhbz#924851). + +* Thu Mar 21 2013 Vít Ondruch - 2.0.0.0-5 +- Make Ruby buildable without rubypick. +- Prevent random test failures. + +* Fri Mar 08 2013 Mamoru TASAKA - 2.0.0.0-4 +- Don't mark rpm config file as %%config (fpc#259) + +* Tue Mar 05 2013 Vít Ondruch - 2.0.0.0-3 +- Avoid "method redefined;" warnings due to modified operating_system.rb. +- Fix strange paths created during build of binary gems. + +* Mon Feb 25 2013 Vít Ondruch - 2.0.0.0-2 +- Prevent squash of %%gem_install with following line. + +* Mon Feb 25 2013 Vít Ondruch - 2.0.0.0-1 +- Update to Ruby 2.0.0-p0. +- Change %%{ruby_extdir} to %%{ruby_extdir_mri} in preparation for better + JRuby support. + +* Mon Feb 25 2013 Mamoru TASAKA - 2.0.0.0-0.3.r39387 +- Move test-unit.gemspec to -libs subpackage for now because rubygems + 2.0.0 does not create this + +* Fri Feb 22 2013 Vít Ondruch - 2.0.0.0-0.2.r39387 +- Fix issues with wrong value of Rubygem's shebang introduced in r39267. + +* Fri Feb 22 2013 Vít Ondruch - 2.0.0.0-0.1.r39387 +- Upgrade to Ruby 2.0.0 (r39387). +- Introduce %%gem_install macro. +- Build against libdb instead of libdb4 (rhbz#894022). +- Move native extensions from exts to ruby directory. +- Enable most of the PPC test suite. +- Change ruby(abi) -> ruby(release). +- Rename ruby executable to ruby-mri, to be prepared for RubyPick. +- Add ruby(runtime_executable) virtual provide, which is later used + by RubyPick. +- RDoc now depends on JSON. +- Try to make -doc subpackage noarch again, since the new RDoc should resolve + the arch dependent issues (https://github.com/rdoc/rdoc/issues/71). +- Enable SystemTap support. +- Add TapSet for Ruby. +- Split Psych into rubygem-psych subpackage. + +* Mon Feb 11 2013 Mamoru TASAKA - 1.9.3.385-28 +- Update to 1.9.3 p385 + +* Sat Jan 19 2013 Mamoru TASAKA - 1.9.3.374-27 +- Update to 1.9.3 p374 +- Fix provided variables in pkgconfig (bug 789532: + Vít Ondruch ) + +* Fri Jan 18 2013 Mamoru TASAKA - 1.9.3.362-26 +- Provide non-versioned pkgconfig file (bug 789532) +- Use db5 on F-19 (bug 894022) + +* Wed Jan 16 2013 Mamoru TASAKA - 1.9.3.362-25 +- Backport fix for the upstream PR7629, save the proc made from the given block + (bug 895173) + +* Wed Jan 2 2013 Mamoru TASAKA - 1.9.3.362-24 +- Update to 1.9.3.362 + +* Mon Dec 03 2012 Jaromir Capik - 1.9.3.327-23 +- Skipping test_parse.rb (fails on ARM at line 787) +- http://bugs.ruby-lang.org/issues/6899 + +* Sun Nov 11 2012 Mamoru TASAKA - 1.9.3.327-23 +- Skip test_str_crypt (on rawhide) for now (upstream bug 7312) + +* Sat Nov 10 2012 Mamoru TASAKA - 1.9.3.327-22 +- Ignore some network related tests + +* Sat Nov 10 2012 Mamoru TASAKA - 1.9.3.327-21 +- Update to 1.9.3.327 +- Fix Hash-flooding DoS vulnerability on MurmurHash function + (CVE-2012-5371) + +* Sat Oct 13 2012 Mamoru TASAKA - 1.9.3.286-19 +- Update to 1.9.3 p286 +- Don't create files when NUL-containing path name is passed + (bug 865940, CVE-2012-4522) + +* Thu Oct 04 2012 Mamoru Tasaka - 1.9.3.194-18 +- Patch from trunk for CVE-2012-4464, CVE-2012-4466 + +* Thu Sep 06 2012 Vít Ondruch - 1.9.3.194-17 +- Split documentation into -doc subpackage (rhbz#854418). + +* Tue Aug 14 2012 Vít Ondruch - 1.9.3.194-16 +- Revert the dependency of ruby-libs on rubygems (rhbz#845011, rhbz#847482). + +* Wed Aug 01 2012 Vít Ondruch - 1.9.3.194-15 +- ruby-libs must require rubygems (rhbz#845011). + +* Sat Jul 21 2012 Fedora Release Engineering - 1.9.3.194-14 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jun 11 2012 Bohuslav Kabrda - 1.9.3.194-13 +- Make the bigdecimal gem a runtime dependency of Ruby. + +* Mon Jun 11 2012 Bohuslav Kabrda - 1.9.3.194-12 +- Make symlinks for bigdecimal and io-console gems to ruby stdlib dirs (RHBZ 829209). + +* Tue May 29 2012 Bohuslav Kabrda - 1.9.3.194-11 +- Fix license to contain Public Domain. +- macros.ruby now contains unexpanded macros. + +* Sun Apr 22 2012 Mamoru Tasaka - 1.9.3.194-10.1 +- Bump release + +* Fri Apr 20 2012 Vít Ondruch - 1.9.3.194-1 +- Update to Ruby 1.9.3-p194. + +* Mon Apr 09 2012 Karsten Hopp 1.9.3.125-3 +- disable check on ppc(64), RH bugzilla 803698 + +* Wed Feb 29 2012 Peter Robinson - 1.9.3.125-2 +- Temporarily disable make check on ARM until it's fixed upstream. Tracked in RHBZ 789410 + +* Mon Feb 20 2012 Vít Ondruch - 1.9.3.125-1 +- Upgrade to Ruby 1.9.3-p125. + +* Sun Jan 29 2012 Mamoru Tasaka - 1.9.3.0-7 +- Make mkmf.rb verbose by default + +* Thu Jan 26 2012 Vít Ondruch - 1.9.3.0-6 +- Relax dependencies to allow external updates of bundled gems. + +* Wed Jan 18 2012 Vít Ondruch - 1.9.3.0-5 +- Initial release of Ruby 1.9.3. +- Add rubygems dependency on io-console for user interactions. +- Gems license clarification. + +* Tue Jan 17 2012 Vít Ondruch - 1.9.3.0-4 +- Bundled gems moved into dedicated directories and subpackages. +- Create and own RubyGems directories for binary extensions. +- Fix build with GCC 4.7. + +* Mon Jan 16 2012 Vít Ondruch - 1.9.3.0-3 +- Fix RHEL build. +- Fixed directory ownership. +- Verose build output. + +* Sun Jan 15 2012 Vít Ondruch - 1.9.3.0-2 +- Install RubyGems outside of Ruby directory structure. +- RubyGems has not its own -devel subpackage. +- Enhanced macros.ruby and macros.rubygems. +- All tests are green now (bkabrda). + +* Sat Jan 14 2012 Vít Ondruch - 1.9.3.0-1 +- Initial package + +* Sat Jan 14 2012 Fedora Release Engineering - 1.8.7.357-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Thu Dec 29 2011 Mamoru Tasaka - 1.8.7.357-1 +- Update to 1.8.7p357 +- Randomize hash on process startup (CVE-2011-4815, bug 750564) + +* Fri Dec 23 2011 Dennis Gilmore - 1.8.7.352-2 +- dont normalise arm cpus to arm +- there is something weird about how ruby choses where to put bits + +* Thu Nov 17 2011 Mamoru Tasaka - 1.8.7.352-3 +- F-17: kill gdbm support for now due to licensing compatibility issue + +* Sat Oct 1 2011 Mamoru Tasaka - 1.8.7.352-2 +- F-17: rebuild against new gdbm + +* Sat Jul 16 2011 Mamoru Tasaka - 1.8.7.352-1 +- Update to 1.8.7 p352 +- CVE-2011-2686 is fixed in this version (bug 722415) +- Update ext/tk to the latest git +- Remove duplicate path entry (bug 718695) + +* Thu Jul 14 2011 Mamoru Tasaka - 1.8.7.334-4 +- Once fix FTBFS (bug 716021) + +* Mon Jul 11 2011 Dennis Gilmore - 1.8.7.334-3 +- normalise arm cpus to arm + +* Mon May 30 2011 Mamoru Tasaka - 1.8.7.334-2 +- Own %%{_normalized_cpu}-%%{_target_os} directory (bug 708816) + +* Sat Feb 19 2011 Mamoru Tasaka - 1.8.7.334-1 +- Update to 1.8.7 p334 + +* Wed Feb 09 2011 Fedora Release Engineering - 1.8.7.330-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Sun Jan 02 2011 Dennis Gilmore - 1.8.7.330-2 +- nomalise the 32 bit sparc archs to sparc + +* Sun Dec 26 2010 Mamoru Tasaka - 1.8.7.330-1 +- Update to 1.8.7 p330 +- ext/tk updated to the newest header + +* Thu Nov 4 2010 Mamoru Tasaka - 1.8.7.302-2 +- Avoid multilib conflict on -libs subpackage (bug 649174) + +* Mon Aug 23 2010 Mamoru Tasaka - 1.8.7.302-1 +- Update to 1.8.7.302 +- CVE-2010-0541 (bug 587731) is fixed in this version +- Update ext/tk to the latest head + +* Mon Aug 2 2010 Mamoru Tasaka - 1.8.7.299-5 +- More cleanup of spec file, expecially for rpmlint issue +- build ri files in %%build + +* Mon Jul 26 2010 Mamoru Tasaka - 1.8.7.299-4 +- Cleanup spec file +- Make -irb, -rdoc subpackage noarch +- Make dependencies between arch-dependent subpackages isa specific +- Improve sample documentation gathering + +* Mon Jul 12 2010 Mohammed Morsi - 1.8.7.299-3 +- updated packaged based on feedback (from mtasaka) +- added comments to all patches / sources +- obsoleted ruby-mode, as it's now provided by the emacs package itself +- readded missing documentation +- various small compatability/regression fixes + +* Tue Jul 06 2010 Mohammed Morsi - 1.8.7.299-2 +- readded bits to pull tk package from upstream source branch +- removed unecessary .tk.old dir +- renamed macros which may cause confusion, removed unused ones + +* Thu Jun 24 2010 Mohammed Morsi - 1.8.7.299-1 +- integrate more of jmeyering's and mtaska's feedback +- removed emacs bits that are now shipped with the emacs package +- various patch and spec cleanup +- rebased to ruby 1.8.7 patch 299, removed patches no longer needed: + ruby-1.8.7-openssl-1.0.patch, ruby-1.8.7-rb_gc_guard_ptr-optimization.patch + +* Wed Jun 23 2010 Mohammed Morsi - 1.8.7.249-5 +- Various fixes + +* Wed Jun 23 2010 Mohammed Morsi - 1.8.7.249-4 +- Fixed incorrect paths in 1.8.7 rpm + +* Tue Jun 22 2010 Mohammed Morsi - 1.8.7.249-3 +- Integrated Jim Meyering's feedback and changes in to: +- remove trailing blanks +- placate rpmlint +- ruby_* definitions: do not use trailing slashes in directory names +- _normalized_cpu: simplify definition + +* Mon Jun 21 2010 Mohammed Morsi - 1.8.7.249-2 +- Integrate mtasaka's feedback and changes +- patch101 ruby_1_8_7-rb_gc_guard_ptr-optimization.patch + +* Tue Jun 15 2010 Mohammed Morsi - 1.8.7.249-1 +- Initial Ruby 1.8.7 specfile + +* Wed May 19 2010 Mamoru Tasaka - 1.8.6.399-5 +- Retry for bug 559158, Simplify the OpenSSL::Digest class + pull more change commits from ruby_1_8 branch + +* Mon May 17 2010 Mamoru Tasaka - 1.8.6.399-4 +- Patch36 (ruby-1.8.x-RHASH_SIZE-rb_hash_lookup-def.patch) + also backport rb_hash_lookup definition (bug 592936) + +* Thu May 13 2010 Mamoru Tasaka - 1.8.6.399-3 +- ruby-1.8.x-null-class-must-be-Qnil.patch (bug 530407) +- Recreate some patches using upstream svn when available, and + add some comments for patches + +* Tue May 11 2010 Mamoru Tasaka - 1.8.6.399-2 +- tcltk: Give up using potentially unmaintained ruby_1_8_6 branch + and instead completely replace with ruby_1_8 branch head + (at this time, using rev 27738) + (seems to fix 560053, 590503) +- Fix Japanese encoding strings under ruby-tcltk/ext/tk/sample/ + +* Tue Apr 27 2010 Mamoru Tasaka - 1.8.6.399-1 +- Update to 1.8.6 p 399 (bug 579675) +- Patch to fix gc bug causing open4 crash (bug 580993) + +* Fri Mar 12 2010 Mamoru Tasaka - 1.8.6.388-9 +- F-14: rebuild against new gdbm + +* Thu Jan 28 2010 Mamoru Tasaka +- Once revert the previous change (patch34) + +* Wed Jan 27 2010 Jeroen van Meeuwen - 1.8.6.388-8 +- Backport openssl/digest functions providing digest and hexdigest functions + directly in OpenSSL::Digest.methods +- Make sure that Red Hat people version their changelog entries +- This is actually release #1, but now needs to be release #7 + +* Mon Jan 18 2010 Akira TAGOH - 1.8.6.388-1 +- Add conditional for RHEL. + +* Wed Jan 13 2010 Mamoru Tasaka - 1.8.6.383-6 +- CVE-2009-4492 ruby WEBrick log escape sequence (bug 554485) + +* Wed Dec 9 2009 Mamoru Tasaka - 1.8.6.383-5 +- Change mkmf.rb to use LIBRUBYARG_SHARED so that have_library() works + without libruby-static.a (bug 428384) +- And move libruby-static.a to -static subpackage + +* Thu Oct 29 2009 Mamoru Tasaka - 1.8.6.383-4 +- Use bison to regenerate parse.c to keep the original format of error + messages (bug 530275 comment 4) + +* Sun Oct 25 2009 Mamoru Tasaka - 1.8.6.383-3 +- Patch so that irb saves its history (bug 518584, ruby issue 1556) + +* Sat Oct 24 2009 Mamoru Tasaka - 1.8.6.383-2 +- Update to 1.8.6 patchlevel 383 (bug 520063) + +* Wed Oct 14 2009 Mamoru Tasaka - 1.8.6.369-5 +- Much better idea for Patch31 provided by Akira TAGOH + +* Wed Oct 14 2009 Mamoru Tasaka - 1.8.6.369-4 +- Fix the search path of ri command for ri manuals installed with gem + (bug 528787) + +* Wed Aug 26 2009 Tomas Mraz - 1.8.6.369-3 +- Rebuild against new openssl + +* Thu Jul 23 2009 Mamoru Tasaka - 1.8.6.369-2 +- Make sure that readline.so is linked against readline 5 because + Ruby is under GPLv2 + +* Sat Jun 20 2009 Jeroen van Meeuwen - 1.8.6.369-1 +- New patchlevel fixing CVE-2009-1904 +- Fix directory on ARM (#506233, Kedar Sovani) + +* Sun May 31 2009 Jeroen van Meeuwen - 1.8.6.368-1 +- New upstream release (p368) + +* Sat Apr 11 2009 Mamoru Tasaka - 1.8.6.287-8 +- Merge Review fix (#226381) + +* Wed Mar 18 2009 Jeroen van Meeuwen - 1.8.6.287-7 +- Fix regression in CVE-2008-3790 (#485383) + +* Mon Mar 16 2009 Mamoru Tasaka - 1.8.6.287-6 +- Again use -O2 optimization level +- i586 should search i386-linux directory (on <= F-11) + +* Thu Mar 05 2009 Jeroen van Meeuwen - 1.8.6.287-5 +- Rebuild for gcc4.4 + +* Fri Feb 27 2009 Jeroen van Meeuwen - 1.8.6.287-3 +- CVE-2008-5189: CGI header injection. + +* Wed Oct 8 2008 Akira TAGOH - 1.8.6.287-2 +- CVE-2008-3790: DoS vulnerability in the REXML module. + +* Sat Aug 23 2008 Akira TAGOH - 1.8.6.287-1 +- New upstream release. +- Security fixes. + - CVE-2008-3655: Ruby does not properly restrict access to critical + variables and methods at various safe levels. + - CVE-2008-3656: DoS vulnerability in WEBrick. + - CVE-2008-3657: Lack of taintness check in dl. + - CVE-2008-1447: DNS spoofing vulnerability in resolv.rb. + - CVE-2008-3443: Memory allocation failure in Ruby regex engine. +- Remove the unnecessary backported patches. + +* Thu Jul 10 2008 Tom "spot" Callaway - 1.8.6.230-5 +- rebuild against db4-4.7 + +* Tue Jul 1 2008 Akira TAGOH - 1.8.6.230-4 +- Backported from upstream SVN to fix a segfault issue with Array#fill. + +* Mon Jun 30 2008 Akira TAGOH - 1.8.6.230-3 +- Backported from upstream SVN to fix a segfault issue. (#452825) +- Backported from upstream SVN to fix an integer overflow in rb_ary_fill. + +* Wed Jun 25 2008 Akira TAGOH - 1.8.6.230-2 +- Fix a segfault issue. (#452810) + +* Tue Jun 24 2008 Akira TAGOH - 1.8.6.230-1 +- New upstream release. +- Security fixes. (#452295) + - CVE-2008-1891: WEBrick CGI source disclosure. + - CVE-2008-2662: Integer overflow in rb_str_buf_append(). + - CVE-2008-2663: Integer overflow in rb_ary_store(). + - CVE-2008-2664: Unsafe use of alloca in rb_str_format(). + - CVE-2008-2725: Integer overflow in rb_ary_splice(). + - CVE-2008-2726: Integer overflow in rb_ary_splice(). +- ruby-1.8.6.111-CVE-2007-5162.patch: removed. +- Build ruby-mode package for all archtectures. + +* Tue Mar 4 2008 Akira TAGOH - 1.8.6.114-1 +- Security fix for CVE-2008-1145. +- Improve a spec file. (#226381) + - Correct License tag. + - Fix a timestamp issue. + - Own a arch-specific directory. + +* Tue Feb 19 2008 Fedora Release Engineering - 1.8.6.111-9 +- Autorebuild for GCC 4.3 + +* Tue Feb 19 2008 Akira TAGOH - 1.8.6.111-8 +- Rebuild for gcc-4.3. + +* Tue Jan 15 2008 Akira TAGOH - 1.8.6.111-7 +- Revert the change of libruby-static.a. (#428384) + +* Fri Jan 11 2008 Akira TAGOH - 1.8.6.111-6 +- Fix an unnecessary replacement for shebang. (#426835) + +* Fri Jan 4 2008 Akira TAGOH - 1.8.6.111-5 +- Rebuild. + +* Fri Dec 28 2007 Akira TAGOH - 1.8.6.111-4 +- Clean up again. + +* Fri Dec 21 2007 Akira TAGOH - 1.8.6.111-3 +- Clean up the spec file. +- Remove ruby-man-1.4.6 stuff. this is entirely the out-dated document. + this could be replaced by ri. +- Disable the static library building. + +* Tue Dec 04 2007 Release Engineering - 1.8.6.111-2 + - Rebuild for openssl bump + +* Wed Oct 31 2007 Akira TAGOH +- Fix the dead link. + +* Mon Oct 29 2007 Akira TAGOH - 1.8.6.111-1 +- New upstream release. +- ruby-1.8.6.111-CVE-2007-5162.patch: Update a bit with backporting the changes + at trunk to enable the fix without any modifications on the users' scripts. + Note that Net::HTTP#enable_post_connection_check isn't available anymore. + If you want to disable this post-check, you should give OpenSSL::SSL::VERIFY_NONE + to Net::HTTP#verify_mode= instead of. + +* Mon Oct 15 2007 Akira TAGOH - 1.8.6.110-2 +- Enable pthread support for ppc too. (#201452) +- Fix unexpected dependencies appears in ruby-libs. (#253325) + +* Wed Oct 10 2007 Akira TAGOH - 1.8.6.110-1 +- New upstream release. + - ruby-r12567.patch: removed. +- ruby-1.8.6-CVE-2007-5162.patch: security fix for Net::HTTP that is + insufficient verification of SSL certificate. + +* Thu Aug 23 2007 Akira TAGOH - 1.8.6.36-4 +- Rebuild + +* Fri Aug 10 2007 Akira TAGOH +- Update License tag. + +* Mon Jun 25 2007 Akira TAGOH - 1.8.6.36-3 +- ruby-r12567.patch: backport patch from upstream svn to get rid of + the unnecessary declarations. (#245446) + +* Wed Jun 20 2007 Akira TAGOH - 1.8.6.36-2 +- New upstream release. + - Fix Etc::getgrgid to get the correct gid as requested. (#236647) + +* Wed Mar 28 2007 Akira TAGOH - 1.8.6-2 +- Fix search path breakage. (#234029) + +* Thu Mar 15 2007 Akira TAGOH - 1.8.6-1 +- New upstream release. +- clean up a spec file. + +* Tue Feb 13 2007 Akira TAGOH - 1.8.5.12-2 +- Rebuild + +* Mon Feb 5 2007 Akira TAGOH - 1.8.5.12-1 +- New upstream release. + +* Mon Dec 11 2006 Akira TAGOH - 1.8.5.2-1 +- security fix release. + +* Fri Oct 27 2006 Akira TAGOH - 1.8.5-4 +- security fix release. +- ruby-1.8.5-cgi-CVE-2006-5467.patch: fix a CGI multipart parsing bug that + causes the denial of service. (#212396) + +* Sun Oct 01 2006 Jesse Keating - 1.8.5-3 +- rebuilt for unwind info generation, broken in gcc-4.1.1-21 + +* Tue Sep 26 2006 Akira TAGOH - 1.8.5-2 +- fixed rbconfig.rb to refer to DESTDIR for sitearchdir. (#207311) + +* Mon Aug 28 2006 Akira TAGOH - 1.8.5-1 +- New upstream release. +- removed the unnecessary patches: + - ruby-1.8.4-no-eaccess.patch + - ruby-1.8.4-64bit-pack.patch + - ruby-1.8.4-fix-insecure-dir-operation.patch + - ruby-1.8.4-fix-insecure-regexp-modification.patch + - ruby-1.8.4-fix-alias-safe-level.patch +- build with --enable-pthread except on ppc. +- ruby-1.8.5-hash-memory-leak.patch: backported from CVS to fix a memory leak + on Hash. [ruby-talk:211233] + +* Mon Aug 7 2006 Akira TAGOH - 1.8.4-12 +- owns sitearchdir. (#201208) + +* Thu Jul 20 2006 Akira TAGOH - 1.8.4-11 +- security fixes [CVE-2006-3694] + - ruby-1.8.4-fix-insecure-dir-operation.patch: + - ruby-1.8.4-fix-insecure-regexp-modification.patch: fixed the insecure + operations in the certain safe-level restrictions. (#199538) + - ruby-1.8.4-fix-alias-safe-level.patch: fixed to not bypass the certain + safe-level restrictions. (#199543) + +* Wed Jul 12 2006 Jesse Keating - 1.8.4-10.fc6.1 +- rebuild + +* Mon Jun 19 2006 Akira TAGOH - 1.8.4-10 +- fixed the wrong file list again. moved tcltk library into ruby-tcltk. + (#195872) + +* Thu Jun 8 2006 Akira TAGOH - 1.8.4-8 +- ruby-deprecated-sitelib-search-path.patch: correct the order of search path. + +* Wed Jun 7 2006 Akira TAGOH - 1.8.4-7 +- exclude ppc64 to make ruby-mode package. right now emacs.ppc64 isn't provided + and buildsys became much stricter. +- ruby-deprecated-sitelib-search-path.patch: applied to add more search path + for backward compatiblity. +- added byacc to BuildReq. (#194161) + +* Wed May 17 2006 Akira TAGOH - 1.8.4-6 +- ruby-deprecated-search-path.patch: added the deprecated installation paths + to the search path for the backward compatibility. +- added a Provides: ruby(abi) to ruby-libs. +- ruby-1.8.4-64bit-pack.patch: backport patch from upstream to fix unpack("l") + not working on 64bit arch and integer overflow on template "w". (#189350) +- updated License tag to be more comfortable, and with a pointer to get more + details, like Python package does. (#179933) +- clean up. + +* Wed Apr 19 2006 Akira TAGOH +- ruby-rubyprefix.patch: moved all arch-independent modules under /usr/lib/ruby + and keep arch-dependent modules under /usr/lib64/ruby for 64bit archs. + so 'rubylibdir', 'sitelibdir' and 'sitedir' in Config::CONFIG points to + the kind of /usr/lib/ruby now. (#184199) + +* Mon Apr 17 2006 Akira TAGOH - 1.8.4-4 +- correct sitelibdir. (#184198) + +* Fri Feb 10 2006 Jesse Keating - 1.8.4-3.2 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 1.8.4-3.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Mon Feb 6 2006 Akira TAGOH - 1.8.4-3 +- ruby-1.8.4-no-eaccess.patch: backported from ruby CVS to avoid conflict + between newer glibc. (#179835) + +* Wed Jan 4 2006 Akira TAGOH - 1.8.4-2 +- ruby-tcltk-multilib.patch: fixed a typo. + +* Tue Dec 27 2005 Akira TAGOH - 1.8.4-1 +- New upstream release. + - fixed a missing return statement. (#140833) + - fixed an use of uninitialized variable. (#144890) + +* Fri Dec 16 2005 Akira TAGOH - 1.8.4-0.4.preview2 +- updates to 1.8.4-preview2. +- renamed the packages to ruby-* (#175765) + - irb -> ruby-irb + - rdoc -> ruby-rdoc + - ri -> ruby-ri +- added tcl-devel and tk-devel into BuildRequires. + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Thu Nov 10 2005 Akira TAGOH - 1.8.4-0.3.preview1 +- rebuilt against the latest openssl. + +* Tue Nov 1 2005 Akira TAGOH - 1.8.4-0.2.preview1 +- build-deps libX11-devel instead of xorg-x11-devel. + +* Mon Oct 31 2005 Akira TAGOH - 1.8.4-0.1.preview1 +- New upstream release. +- ruby-1.8.2-strscan-memset.patch: removed because it's no longer needed. + +* Tue Oct 4 2005 Akira TAGOH - 1.8.3-4 +- moved the documents from ruby-libs to ruby-docs, which contains the arch + specific thing and to be multilib support. (#168826) + +* Mon Oct 3 2005 Akira TAGOH - 1.8.3-3 +- fixed the wrong file list. the external library for tcl/tk was included + in ruby-libs unexpectedly. + +* Mon Sep 26 2005 Akira TAGOH - 1.8.3-2 +- ruby-multilib.patch: added another chunk for multilib. (#169127) + +* Wed Sep 21 2005 Akira TAGOH - 1.8.3-1 +- New upstream release. +- Build-Requires xorg-x11-devel instead of XFree86-devel. +- ruby-multilib.patch: applied for only 64-bit archs. +- ruby-1.8.2-xmlrpc-CAN-2005-1992.patch: removed. it has already been in upstream. + +* Tue Jun 21 2005 Akira TAGOH - 1.8.2-9 +- ruby-1.8.2-xmlrpc-CAN-2005-1992.patch: fixed the arbitrary command execution + on XMLRPC server. (#161096) + +* Thu Jun 16 2005 Akira TAGOH - 1.8.2-8 +- ruby-1.8.2-tcltk-multilib.patch: applied to get tcltklib.so built. (#160194) + +* Thu Apr 7 2005 Akira TAGOH - 1.8.2-7 +- ruby-1.8.2-deadcode.patch: removed the dead code from the source. (#146108) +- make sure that all documentation files in ruby-docs are the world- + readable. (#147279) + +* Tue Mar 22 2005 Akira TAGOH - 1.8.2-6 +- ruby-1.8.2-strscan-memset.patch: fixed an wrong usage of memset(3). + +* Tue Mar 15 2005 Akira TAGOH - 1.8.2-5 +- rebuilt + +* Tue Jan 25 2005 Akira TAGOH - 1.8.2-4 +- fixed the wrong generation of file manifest. (#146055) +- spec file clean up. + +* Mon Jan 24 2005 Akira TAGOH - 1.8.2-3 +- separated out to rdoc package. +- make the dependency of irb for rdoc. (#144708) + +* Wed Jan 12 2005 Tim Waugh - 1.8.2-2 +- Rebuilt for new readline. + +* Wed Jan 5 2005 Akira TAGOH - 1.8.2-1 +- New upstream release. +- ruby-1.8.1-ia64-stack-limit.patch: removed - it's no longer needed. +- ruby-1.8.1-cgi_session_perms.patch: likewise. +- ruby-1.8.1-cgi-dos.patch: likewise. +- generated Ruby interactive documentation - senarated package. + it's now provided as ri package. (#141806) + +* Thu Nov 11 2004 Jeff Johnson 1.8.1-10 +- rebuild against db-4.3.21. + +* Wed Nov 10 2004 Akira TAGOH - 1.8.1-9 +- ruby-1.8.1-cgi-dos.patch: security fix [CAN-2004-0983] +- ruby-1.8.1-cgi_session_perms.patch: security fix [CAN-2004-0755] + +* Fri Oct 29 2004 Akira TAGOH - 1.8.1-8 +- added openssl-devel and db4-devel into BuildRequires (#137479) + +* Wed Oct 6 2004 Akira TAGOH - 1.8.1-7 +- require emacs-common instead of emacs. + +* Wed Jun 23 2004 Akira TAGOH 1.8.1-4 +- updated the documentation. + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Tue Mar 02 2004 Elliot Lee +- rebuilt + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Wed Feb 04 2004 Akira TAGOH 1.8.1-1 +- New upstream release. +- don't use any optimization for ia64 to avoid the build failure. +- ruby-1.8.1-ia64-stack-limit.patch: applied to fix SystemStackError when the optimization is disabled. + +* Sat Dec 13 2003 Jeff Johnson 1.8.0-3 +- rebuild against db-4.2.52. + +* Thu Sep 25 2003 Jeff Johnson 1.8.0-2 +- rebuild against db-4.2.42. + +* Tue Aug 5 2003 Akira TAGOH 1.8.0-1 +- New upstream release. + +* Thu Jul 24 2003 Akira TAGOH 1.6.8-9.1 +- rebuilt + +* Thu Jul 24 2003 Akira TAGOH 1.6.8-9 +- ruby-1.6.8-castnode.patch: handling the nodes with correct cast. + use this patch now instead of ruby-1.6.8-fix-x86_64.patch. + +* Fri Jul 04 2003 Akira TAGOH 1.6.8-8 +- rebuilt + +* Fri Jul 04 2003 Akira TAGOH 1.6.8-7 +- fix the gcc warnings. (#82192) +- ruby-1.6.8-fix-x86_64.patch: correct a patch. + NOTE: DON'T USE THIS PATCH FOR BIG ENDIAN ARCHITECTURE. +- ruby-1.6.7-long2int.patch: removed. + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Fri Feb 7 2003 Jens Petersen - 1.6.8-5 +- rebuild against ucs4 tcltk + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Wed Jan 22 2003 Akira TAGOH 1.6.8-3 +- ruby-1.6.8-multilib.patch: applied to fix the search path issue on x86_64 + +* Tue Jan 21 2003 Akira TAGOH 1.6.8-2 +- ruby-1.6.8-require.patch: applied to fix the search bug in require. +- don't apply long2int patch to s390 and s390x. it doesn't work. + +* Wed Jan 15 2003 Akira TAGOH 1.6.8-1 +- New upstream release. +- removed some patches. it's no longer needed. + - ruby-1.6.7-100.patch + - ruby-1.6.7-101.patch + - ruby-1.6.7-102.patch + - ruby-1.6.7-103.patch + - 801_extmk.rb-shellwords.patch + - 801_mkmf.rb-shellwords.patch + - 804_parse.y-new-bison.patch + - 805_uri-bugfix.patch + - ruby-1.6.6-900_XXX_strtod.patch + - ruby-1.6.7-sux0rs.patch + - ruby-1.6.7-libobj.patch + +* Wed Jan 15 2003 Jens Petersen 1.6.7-14 +- rebuild to update tcltk deps + +* Mon Dec 16 2002 Elliot Lee 1.6.7-13 +- Remove ExcludeArch: x86_64 +- Fix x86_64 ruby with long2int.patch (ruby was assuming that sizeof(long) + == sizeof(int). The patch does not fix the source of the problem, just + makes it a non-issue.) +- _smp_mflags + +* Tue Dec 10 2002 Tim Powers 1.6.7-12 +- rebuild to fix broken tcltk deps + +* Tue Oct 22 2002 Akira TAGOH 1.6.7-11 +- use %%configure macro instead of configure script. +- use the latest config.{sub,guess}. +- get archname from rbconfig.rb for %%dir +- applied some patches from Debian: + - 801_extmk.rb-shellwords.patch: use Shellwords + - 801_mkmf.rb-shellwords.patch: mkmf.rb creates bad Makefile. the Makefile + links libruby.a to the target. + - 803_sample-fix-shbang.patch: all sample codes should be + s|/usr/local/bin|/usr/bin|g + - 804_parse.y-new-bison.patch: fix syntax warning. + - 805_uri-bugfix.patch: uri.rb could not handle correctly broken mailto-uri. +- add ExcludeArch x86_64 temporarily to fix Bug#74581. Right now ruby can't be + built on x86_64. + +* Tue Aug 27 2002 Akira TAGOH 1.6.7-10 +- moved sitedir to /usr/lib/ruby/site_ruby again according as our perl and + python. +- ruby-1.6.7-resolv1.patch, ruby-1.6.7-resolv2.patch: applied to fix 'Too many + open files - "/etc/resolv.conf"' issue. (Bug#64830) + +* Thu Jul 18 2002 Akira TAGOH 1.6.7-9 +- add the owned directory. + +* Fri Jul 12 2002 Akira TAGOH 1.6.7-8 +- fix typo. + +* Thu Jul 04 2002 Akira TAGOH 1.6.7-7 +- removed the ruby-mode-xemacs because it's merged to the xemacs sumo. + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Wed Jun 19 2002 Akira TAGOH 1.6.7-5 +- fix the stripped binary. +- use the appropriate macros. + +* Sun May 26 2002 Tim Powers +- automated rebuild + +* Thu May 23 2002 Akira TAGOH 1.6.7-3 +- ruby-1.6.7-libobj.patch: applied to fix autoconf2.53 error. + +* Mon Mar 18 2002 Akira TAGOH 1.6.7-2 +- ruby-man-1.4.6-jp.tar.bz2: removed. +- ruby-refm-rdp-1.4.7-ja-html.tar.bz2: uses it instead of. +- ruby-1.6.7-500-marshal-proc.patch, ruby-1.6.7-501-class-var.patch: + removed. +- ruby-1.6.7-100.patch: applied a bug fix patch. + (ruby-dev#16274: patch for 'wm state') + (PR#206ja: SEGV handle EXIT) +- ruby-1.6.7-101.patch: applied a bug fix patch. + (ruby-list#34313: singleton should not be Marshal.dump'ed) + (ruby-dev#16411: block local var) +- ruby-1.6.7-102.patch: applied a bug fix patch. + (handling multibyte chars is partially broken) +- ruby-1.6.7-103.patch: applied a bug fix patch. + (ruby-dev#16462: preserve reference for GC, but link should be cut) + +* Fri Mar 8 2002 Akira TAGOH 1.6.7-1 +- New upstream release. +- ruby-1.6.6-100.patch, ruby-1.6.6-501-ruby-mode.patch: + removed. these patches no longer should be needed. +- ruby-1.6.7-500-marshal-proc.patch: applied a fix patch. + (ruby-dev#16178: Marshal::dump should call Proc#call.) +- ruby-1.6.7-501-class-var.patch: applied a fix patch. + (ruby-talk#35157: class vars broken in 1.6.7) + +* Wed Feb 27 2002 Akira TAGOH 1.6.6-5 +- Disable alpha because nothing is xemacs for alpha now. + +* Tue Feb 5 2002 Akira TAGOH 1.6.6-3 +- Fixed the duplicate files. + +* Tue Feb 5 2002 Akira TAGOH 1.6.6-2 +- Fixed the missing %%defattr + +* Fri Feb 1 2002 Akira TAGOH 1.6.6-1 +- New upstream release. +- Applied bug fix patches: + - ruby-1.6.6-501-ruby-mode.patch: ruby-talk#30479: disables font-lock + coloring. + - ruby-1.6.6-100.patch: ruby-talk#30203: Ruby 1.6.6 bug and fix + ruby-list#33047: regex bug + PR#230: problem with -d in 1.6.6 +- Added ruby-mode and ruby-mode-xemacs packages. +- Ruby works fine for ia64. so re-enable to build with ia64. + (probably it should be worked for alpha) + +* Wed Jan 09 2002 Tim Powers +- automated rebuild + +* Thu Jul 19 2001 Bernhard Rosenkraenzer 1.6.4-2 +- Remove Japanese description and summaries; they belong in specspo and + break rpm +- Clean up specfile +- Mark language specific files (README.jp) as such +- bzip2 sources +- rename the libruby package to ruby-libs for consistency +- Exclude ia64 (doesn't build - the code doesn't seem to be 64-bit clean + [has been excluded on alpha forever]) + +* Tue Jul 17 2001 Akira TAGOH 1.6.4-1 +- rebuild for Red Hat 7.2 + +* Mon Jun 04 2001 akira yamada +- upgrade to nwe upstream version 1.6.4. + +* Mon Apr 02 2001 akira yamada +- applied patch: + - fixed method cache bug. etc. (Patch103, Patch104) + +* Tue Mar 27 2001 akira yamada +- applied patch: + - fixed marshal for bignum bug. + - fixed scope of constant variables bug. + +* Tue Mar 20 2001 akira yamada +- upgraded to new upstream version 1.6.3. + +* Fri Feb 09 2001 akira yamada +- fixed bad group for libruby. +- Applied patch: upgraded to cvs version (2001-02-08): + fixed minor bugs. + +* Thu Jan 18 2001 akira yamada +- Applied patch: upgraded to cvs version (2001-01-15): + fixed minor bugs(e.g. ruby makes extention librares too large...). + +* Wed Jan 10 2001 akira yamada +- Applied patch: upgraded to cvs version (2001-01-09): + fixed minor bugs. + +* Sat Dec 30 2000 akira yamada +- Applied bug fix patch. + +* Mon Dec 25 2000 akira yamada +- Updated to new upstream version 1.6.2. + +* Fri Dec 22 2000 akira yamada +- Removed ruby_cvs.2000122019.patch, added ruby_cvs.2000122215.patch + (upgraded ruby to latest cvs version, 1.6.2-preview4). + +* Wed Dec 20 2000 akira yamada +- Removed ruby_cvs.2000121413.patch, added ruby_cvs.2000122019.patch + (upgraded ruby to latest cvs version). +- new package: libruby + +* Thu Dec 14 2000 akira yamada +- Removed ruby_cvs.2000101901.patch, added ruby_cvs.2000121413.patch + (upgraded ruby to latest cvs version). +- Removed ruby-dev.11262.patch, ruby-dev.11265.patch, + and ruby-dev.11268.patch (included into above patch). + +* Sun Nov 12 2000 MACHINO, Satoshi 1.6.1-0vl9 +- build on gcc-2.95.3 + +* Thu Oct 19 2000 akira yamada +- Added ruby-dev.11268.patch. + +* Thu Oct 19 2000 akira yamada +- Removed ruby_cvs.2000101117.patch and added ruby_cvs.2000101901.patch + (upgraded ruby to latest cvs version). +- Added ruby-dev.11262.patch. +- Added ruby-dev.11265.patch. + +* Wed Oct 11 2000 akira yamada +- Removed ruby_cvs.2000100313.patch and added ruby_cvs.2000101117.patch + (upgraded ruby to latest cvs version). + +* Mon Oct 09 2000 akira yamada +- Removed ruby_cvs.2000100313.patch and added ruby_cvs.2000100313.patch + (upgraded ruby to latest cvs version). + +* Tue Oct 03 2000 akira yamada +- Removed ruby_cvs.2000100218.patch and added ruby_cvs.2000100313.patch + (upgraded ruby to latest cvs version). + +* Mon Oct 02 2000 akira yamada +- Removed ruby_cvs.2000092718.patch and added ruby_cvs.2000100218.patch + (upgraded ruby to latest cvs version). + +* Wed Sep 27 2000 akira yamada +- Updated to upstream version 1.6.1. +- Removed ruby_cvs.2000082901.patch and added ruby_cvs.2000092718.patch + (upgraded ruby to latest cvs version). + +* Tue Aug 29 2000 akira yamada +- Updated to version 1.4.6. +- removed ruby-dev.10123.patch(included into ruby-1.4.6). +- Added ruby_cvs.2000082901.patch(upgraded ruby to latest cvs version). + +* Tue Jun 27 2000 akira yamada +- Updated manuals to version 1.4.5. + +* Sun Jun 25 2000 akira yamada +- Added ruby-dev.10123.patch. + +* Sat Jun 24 2000 akira yamada +- Updated to version 1.4.5. +- Removed ruby_cvs.2000062401.patch(included into ruby-1.4.5). + +* Thu Jun 22 2000 akira yamada +- Updated to version 1.4.4(06/22/2000 CVS). +- Removed ruby-dev.10054.patch(included into ruby_cvs.patch). + +* Thu Jun 22 2000 akira yamada +- Renamed to ruby_cvs20000620.patch from ruby_cvs.patch. + +* Tue Jun 20 2000 akira yamada +- Updated to version 1.4.4(06/20/2000 CVS). +- Removed ruby-list.23190.patch(included into ruby_cvs.patch). +- Added ruby-dev.10054.patch. + +* Thu Jun 15 2000 akira yamada +- Updated to version 1.4.4(06/12/2000 CVS). +- Added manuals and FAQs. +- Split into ruby, ruby-devel, ruby-tcltk, ruby-docs, irb. + +* Tue Jun 13 2000 Mitsuo Hamada +- Updated to version 1.4.4 + +* Wed Dec 08 1999 Atsushi Yamagata +- Updated to version 1.4.3 + +* Mon Sep 20 1999 Atsushi Yamagata +- Updated to version 1.4.2 (Sep 18) + +* Fri Sep 17 1999 Atsushi Yamagata +- Updated to version 1.4.2 + +* Tue Aug 17 1999 Atsushi Yamagata +- Updated to version 1.4.0 + +* Fri Jul 23 1999 Atsushi Yamagata +- 2nd release +- Updated to version 1.2.6(15 Jul 1999) +- striped %%{prefix}/bin/ruby + +* Mon Jun 28 1999 Atsushi Yamagata +- Updated to version 1.2.6(21 Jun 1999) + +* Wed Apr 14 1999 Atsushi Yamagata +- Updated to version 1.2.5 + +* Fri Apr 09 1999 Atsushi Yamagata +- Updated to version 1.2.4 + +* Fri Dec 25 1998 Toru Hoshina +- Version up to 1.2 stable. + +* Fri Nov 27 1998 Toru Hoshina +- Version up to 1.1c9. + +* Thu Nov 19 1998 Toru Hoshina +- Version up to 1.1c8, however it appear short life :-P + +* Fri Nov 13 1998 Toru Hoshina +- Version up. + +* Tue Sep 22 1998 Toru Hoshina +- To make a libruby.so. + +* Mon Sep 21 1998 Toru Hoshina +- Modified SPEC in order to install libruby.a so that it should be used by + another ruby entention. +- 2nd release. + +* Mon Mar 9 1998 Shoichi OZAWA +- Added a powerPC arch part. Thanks, MURATA Nobuhiro diff --git a/rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch b/rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch new file mode 100644 index 0000000..433d03e --- /dev/null +++ b/rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch @@ -0,0 +1,44 @@ +From bb0f57aeb4de36a3b2b8b8cb01d25b32af0357d3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADt=20Ondruch?= +Date: Wed, 27 Oct 2021 16:28:24 +0200 +Subject: [PATCH] Provide distinguished name which will be correctly parsed. + +It seems that since ruby openssl 2.1.0 [[1]], the distinguished name +submitted to `OpenSSL::X509::Name.parse` is not correctly parsed if it +does not contain the first slash: + +~~~ +$ ruby -v +ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux] + +$ gem list | grep openssl +openssl (default: 2.2.0) + +$ irb -r openssl +irb(main):001:0> OpenSSL::X509::Name.parse("CN=nobody/DC=example").to_s(OpenSSL::X509::Name::ONELINE) +=> "CN = nobody/DC=example" +irb(main):002:0> OpenSSL::X509::Name.parse("/CN=nobody/DC=example").to_s(OpenSSL::X509::Name::ONELINE) +=> "CN = nobody, DC = example" +~~~ + +[1]: https://github.com/ruby/openssl/commit/19c67cd10c57f3ab7b13966c36431ebc3fdd653b +--- + lib/rubygems/security.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb +index c80639af6d..12de141f36 100644 +--- a/lib/rubygems/security.rb ++++ b/lib/rubygems/security.rb +@@ -510,7 +510,7 @@ def self.email_to_name(email_address) + + dcs = dcs.split '.' + +- name = "CN=#{cn}/#{dcs.map {|dc| "DC=#{dc}" }.join '/'}" ++ name = "/CN=#{cn}/#{dcs.map {|dc| "DC=#{dc}" }.join '/'}" + + OpenSSL::X509::Name.parse name + end +-- +2.32.0 + diff --git a/rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch b/rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch new file mode 100644 index 0000000..d5a0673 --- /dev/null +++ b/rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch @@ -0,0 +1,261 @@ +From e80e7a3d0b3d72f7af7286b935702b3fab117008 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +Date: Wed, 8 Dec 2021 21:12:24 +0100 +Subject: [PATCH 1/5] More explicit require + +This class does not use `rubygems/deprecate`. It uses +`rubygems/version`, which in turn uses `rubygems/deprecate`. Make this +explicit. +--- + lib/rubygems/requirement.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb +index d2e28fab5b4..9edd6aa7d3c 100644 +--- a/lib/rubygems/requirement.rb ++++ b/lib/rubygems/requirement.rb +@@ -1,5 +1,5 @@ + # frozen_string_literal: true +-require_relative "deprecate" ++require_relative "version" + + ## + # A Requirement is a set of one or more version restrictions. It supports a + +From 4e46dcc17ee5cabbde43b8a34063b8ab042536f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +Date: Wed, 8 Dec 2021 21:17:30 +0100 +Subject: [PATCH 2/5] Remove ineffective autoloads + +These files are loaded on startup unconditionally, so we can require +them relatively when needed. +--- + lib/rubygems.rb | 4 +--- + lib/rubygems/specification.rb | 2 ++ + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/lib/rubygems.rb b/lib/rubygems.rb +index f803e47628e..b8747409304 100644 +--- a/lib/rubygems.rb ++++ b/lib/rubygems.rb +@@ -1310,19 +1310,17 @@ def default_gem_load_paths + autoload :Licenses, File.expand_path('rubygems/util/licenses', __dir__) + autoload :NameTuple, File.expand_path('rubygems/name_tuple', __dir__) + autoload :PathSupport, File.expand_path('rubygems/path_support', __dir__) +- autoload :Platform, File.expand_path('rubygems/platform', __dir__) + autoload :RequestSet, File.expand_path('rubygems/request_set', __dir__) +- autoload :Requirement, File.expand_path('rubygems/requirement', __dir__) + autoload :Resolver, File.expand_path('rubygems/resolver', __dir__) + autoload :Source, File.expand_path('rubygems/source', __dir__) + autoload :SourceList, File.expand_path('rubygems/source_list', __dir__) + autoload :SpecFetcher, File.expand_path('rubygems/spec_fetcher', __dir__) +- autoload :Specification, File.expand_path('rubygems/specification', __dir__) + autoload :Util, File.expand_path('rubygems/util', __dir__) + autoload :Version, File.expand_path('rubygems/version', __dir__) + end + + require_relative 'rubygems/exceptions' ++require_relative 'rubygems/specification' + + # REFACTOR: This should be pulled out into some kind of hacks file. + begin +diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb +index d3b96491a28..dc5e5ba0138 100644 +--- a/lib/rubygems/specification.rb ++++ b/lib/rubygems/specification.rb +@@ -9,6 +9,8 @@ + require_relative 'deprecate' + require_relative 'basic_specification' + require_relative 'stub_specification' ++require_relative 'platform' ++require_relative 'requirement' + require_relative 'specification_policy' + require_relative 'util/list' + + +From 96b6b3e04e8e4fec17f63079a0caf999a2709d71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +Date: Wed, 8 Dec 2021 21:45:16 +0100 +Subject: [PATCH 3/5] Load `operating_system.rb` customizations before setting + up default gems + +It's very common for packagers to configure gem paths in this file, for +example, `Gem.default_dir`. Also, setting up default gems requires these +paths to be set, so that we know which default gems need to be setup. + +If we setup default gems before loading `operatin_system.rb` +customizations, the wrong default gems will be setup. + +Unfortunately, default gems loaded by `operating_system.rb` can't be +upgraded if we do this, but it seems much of a smaller issue. I wasn't +even fully sure it was the right thing to do when I added that, and it +was not the culprit of the end user issue that led to making that +change. +--- + lib/rubygems.rb | 32 ++++++++++++++++---------------- + test/rubygems/test_rubygems.rb | 23 +++++++++++++++++++++++ + 2 files changed, 39 insertions(+), 16 deletions(-) + +diff --git a/lib/rubygems.rb b/lib/rubygems.rb +index b8747409304..11474b6554c 100644 +--- a/lib/rubygems.rb ++++ b/lib/rubygems.rb +@@ -1323,22 +1323,6 @@ def default_gem_load_paths + require_relative 'rubygems/specification' + + # REFACTOR: This should be pulled out into some kind of hacks file. +-begin +- ## +- # Defaults the Ruby implementation wants to provide for RubyGems +- +- require "rubygems/defaults/#{RUBY_ENGINE}" +-rescue LoadError +-end +- +-## +-# Loads the default specs. +-Gem::Specification.load_defaults +- +-require_relative 'rubygems/core_ext/kernel_gem' +-require_relative 'rubygems/core_ext/kernel_require' +-require_relative 'rubygems/core_ext/kernel_warn' +- + begin + ## + # Defaults the operating system (or packager) wants to provide for RubyGems. +@@ -1354,3 +1338,19 @@ def default_gem_load_paths + "the problem and ask for help." + raise e.class, msg + end ++ ++begin ++ ## ++ # Defaults the Ruby implementation wants to provide for RubyGems ++ ++ require "rubygems/defaults/#{RUBY_ENGINE}" ++rescue LoadError ++end ++ ++## ++# Loads the default specs. ++Gem::Specification.load_defaults ++ ++require_relative 'rubygems/core_ext/kernel_gem' ++require_relative 'rubygems/core_ext/kernel_require' ++require_relative 'rubygems/core_ext/kernel_warn' +diff --git a/test/rubygems/test_rubygems.rb b/test/rubygems/test_rubygems.rb +index 493b9fdf4a3..fa77a299322 100644 +--- a/test/rubygems/test_rubygems.rb ++++ b/test/rubygems/test_rubygems.rb +@@ -22,6 +22,29 @@ def test_operating_system_other_exceptions + "the problem and ask for help." + end + ++ def test_operating_system_customizing_default_dir ++ pend "does not apply to truffleruby" if RUBY_ENGINE == 'truffleruby' ++ pend "loads a custom defaults/jruby file that gets in the middle" if RUBY_ENGINE == 'jruby' ++ ++ # On a non existing default dir, there should be no gems ++ ++ path = util_install_operating_system_rb <<-RUBY ++ module Gem ++ def self.default_dir ++ File.expand_path("foo") ++ end ++ end ++ RUBY ++ ++ output = Gem::Util.popen( ++ *ruby_with_rubygems_and_fake_operating_system_in_load_path(path), ++ '-e', ++ "require \"rubygems\"; puts Gem::Specification.stubs.map(&:full_name)", ++ {:err => [:child, :out]} ++ ).strip ++ assert_empty output ++ end ++ + private + + def util_install_operating_system_rb(content) + +From 52cfdd14fd1213a97aac12f01177e27779de9035 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +Date: Thu, 9 Dec 2021 06:08:31 +0100 +Subject: [PATCH 4/5] Install default fiddle on latest ruby on specs that need + it + +Otherwise first OS customizations load and activate that fiddle version, +but then when we change to `Gem.default_dir`, that fiddle version is no +longer there. +--- + spec/bundler/commands/clean_spec.rb | 2 +- + spec/bundler/install/gems/standalone_spec.rb | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb +index ffaf22dbb32..65231b35fac 100644 +--- a/spec/bundler/commands/clean_spec.rb ++++ b/spec/bundler/commands/clean_spec.rb +@@ -638,7 +638,7 @@ def should_not_have_gems(*gems) + s.executables = "irb" + end + +- realworld_system_gems "fiddle --version 1.0.6", "tsort --version 0.1.0", "pathname --version 0.1.0", "set --version 1.0.1" ++ realworld_system_gems "fiddle --version 1.0.8", "tsort --version 0.1.0", "pathname --version 0.1.0", "set --version 1.0.1" + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" +diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb +index db16a1b0e13..faefda25f45 100644 +--- a/spec/bundler/install/gems/standalone_spec.rb ++++ b/spec/bundler/install/gems/standalone_spec.rb +@@ -113,7 +113,7 @@ + skip "does not work on rubygems versions where `--install_dir` doesn't respect --default" unless Gem::Installer.for_spec(loaded_gemspec, :install_dir => "/foo").default_spec_file == "/foo/specifications/default/bundler-#{Bundler::VERSION}.gemspec" # Since rubygems 3.2.0.rc.2 + skip "does not work on old rubies because the realworld gems that need to be installed don't support them" if RUBY_VERSION < "2.7.0" + +- realworld_system_gems "fiddle --version 1.0.6", "tsort --version 0.1.0" ++ realworld_system_gems "fiddle --version 1.0.8", "tsort --version 0.1.0" + + necessary_system_gems = ["optparse --version 0.1.1", "psych --version 3.3.2", "yaml --version 0.1.1", "logger --version 1.4.3", "etc --version 1.2.0", "stringio --version 3.0.0"] + necessary_system_gems += ["shellwords --version 0.1.0", "base64 --version 0.1.0", "resolv --version 0.2.1"] if Gem.rubygems_version < Gem::Version.new("3.3.3.a") + +From c6a9c81021092c9157f5616a2bbe1323411a5bf8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +Date: Thu, 9 Dec 2021 12:46:23 +0100 +Subject: [PATCH 5/5] Resolve symlinks in LOAD_PATH when activating + pre-required default gems + +Some double load issues were reported a while ago by OS packagers where +if a gem has been required before rubygems, and then after, rubygems +require would cause a double load. + +We avoid this issue by activating the corresponding gem if we detect +that a file in the default LOAD_PATH that belongs to a default gem has +already been required when rubygems registers default gems. + +However, the fix does not take into account that the default LOAD_PATH +could potentially include symlinks. This change fixes the same double +load issue described above but for situations where the default +LOAD_PATH includes symlinks. +--- + lib/rubygems.rb | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/lib/rubygems.rb b/lib/rubygems.rb +index 11474b6554c..b7dda38d522 100644 +--- a/lib/rubygems.rb ++++ b/lib/rubygems.rb +@@ -1293,7 +1293,12 @@ def already_loaded?(file) + end + + def default_gem_load_paths +- @default_gem_load_paths ||= $LOAD_PATH[load_path_insert_index..-1] ++ @default_gem_load_paths ||= $LOAD_PATH[load_path_insert_index..-1].map do |lp| ++ expanded = File.expand_path(lp) ++ next expanded unless File.exist?(expanded) ++ ++ File.realpath(expanded) ++ end + end + end + diff --git a/rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch b/rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch new file mode 100644 index 0000000..b405b5f --- /dev/null +++ b/rubygems-3.3.1-Fix-compatibility-with-OpenSSL3.0.patch @@ -0,0 +1,105 @@ +From 558128594de16add5b453833fd5b043a24c1b7f5 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Wed, 22 Dec 2021 01:38:47 +0900 +Subject: [PATCH 1/3] Use OpenSSL::PKey::EC.generate to generate ECC key pairs + +When Ruby/OpenSSL is built against OpenSSL 3.0, OpenSSL::PKey::PKey +instances are immutable and OpenSSL::PKey::EC#generate_key cannot work +because it modifies the receiver. + +OpenSSL::PKey::EC.generate is available on Ruby 2.4 (Ruby/OpenSSL 2.0) +or later. +--- + lib/rubygems/security.rb | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb +index 22759972070..2aa07381d69 100644 +--- a/lib/rubygems/security.rb ++++ b/lib/rubygems/security.rb +@@ -490,9 +490,13 @@ def self.create_key(algorithm) + when 'rsa' + OpenSSL::PKey::RSA.new(RSA_DSA_KEY_LENGTH) + when 'ec' +- domain_key = OpenSSL::PKey::EC.new(EC_NAME) +- domain_key.generate_key +- domain_key ++ if RUBY_VERSION >= "2.4.0" ++ OpenSSL::PKey::EC.generate(EC_NAME) ++ else ++ domain_key = OpenSSL::PKey::EC.new(EC_NAME) ++ domain_key.generate_key ++ domain_key ++ end + else + raise Gem::Security::Exception, + "#{algorithm} algorithm not found. RSA, DSA, and EC algorithms are supported." + +From 60067d4f09b7fb9c23bed38e91acfde0293f29a0 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Wed, 22 Dec 2021 01:49:05 +0900 +Subject: [PATCH 2/3] Use OpenSSL::X509::Certificate#check_private_key + +The method is for the exact purpose: to check that an instance of +OpenSSL::PKey::PKey matches the public key in a certificate. +--- + lib/rubygems/security.rb | 2 +- + lib/rubygems/security/policy.rb | 4 +--- + 2 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb +index 2aa07381d69..2906819bd34 100644 +--- a/lib/rubygems/security.rb ++++ b/lib/rubygems/security.rb +@@ -530,7 +530,7 @@ def self.re_sign(expired_certificate, private_key, age = ONE_YEAR, + raise Gem::Security::Exception, + "incorrect signing key for re-signing " + + "#{expired_certificate.subject}" unless +- expired_certificate.public_key.to_pem == get_public_key(private_key).to_pem ++ expired_certificate.check_private_key(private_key) + + unless expired_certificate.subject.to_s == + expired_certificate.issuer.to_s +diff --git a/lib/rubygems/security/policy.rb b/lib/rubygems/security/policy.rb +index 3c3cb647ee3..06eae073f4a 100644 +--- a/lib/rubygems/security/policy.rb ++++ b/lib/rubygems/security/policy.rb +@@ -115,11 +115,9 @@ def check_key(signer, key) + raise Gem::Security::Exception, 'missing key or signature' + end + +- public_key = Gem::Security.get_public_key(key) +- + raise Gem::Security::Exception, + "certificate #{signer.subject} does not match the signing key" unless +- signer.public_key.to_pem == public_key.to_pem ++ signer.check_private_key(key) + + true + end + +From 6819e3d0fadc10ce8d10919402eedb730cf0e43f Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Wed, 22 Dec 2021 01:54:10 +0900 +Subject: [PATCH 3/3] Fix Gem::Security.get_public_key on OpenSSL 3.0 + +Ruby/OpenSSL 2.2 added OpenSSL::PKey::PKey#public_to_der for serializing +only the public key components contained in the instance. This works +for all possible key types. +--- + lib/rubygems/security.rb | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb +index 2906819bd34..f21c1756422 100644 +--- a/lib/rubygems/security.rb ++++ b/lib/rubygems/security.rb +@@ -424,6 +424,8 @@ def self.create_cert(subject, key, age = ONE_YEAR, extensions = EXTENSIONS, + # Gets the right public key from a PKey instance + + def self.get_public_key(key) ++ # Ruby 3.0 (Ruby/OpenSSL 2.2) or later ++ return OpenSSL::PKey.read(key.public_to_der) if key.respond_to?(:public_to_der) + return key.public_key unless key.is_a?(OpenSSL::PKey::EC) + + ec_key = OpenSSL::PKey::EC.new(key.group.curve_name) diff --git a/rubygems.attr b/rubygems.attr new file mode 100644 index 0000000..5793bf7 --- /dev/null +++ b/rubygems.attr @@ -0,0 +1,6 @@ +%__rubygems_requires %{_rpmconfigdir}/rubygems.req +%__rubygems_provides %{_rpmconfigdir}/rubygems.prov +%__rubygems_conflicts %{_rpmconfigdir}/rubygems.con +# In non-gem packages, the %%{gem_name} macro is not available and the macro +# stays unexpanded which leads to "invalid regex" error (rhbz#1154067). +%__rubygems_path ^%{?gem_name:%{gem_spec}}%{!?gem_name:this_should_never_match_anything}$ diff --git a/rubygems.con b/rubygems.con new file mode 100644 index 0000000..1a99ed0 --- /dev/null +++ b/rubygems.con @@ -0,0 +1,52 @@ +#!/usr/bin/ruby + +require 'rubygems/package' + +module RubyGemsReq + module Helpers + # Keep only '!=' requirements. + def self.conflicts(requirements) + conflicts = requirements.select {|r| r.first == '!='} + end + + # Converts Gem::Requirement into array of requirements strings compatible + # with RPM .spec file. + def self.requirement_versions_to_rpm(requirement) + self.conflicts(requirement.requirements).map do |op, version| + version == Gem::Version.new(0) ? "" : "= #{version}" + end + end + end + + # Report conflicting gem dependencies including their version. + def self.gem_depenencies(specification) + specification.runtime_dependencies.each do |dependency| + conflict_strings = Helpers::requirement_versions_to_rpm(dependency.requirement).map do |requirement| + requirement_string = "rubygem(#{dependency.name}) #{requirement}" + end + if conflict_strings.length > 0 + conflict_string = conflict_strings.join(' with ') + conflict_string.prepend('(').concat(')') if conflict_strings.length > 1 + puts conflict_string + end + end + end + + # Reports all conflicts specified by all provided .gemspec files. + def self.conflicts + while filename = gets + filename.strip! + begin + specification = Gem::Specification.load filename + + gem_depenencies(specification) + rescue => e + # Ignore all errors. + end + end + end +end + +if __FILE__ == $0 + RubyGemsReq::conflicts +end diff --git a/rubygems.prov b/rubygems.prov new file mode 100644 index 0000000..f23ec3f --- /dev/null +++ b/rubygems.prov @@ -0,0 +1,36 @@ +#!/usr/bin/ruby + +require 'rubygems/package' + +module RubyGemsProv + module Helpers + # If there is some prelease version files, such as rc1 (i.e. non-numeric + # field), prepend this field by tilde instead of dot. + def self.normalize_prerelease(version) + if version.prerelease? + prerelease = version.version.sub /^#{version.release}\./, '' + "#{version.release}~#{prerelease}" + else + version.release + end + end + end + + # Reports all functionality gem provides. + def self.provides + while filename = gets + filename.strip! + begin + specification = Gem::Specification.load filename + + puts "rubygem(#{specification.name}) = #{Helpers::normalize_prerelease(specification.version)}" + rescue => e + # Ignore all errors. + end + end + end +end + +if __FILE__ == $0 + RubyGemsProv::provides +end diff --git a/rubygems.req b/rubygems.req new file mode 100644 index 0000000..38e4a9c --- /dev/null +++ b/rubygems.req @@ -0,0 +1,88 @@ +#!/usr/bin/ruby + +require 'rubygems/package' + +module RubyGemsReq + module Helpers + # Expands '~>' and '!=' gem requirements. + def self.expand_requirement(requirements) + requirements.inject([]) do |output, r| + output.concat case r.first + when '~>' + expand_pessimistic_requirement(r) + when '!=' + # If there is only the conflict requirement, we still need to depend + # on the specified gem. + if requirements.size == 1 + Gem::Requirement.default.requirements + else + [] + end + else + [r] + end + end.reject {|r| r.empty? } + end + + # Expands the pessimistic version operator '~>' into equivalent '>=' and + # '<' pair. + def self.expand_pessimistic_requirement(requirement) + next_version = Gem::Version.create(requirement.last).bump + return ['>=', requirement.last], ['<', next_version] + end + + # Converts Gem::Requirement into array of requirements strings compatible + # with RPM .spec file. + def self.requirement_versions_to_rpm(requirement) + self.expand_requirement(requirement.requirements).map do |op, version| + version == Gem::Version.new(0) ? "" : " #{op} #{version}" + end + end + + # Compose dependency together with its requirements in RPM rich dependency + # string. + def self.compose_dependency_string(name, requirements) + dependency_strings = requirements.map { |requirement| name + requirement } + dependency_string = dependency_strings.join(' with ') + dependency_string.prepend('(').concat(')') if dependency_strings.length > 1 + dependency_string + end + end + + # Report RubyGems dependency, versioned if required. + def self.rubygems_dependency(specification) + dependency_name = "ruby(rubygems)" + requirements = Helpers::requirement_versions_to_rpm(specification.required_rubygems_version) + + puts Helpers::compose_dependency_string(dependency_name, requirements) + end + + # Report all gem dependencies including their version. + def self.gem_depenencies(specification) + specification.runtime_dependencies.each do |dependency| + dependency_name = "rubygem(#{dependency.name})" + requirements = Helpers::requirement_versions_to_rpm(dependency.requirement) + + puts Helpers::compose_dependency_string(dependency_name, requirements) + end + end + + # Reports all requirements specified by all provided .gemspec files. + def self.requires + while filename = gets + filename.strip! + begin + specification = Gem::Specification.load filename + + rubygems_dependency(specification) + gem_depenencies(specification) + rescue => e + # Ignore all errors. + end + end + end +end + +if __FILE__ == $0 + RubyGemsReq::requires +end diff --git a/sources b/sources new file mode 100644 index 0000000..7479778 --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA1 (ruby-3.0.4.tar.xz) = 14461adca874d42a06a11851029dec877d9d28de diff --git a/test_abrt.rb b/test_abrt.rb new file mode 100644 index 0000000..6d110ba --- /dev/null +++ b/test_abrt.rb @@ -0,0 +1,7 @@ +if !!$LOADED_FEATURES.detect { |f| f =~ /abrt\.rb/ } + exit true +else + puts 'ERROR: ABRT hook was not loaded.' + + exit false +end diff --git a/test_systemtap.rb b/test_systemtap.rb new file mode 100644 index 0000000..5784e2d --- /dev/null +++ b/test_systemtap.rb @@ -0,0 +1,65 @@ +require 'set' + +LIBRUBY_SO = 'libruby.so' +PROBES_D = 'probes.d' + +# These probes are excluded by VM_COLLECT_USAGE_DETAILS ifdef. +EXCLUDE_PROBES = Set.new %w(insn insn__operand) + +## Detect SystemTap section headers presence + +stap_headers = [ + '\.stapsdt\.base', + '\.note\.stapsdt' +] + +header_regexp = %r{ (#{stap_headers.join('|')}) } + +section_headers = `readelf -S "#{LIBRUBY_SO}"` +detected_stap_headers = section_headers.scan(header_regexp).flatten + +# Assume there are both headers until this is proven wrong ;) +unless detected_stap_headers.size == 2 + puts 'ERROR: SystemTap (DTrace) headers were not detected in resulting library.' + exit false +end + +## Find if every declared probe is propagated to resulting library + +# Colect probes specified in probes.d file. +probes_declared = [] + +File.open(PROBES_D) do |file| + file.each_line do |line| + if probe = line[/probe (\S+)\(.*\);/, 1] + probes_declared << probe + end + end +end + +probes_declared = Set.new probes_declared + +unless EXCLUDE_PROBES.subset? probes_declared + puts 'ERROR: Change in SystemTap (DTrace) probes definition file detected.' + exit false +end + +probes_declared -= EXCLUDE_PROBES + +# Detect probes in resulting library. +get_probes_detected = %r{ +^\s*Provider:\s+ruby,\s+Name:\s+(\S+),\s+.*$ +} + +probes_detected = `eu-readelf -n "#{LIBRUBY_SO}"` + +probes_detected = Set.new probes_detected.scan(get_probes_detected).flatten + +# Both sets must be equal, otherwise something is wrong. +unless probes_declared == probes_detected + puts 'ERROR: SystemTap (DTrace) probes were not correctly propagated into resulting library.' + puts " Undetected probes: #{(probes_declared - probes_detected).sort.join(', ')}\n", + " Additional detected probes: #{(probes_detected - probes_declared).sort.join(', ')}" + + exit false +end