diff --git a/CVE-2019-16163.patch b/CVE-2019-16163.patch deleted file mode 100644 index c93d459..0000000 --- a/CVE-2019-16163.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 4097828d7cc87589864fecf452f2cd46c5f37180 Mon Sep 17 00:00:00 2001 -From: "K.Kosako" -Date: Mon, 29 Jul 2019 12:52:56 +0900 -Subject: [PATCH] fix #147: Stack Exhaustion Problem caused by some parsing - functions in regcomp.c making recursive calls to themselves. - ---- - regparse.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/regparse.c b/regparse.c -index f7177db..c07fccd 100644 ---- a/regparse.c -+++ b/regparse.c -@@ -4568,6 +4568,7 @@ parse_char_class(Node** np, Node** asc_np, OnigToken* tok, UChar** src, UChar* e - env->parse_depth++; - if (env->parse_depth > ParseDepthLimit) - return ONIGERR_PARSE_DEPTH_LIMIT_OVER; -+ - prev_cc = asc_prev_cc = (CClassNode* )NULL; - r = fetch_token_in_cc(tok, src, end, env); - if (r == TK_CHAR && tok->u.c == '^' && tok->escaped == 0) { -@@ -6514,14 +6515,18 @@ static int - parse_exp(Node** np, OnigToken* tok, int term, - UChar** src, UChar* end, ScanEnv* env) - { -- int r, len, group = 0; -+ int r, len, group; - Node* qn; - Node** targetp; -+ unsigned int parse_depth; - -+ group = 0; - *np = NULL; - if (tok->type == (enum TokenSyms )term) - goto end_of_token; - -+ parse_depth = env->parse_depth; -+ - switch (tok->type) { - case TK_ALT: - case TK_EOT: -@@ -6832,6 +6837,10 @@ parse_exp(Node** np, OnigToken* tok, int term, - if (is_invalid_quantifier_target(*targetp)) - return ONIGERR_TARGET_OF_REPEAT_OPERATOR_INVALID; - -+ parse_depth++; -+ if (parse_depth > ParseDepthLimit) -+ return ONIGERR_PARSE_DEPTH_LIMIT_OVER; -+ - qn = node_new_quantifier(tok->u.repeat.lower, tok->u.repeat.upper, - (r == TK_INTERVAL ? 1 : 0)); - CHECK_NULL_RETURN_MEMERR(qn); --- -1.8.3.1 - diff --git a/CVE-2019-19204.patch b/CVE-2019-19204.patch deleted file mode 100644 index a9fec42..0000000 --- a/CVE-2019-19204.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 6eb4aca6a7f2f60f473580576d86686ed6a6ebec Mon Sep 17 00:00:00 2001 -From: "K.Kosako" -Date: Wed, 6 Nov 2019 17:32:29 +0900 -Subject: [PATCH] fix #162: heap-buffer-overflow in fetch_interval_quantifier - due to double PFETCH - ---- - regparse.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/regparse.c b/regparse.c -index 324c414..70c36d5 100644 ---- a/regparse.c -+++ b/regparse.c -@@ -4178,7 +4178,7 @@ fetch_interval_quantifier(UChar** src, UChar* end, PToken* tok, ScanEnv* env) - if (PEND) goto invalid; - PFETCH(c); - if (IS_SYNTAX_OP(env->syntax, ONIG_SYN_OP_ESC_BRACE_INTERVAL)) { -- if (c != MC_ESC(env->syntax)) goto invalid; -+ if (c != MC_ESC(env->syntax) || PEND) goto invalid; - if (PEND) goto invalid; - PFETCH(c); - } diff --git a/CVE-2019-19246.patch b/CVE-2019-19246.patch deleted file mode 100644 index 3c14ac9..0000000 --- a/CVE-2019-19246.patch +++ /dev/null @@ -1,24 +0,0 @@ -From d3e402928b6eb3327f8f7d59a9edfa622fec557b Mon Sep 17 00:00:00 2001 -From: "K.Kosako" -Date: Tue, 13 Aug 2019 13:37:30 +0900 -Subject: [PATCH] fix heap-buffer-overflow - ---- - regexec.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/regexec.c b/regexec.c -index 4582c35..8a17ee7 100644 ---- a/regexec.c -+++ b/regexec.c -@@ -3255,6 +3255,7 @@ str_lower_case_match(OnigEncoding enc, int case_fold_flag, - lowlen = ONIGENC_MBC_CASE_FOLD(enc, case_fold_flag, &p, end, lowbuf); - q = lowbuf; - while (lowlen > 0) { -+ if (t >= tend) return 0; - if (*t++ != *q++) return 0; - lowlen--; - } --- -1.8.3.1 - diff --git a/CVE-2020-25613.patch b/CVE-2020-25613.patch deleted file mode 100644 index 75edbfd..0000000 --- a/CVE-2020-25613.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 8946bb38b4d87549f0d99ed73c62c41933f97cc7 Mon Sep 17 00:00:00 2001 -From: Yusuke Endoh -Date: Tue, 29 Sep 2020 13:15:58 +0900 -Subject: [PATCH] Make it more strict to interpret some headers - -Some regexps were too tolerant. ---- - lib/webrick/httprequest.rb | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/lib/webrick/httprequest.rb b/lib/webrick/httprequest.rb -index 294bd91..d34eac7 100644 ---- a/lib/webrick/httprequest.rb -+++ b/lib/webrick/httprequest.rb -@@ -227,9 +227,9 @@ def parse(socket=nil) - raise HTTPStatus::BadRequest, "bad URI `#{@unparsed_uri}'." - end - -- if /close/io =~ self["connection"] -+ if /\Aclose\z/io =~ self["connection"] - @keep_alive = false -- elsif /keep-alive/io =~ self["connection"] -+ elsif /\Akeep-alive\z/io =~ self["connection"] - @keep_alive = true - elsif @http_version < "1.1" - @keep_alive = false -@@ -508,7 +508,7 @@ def read_body(socket, block) - return unless socket - if tc = self['transfer-encoding'] - case tc -- when /chunked/io then read_chunked(socket, block) -+ when /\Achunked\z/io then read_chunked(socket, block) - else raise HTTPStatus::NotImplemented, "Transfer-Encoding: #{tc}." - end - elsif self['content-length'] || @remaining_size diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 63ea4b4..0000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# ruby - -#### Description -{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md deleted file mode 100644 index 4da46ff..0000000 --- a/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# ruby - -#### 介绍 -{**以下是码云平台说明,您可以替换此简介** -码云是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用码云实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} - -#### 软件架构 -软件架构说明 - - -#### 安装教程 - -1. xxxx -2. xxxx -3. xxxx - -#### 使用说明 - -1. xxxx -2. xxxx -3. xxxx - -#### 参与贡献 - -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request - - -#### 码云特技 - -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目 -5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/backport-CVE-2021-31799.patch b/backport-CVE-2021-31799.patch deleted file mode 100644 index 42bffe5..0000000 --- a/backport-CVE-2021-31799.patch +++ /dev/null @@ -1,51 +0,0 @@ -From a7f5d6ab88632b3b482fe10611382ff73d14eed7 Mon Sep 17 00:00:00 2001 -From: aycabta -Date: Sun, 2 May 2021 20:52:23 +0900 -Subject: [PATCH] Use File.open to fix the OS Command Injection vulnerability - in CVE-2021-31799 - -Reference:https://github.com/ruby/rdoc/commit/a7f5d6ab88632b3b482fe10611382ff73d14eed7 ---- - lib/rdoc/rdoc.rb | 2 +- - test/rdoc/test_rdoc_rdoc.rb | 12 ++++++++++++ - 2 files changed, 13 insertions(+), 1 deletion(-) - -diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb -index 68775c8..0095eb7 100644 ---- a/lib/rdoc/rdoc.rb -+++ b/lib/rdoc/rdoc.rb -@@ -433,7 +433,7 @@ The internal error was: - files.reject do |file| - file =~ /\.(?:class|eps|erb|scpt\.txt|svg|ttf|yml)$/i or - (file =~ /tags$/i and -- open(file, 'rb') { |io| -+ File.open(file, 'rb') { |io| - io.read(100) =~ /\A(\f\n[^,]+,\d+$|!_TAG_)/ - }) - end -diff --git a/test/rdoc/test_rdoc_rdoc.rb b/test/rdoc/test_rdoc_rdoc.rb -index bd47943..07541df 100644 ---- a/test/rdoc/test_rdoc_rdoc.rb -+++ b/test/rdoc/test_rdoc_rdoc.rb -@@ -366,6 +366,18 @@ class TestRDocRDoc < RDoc::TestCase - end - end - -+ def test_remove_unparseable_CVE_2021_31799 -+ temp_dir do -+ file_list = ['| touch evil.txt && echo tags'] -+ file_list.each do |f| -+ FileUtils.touch f -+ end -+ -+ assert_equal file_list, @rdoc.remove_unparseable(file_list) -+ assert_equal file_list, Dir.children('.') -+ end -+ end -+ - def test_setup_output_dir - Dir.mktmpdir {|d| - path = File.join d, 'testdir' --- -1.8.3.1 - diff --git a/backport-CVE-2021-31810.patch b/backport-CVE-2021-31810.patch deleted file mode 100644 index 61b313f..0000000 --- a/backport-CVE-2021-31810.patch +++ /dev/null @@ -1,248 +0,0 @@ -From 5709ece67cf57a94655e34532f8a7899b28d496a Mon Sep 17 00:00:00 2001l/pkcs5. -From: Shugo Maeda -Date: Wed, 7 Jul 2021 16:00:45 +0900/pkey.rb -Subject: [PATCH] This fixes CVE-2021-31810. Reported by Alexandr Savca inssl.rb - ./x509.rb - -Reference:https://github.com/ruby/net-ftp/commit/5709ece67cf57a94655e34532f8a7899b28d496a ---- - lib/net/ftp.rb | 15 ++++- - test/net/ftp/test_ftp.rb | 159 ++++++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 170 insertions(+), 4 deletions(-) - -diff --git a/lib/net/ftp.rb b/lib/net/ftp.rb -index 9902f9d..cd446b4 100644 ---- a/lib/net/ftp.rb -+++ b/lib/net/ftp.rb -@@ -97,6 +97,10 @@ module Net - # When +true+, the connection is in passive mode. Default: +true+. - attr_accessor :passive - -+ # When +true+, use the IP address in PASV responses. Otherwise, it uses -+ # the same IP address for the control connection. Default: +false+. -+ attr_accessor :use_pasv_ip -+ - # When +true+, all traffic to and from the server is written - # to +$stdout+. Default: +false+. - attr_accessor :debug_mode -@@ -205,6 +209,9 @@ module Net - # handshake. - # See Net::FTP#ssl_handshake_timeout for - # details. Default: +nil+. -+ # use_pasv_ip:: When +true+, use the IP address in PASV responses. -+ # Otherwise, it uses the same IP address for the control -+ # connection. Default: +false+. - # debug_mode:: When +true+, all traffic to and from the server is - # written to +$stdout+. Default: +false+. - # -@@ -265,6 +272,7 @@ module Net - @open_timeout = options[:open_timeout] - @ssl_handshake_timeout = options[:ssl_handshake_timeout] - @read_timeout = options[:read_timeout] || 60 -+ @use_pasv_ip = options[:use_pasv_ip] || false - if host - connect(host, options[:port] || FTP_PORT) - if options[:username] -@@ -1330,7 +1338,12 @@ module Net - raise FTPReplyError, resp - end - if m = /\((?\d+(,\d+){3}),(?\d+,\d+)\)/.match(resp) -- return parse_pasv_ipv4_host(m["host"]), parse_pasv_port(m["port"]) -+ if @use_pasv_ip -+ host = parse_pasv_ipv4_host(m["host"]) -+ else -+ host = @bare_sock.remote_address.ip_address -+ end -+ return host, parse_pasv_port(m["port"]) - else - raise FTPProtoError, resp - end -diff --git a/test/net/ftp/test_ftp.rb b/test/net/ftp/test_ftp.rb -index 8e0a688..52fb3a9 100644 ---- a/test/net/ftp/test_ftp.rb -+++ b/test/net/ftp/test_ftp.rb -@@ -61,7 +61,7 @@ class FTPTest < Test::Unit::TestCase - end - - def test_parse227 -- ftp = Net::FTP.new -+ ftp = Net::FTP.new(nil, use_pasv_ip: true) - host, port = ftp.send(:parse227, "227 Entering Passive Mode (192,168,0,1,12,34)") - assert_equal("192.168.0.1", host) - assert_equal(3106, port) -@@ -80,6 +80,14 @@ class FTPTest < Test::Unit::TestCase - assert_raise(Net::FTPProtoError) do - ftp.send(:parse227, "227 ) foo bar (") - end -+ -+ ftp = Net::FTP.new -+ sock = OpenStruct.new -+ sock.remote_address = OpenStruct.new -+ sock.remote_address.ip_address = "10.0.0.1" -+ ftp.instance_variable_set(:@bare_sock, sock) -+ host, port = ftp.send(:parse227, "227 Entering Passive Mode (192,168,0,1,12,34)") -+ assert_equal("10.0.0.1", host) - end - - def test_parse228 -@@ -2360,10 +2368,155 @@ EOF - end - end - -+ def test_ignore_pasv_ip -+ commands = [] -+ binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3 -+ server = create_ftp_server(nil, "127.0.0.1") { |sock| -+ sock.print("220 (test_ftp).\r\n") -+ commands.push(sock.gets) -+ sock.print("331 Please specify the password.\r\n") -+ commands.push(sock.gets) -+ sock.print("230 Login successful.\r\n") -+ commands.push(sock.gets) -+ sock.print("200 Switching to Binary mode.\r\n") -+ line = sock.gets -+ commands.push(line) -+ data_server = TCPServer.new("127.0.0.1", 0) -+ port = data_server.local_address.ip_port -+ sock.printf("227 Entering Passive Mode (999,0,0,1,%s).\r\n", -+ port.divmod(256).join(",")) -+ commands.push(sock.gets) -+ sock.print("150 Opening BINARY mode data connection for foo (#{binary_data.size} bytes)\r\n") -+ conn = data_server.accept -+ binary_data.scan(/.{1,1024}/nm) do |s| -+ conn.print(s) -+ end -+ conn.shutdown(Socket::SHUT_WR) -+ conn.read -+ conn.close -+ data_server.close -+ sock.print("226 Transfer complete.\r\n") -+ } -+ begin -+ begin -+ ftp = Net::FTP.new -+ ftp.passive = true -+ ftp.read_timeout *= 5 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # for --jit-wait -+ ftp.connect("127.0.0.1", server.port) -+ ftp.login -+ assert_match(/\AUSER /, commands.shift) -+ assert_match(/\APASS /, commands.shift) -+ assert_equal("TYPE I\r\n", commands.shift) -+ buf = ftp.getbinaryfile("foo", nil) -+ assert_equal(binary_data, buf) -+ assert_equal(Encoding::ASCII_8BIT, buf.encoding) -+ assert_equal("PASV\r\n", commands.shift) -+ assert_equal("RETR foo\r\n", commands.shift) -+ assert_equal(nil, commands.shift) -+ ensure -+ ftp.close if ftp -+ end -+ ensure -+ server.close -+ end -+ end -+ -+ def test_use_pasv_ip -+ commands = [] -+ binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3 -+ server = create_ftp_server(nil, "127.0.0.1") { |sock| -+ sock.print("220 (test_ftp).\r\n") -+ commands.push(sock.gets) -+ sock.print("331 Please specify the password.\r\n") -+ commands.push(sock.gets) -+ sock.print("230 Login successful.\r\n") -+ commands.push(sock.gets) -+ sock.print("200 Switching to Binary mode.\r\n") -+ line = sock.gets -+ commands.push(line) -+ data_server = TCPServer.new("127.0.0.1", 0) -+ port = data_server.local_address.ip_port -+ sock.printf("227 Entering Passive Mode (127,0,0,1,%s).\r\n", -+ port.divmod(256).join(",")) -+ commands.push(sock.gets) -+ sock.print("150 Opening BINARY mode data connection for foo (#{binary_data.size} bytes)\r\n") -+ conn = data_server.accept -+ binary_data.scan(/.{1,1024}/nm) do |s| -+ conn.print(s) -+ end -+ conn.shutdown(Socket::SHUT_WR) -+ conn.read -+ conn.close -+ data_server.close -+ sock.print("226 Transfer complete.\r\n") -+ } -+ begin -+ begin -+ ftp = Net::FTP.new -+ ftp.passive = true -+ ftp.use_pasv_ip = true -+ ftp.read_timeout *= 5 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # for --jit-wait -+ ftp.connect("127.0.0.1", server.port) -+ ftp.login -+ assert_match(/\AUSER /, commands.shift) -+ assert_match(/\APASS /, commands.shift) -+ assert_equal("TYPE I\r\n", commands.shift) -+ buf = ftp.getbinaryfile("foo", nil) -+ assert_equal(binary_data, buf) -+ assert_equal(Encoding::ASCII_8BIT, buf.encoding) -+ assert_equal("PASV\r\n", commands.shift) -+ assert_equal("RETR foo\r\n", commands.shift) -+ assert_equal(nil, commands.shift) -+ ensure -+ ftp.close if ftp -+ end -+ ensure -+ server.close -+ end -+ end -+ -+ def test_use_pasv_invalid_ip -+ commands = [] -+ binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3 -+ server = create_ftp_server(nil, "127.0.0.1") { |sock| -+ sock.print("220 (test_ftp).\r\n") -+ commands.push(sock.gets) -+ sock.print("331 Please specify the password.\r\n") -+ commands.push(sock.gets) -+ sock.print("230 Login successful.\r\n") -+ commands.push(sock.gets) -+ sock.print("200 Switching to Binary mode.\r\n") -+ line = sock.gets -+ commands.push(line) -+ sock.print("227 Entering Passive Mode (999,0,0,1,48,57).\r\n") -+ commands.push(sock.gets) -+ } -+ begin -+ begin -+ ftp = Net::FTP.new -+ ftp.passive = true -+ ftp.use_pasv_ip = true -+ ftp.read_timeout *= 5 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # for --jit-wait -+ ftp.connect("127.0.0.1", server.port) -+ ftp.login -+ assert_match(/\AUSER /, commands.shift) -+ assert_match(/\APASS /, commands.shift) -+ assert_equal("TYPE I\r\n", commands.shift) -+ assert_raise(SocketError) do -+ ftp.getbinaryfile("foo", nil) -+ end -+ ensure -+ ftp.close if ftp -+ end -+ ensure -+ server.close -+ end -+ end -+ - private - -- def create_ftp_server(sleep_time = nil) -- server = TCPServer.new(SERVER_ADDR, 0) -+ def create_ftp_server(sleep_time = nil, addr = SERVER_ADDR) -+ server = TCPServer.new(addr, 0) - @thread = Thread.start do - if sleep_time - sleep(sleep_time) --- -1.8.3.1 - diff --git a/backport-CVE-2021-32066.patch b/backport-CVE-2021-32066.patch deleted file mode 100644 index a893695..0000000 --- a/backport-CVE-2021-32066.patch +++ /dev/null @@ -1,95 +0,0 @@ -From adba6f0c3e5c5607c4822b9120322eb7e9a77891 Mon Sep 17 00:00:00 2001 -From: Shugo Maeda -Date: Wed, 7 Jul 2021 16:09:03 +0900 -Subject: [PATCH] This fixes CVE-2021-32066. Reported by Alexandr Savca in - . - -Reference:https://github.com/ruby/net-imap/commit/adba6f0c3e5c5607c4822b9120322eb7e9a77891 ---- - lib/net/imap.rb | 8 +++++++- - test/net/imap/test_imap.rb | 31 +++++++++++++++++++++++++++++++ - 2 files changed, 38 insertions(+), 1 deletion(-) - -diff --git a/lib/net/imap.rb b/lib/net/imap.rb -index da7d0d5..eedcb4f 100644 ---- a/lib/net/imap.rb -+++ b/lib/net/imap.rb -@@ -1213,12 +1213,14 @@ module Net - end - resp = @tagged_responses.delete(tag) - case resp.name -+ when /\A(?:OK)\z/ni -+ return resp - when /\A(?:NO)\z/ni - raise NoResponseError, resp - when /\A(?:BAD)\z/ni - raise BadResponseError, resp - else -- return resp -+ raise UnknownResponseError, resp - end - end - -@@ -3714,6 +3716,10 @@ module Net - class ByeResponseError < ResponseError - end - -+ # Error raised upon an unknown response from the server. -+ class UnknownResponseError < ResponseError -+ end -+ - RESPONSE_ERRORS = Hash.new(ResponseError) - RESPONSE_ERRORS["NO"] = NoResponseError - RESPONSE_ERRORS["BAD"] = BadResponseError -diff --git a/test/net/imap/test_imap.rb b/test/net/imap/test_imap.rb -index 41f25fe..9247062 100644 ---- a/test/net/imap/test_imap.rb -+++ b/test/net/imap/test_imap.rb -@@ -110,6 +110,16 @@ class IMAPTest < Test::Unit::TestCase - end - end - end -+ -+ def test_starttls_stripping -+ starttls_stripping_test do |port| -+ imap = Net::IMAP.new("localhost", :port => port) -+ assert_raise(Net::IMAP::UnknownResponseError) do -+ imap.starttls(:ca_file => CA_FILE) -+ end -+ imap -+ end -+ end - end - - if defined?(OpenSSL::SSL) -@@ -760,6 +770,27 @@ EOF - end - end - -+ def starttls_stripping_test -+ server = create_tcp_server -+ port = server.addr[1] -+ start_server do -+ sock = server.accept -+ begin -+ sock.print("* OK test server\r\n") -+ sock.gets -+ sock.print("RUBY0001 BUG unhandled command\r\n") -+ ensure -+ sock.close -+ server.close -+ end -+ end -+ begin -+ imap = yield(port) -+ ensure -+ imap.disconnect if imap && !imap.disconnected? -+ end -+ end -+ - def create_tcp_server - return TCPServer.new(server_addr, 0) - end --- -1.8.3.1 - diff --git a/macros.rubygems b/macros.rubygems index d2e8514..8c4d067 100644 --- a/macros.rubygems +++ b/macros.rubygems @@ -9,6 +9,7 @@ %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. @@ -21,7 +22,7 @@ %gem_install(d:n:) \ mkdir -p %{-d*}%{!?-d:.%{gem_dir}} \ \ -CONFIGURE_ARGS="--with-cflags='%{optflags}' $CONFIGURE_ARGS" \\\ +CONFIGURE_ARGS="--with-cflags='%{optflags}' --with-cxxflags='%{optflags}' --with-ldflags='%{build_ldflags}' $CONFIGURE_ARGS" \\\ gem install \\\ -V \\\ --local \\\ @@ -32,16 +33,6 @@ gem install \\\ %{nil} -# For rubygems packages we want to filter out any provides caused by private -# libs in %%{gem_archdir}. -# -# Note that this must be invoked in the spec file, preferably as -# "%{?rubygems_default_filter}", before any %description block. -%rubygems_default_filter %{expand: \ -%global __provides_exclude_from %{?__provides_exclude_from:%{__provides_exclude_from}|}^%{gem_extdir_mri}/.*\\\\.so$ \ -} - - # The 'read' command in %%gemspec_* macros is not essential, but it is usefull # to make the sript appear in build log. @@ -60,7 +51,7 @@ gem install \\\ # %gemspec_add_dep(g:s:d) \ read -d '' gemspec_add_dep_script << 'EOR' || : \ - gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}.gemspec}' \ + gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}%{?prerelease}.gemspec}' \ \ name = '%{-g*}' \ requirements = %{*}%{!?1:nil} \ @@ -97,7 +88,7 @@ unset -v gemspec_add_dep_script \ # %gemspec_remove_dep(g:s:d) \ read -d '' gemspec_remove_dep_script << 'EOR' || : \ - gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}.gemspec}' \ + gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}%{?prerelease}.gemspec}' \ \ name = '%{-g*}' \ requirements = %{*}%{!?1:nil} \ @@ -144,7 +135,7 @@ unset -v gemspec_remove_dep_script \ # %gemspec_add_file(s:tr) \ read -d '' gemspec_add_file_script << 'EOR' || : \ - gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}.gemspec}' \ + 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" \ \ @@ -177,7 +168,7 @@ unset -v gemspec_add_file_script \ # %gemspec_remove_file(s:tr) \ read -d '' gemspec_remove_file_script << 'EOR' || : \ - gemspec_file = '%{-s*}%{!?-s:%{_builddir}/%{gem_name}-%{version}.gemspec}' \ + 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" \ \ diff --git a/operating_system.rb b/operating_system.rb index 0d4b1f0..d95b303 100644 --- a/operating_system.rb +++ b/operating_system.rb @@ -119,6 +119,7 @@ module Gem 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 diff --git a/ruby-1.9.3-mkmf-verbose.patch b/ruby-1.9.3-mkmf-verbose.patch index f2a1408..b9c2c6f 100644 --- a/ruby-1.9.3-mkmf-verbose.patch +++ b/ruby-1.9.3-mkmf-verbose.patch @@ -11,7 +11,7 @@ diff --git a/lib/mkmf.rb b/lib/mkmf.rb index 682eb46..e6b1445 100644 --- a/lib/mkmf.rb +++ b/lib/mkmf.rb -@@ -1899,7 +1899,7 @@ def configuration(srcdir) +@@ -1930,7 +1930,7 @@ def configuration(srcdir) SHELL = /bin/sh # V=0 quiet, V=1 verbose. other values don't work. diff --git a/ruby-2.1.0-Allow-to-specify-additional-preludes-by-configuratio.patch b/ruby-2.1.0-Allow-to-specify-additional-preludes-by-configuratio.patch deleted file mode 100644 index 47bf9bc..0000000 --- a/ruby-2.1.0-Allow-to-specify-additional-preludes-by-configuratio.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 996012f6abe0ce4d68a2de9f249935c6d5b467bc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Fri, 4 Oct 2013 22:13:11 +0200 -Subject: [PATCH] Allow to specify addition preludes by configuration option. - ---- - Makefile.in | 2 ++ - common.mk | 2 +- - configure.ac | 7 +++++++ - 3 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/Makefile.in b/Makefile.in -index 7e8ed82..7916993 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -119,6 +119,8 @@ XRUBY_RUBYLIBDIR = @XRUBY_RUBYLIBDIR@ - XRUBY_RUBYHDRDIR = @XRUBY_RUBYHDRDIR@ - BOOTSTRAPRUBY = @BOOTSTRAPRUBY@ - -+OPTIONAL_PRELUDES = @OPTIONAL_PRELUDES@ -+ - #### End of system configuration section. #### - - MAJOR= @MAJOR@ -diff --git a/common.mk b/common.mk -index 5cfbc3d..3f0a82e 100644 ---- a/common.mk -+++ b/common.mk -@@ -147,7 +147,7 @@ ALLOBJS = $(NORMALMAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(INITOBJS) - GOLFOBJS = goruby.$(OBJEXT) golf_prelude.$(OBJEXT) - - DEFAULT_PRELUDES = $(GEM_PRELUDE) --PRELUDE_SCRIPTS = $(srcdir)/prelude.rb $(DEFAULT_PRELUDES) -+PRELUDE_SCRIPTS = $(srcdir)/prelude.rb $(DEFAULT_PRELUDES) $(OPTIONAL_PRELUDES) - GEM_PRELUDE = $(srcdir)/gem_prelude.rb - PRELUDES = {$(srcdir)}prelude.c {$(srcdir)}miniprelude.c - GOLFPRELUDES = {$(srcdir)}golf_prelude.c -diff --git a/configure.ac b/configure.ac -index 028ef7ca3e..cdeff87871 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -4396,6 +4396,13 @@ AC_SUBST(rubyarchhdrdir)dnl - AC_SUBST(sitearchhdrdir)dnl - AC_SUBST(vendorarchhdrdir)dnl - -+AC_ARG_WITH(prelude, -+ AS_HELP_STRING([--with-prelude=FILE-LIST], [specify additional preludes separated by space]), -+ [prelude=$withval]) -+if test "$prelude" != ""; then -+ AC_SUBST(OPTIONAL_PRELUDES, $prelude) -+fi -+ - AC_ARG_WITH(mantype, - AS_HELP_STRING([--with-mantype=TYPE], [specify man page type; TYPE is one of man and doc]), - [ --- -1.8.3.1 - diff --git a/ruby-2.1.0-Enable-configuration-of-archlibdir.patch b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch index 36ec460..32806da 100644 --- a/ruby-2.1.0-Enable-configuration-of-archlibdir.patch +++ b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch @@ -8,10 +8,10 @@ Subject: [PATCH] Allow to configure libruby.so placement. 1 file changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac -index 11fc237552..b77e88fc37 100644 +index d261ea57b5..3c13076b82 100644 --- a/configure.ac +++ b/configure.ac -@@ -3641,6 +3641,11 @@ AS_IF([test ${multiarch+set}], [ +@@ -3240,6 +3240,11 @@ AS_IF([test ${multiarch+set}], [ ]) archlibdir='${libdir}/${arch}' @@ -24,5 +24,5 @@ index 11fc237552..b77e88fc37 100644 archincludedir='${includedir}/${arch}' sitearchincludedir='${includedir}/${sitearch}' -- -1.8.3.1 +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 index d0cffab..118203c 100644 --- a/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch +++ b/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch @@ -11,10 +11,10 @@ Subject: [PATCH] Prevent duplicated paths when empty version string is 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac -index 999e2d6d5d..11fc237552 100644 +index c42436c23d..d261ea57b5 100644 --- a/configure.ac +++ b/configure.ac -@@ -4251,7 +4251,8 @@ AS_CASE(["$ruby_version_dir_name"], +@@ -3881,7 +3881,8 @@ AS_CASE(["$ruby_version_dir_name"], ruby_version_dir=/'${ruby_version_dir_name}' if test -z "${ruby_version_dir_name}"; then @@ -66,7 +66,7 @@ diff --git a/tool/mkconfig.rb b/tool/mkconfig.rb index 07076d4..35e6c3c 100755 --- a/tool/mkconfig.rb +++ b/tool/mkconfig.rb -@@ -111,7 +111,7 @@ +@@ -114,7 +114,7 @@ val = val.gsub(/\$(?:\$|\{?(\w+)\}?)/) {$1 ? "$(#{$1})" : $&}.dump case name when /^prefix$/ diff --git a/ruby-2.1.0-always-use-i386.patch b/ruby-2.1.0-always-use-i386.patch index 555ad45..de58295 100644 --- a/ruby-2.1.0-always-use-i386.patch +++ b/ruby-2.1.0-always-use-i386.patch @@ -8,10 +8,10 @@ Subject: [PATCH] Always use i386. 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac -index b77e88fc37..6bba453e3c 100644 +index 3c13076b82..93af30321d 100644 --- a/configure.ac +++ b/configure.ac -@@ -4315,6 +4315,8 @@ AC_SUBST(vendorarchdir)dnl +@@ -3945,6 +3945,8 @@ AC_SUBST(vendorarchdir)dnl AC_SUBST(CONFIGURE, "`echo $0 | sed 's|.*/||'`")dnl AC_SUBST(configure_args, "`echo "${ac_configure_args}" | sed 's/\\$/$$/g'`")dnl diff --git a/ruby-2.1.0-custom-rubygems-location.patch b/ruby-2.1.0-custom-rubygems-location.patch index 7b7c724..f7862fa 100644 --- a/ruby-2.1.0-custom-rubygems-location.patch +++ b/ruby-2.1.0-custom-rubygems-location.patch @@ -5,16 +5,17 @@ Subject: [PATCH] Allow to install RubyGems into custom location, outside of Ruby tree. --- - configure.ac | 5 +++++ - loadpath.c | 4 ++++ - template/verconf.h.tmpl | 3 +++ - tool/rbinstall.rb | 7 +++++++ - 4 files changed, 19 insertions(+) + configure.ac | 5 +++++ + loadpath.c | 4 ++++ + template/verconf.h.tmpl | 3 +++ + tool/rbinstall.rb | 10 ++++++++++ + 4 files changed, 22 insertions(+) -diff -Naur a/configure.ac b/configure.ac ---- a/configure.ac 2020-07-27 16:38:47.589749033 +0800 -+++ b/configure.ac 2020-07-27 16:24:09.948494621 +0800 -@@ -4288,6 +4288,10 @@ +diff --git a/configure.ac b/configure.ac +index 93af30321d..bc13397e0e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3917,6 +3917,10 @@ AC_ARG_WITH(vendorarchdir, [vendorarchdir=$withval], [vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby'${ruby_version_dir}}${multiarch-'${vendorlibdir}/${sitearch}'}]) @@ -25,7 +26,7 @@ diff -Naur a/configure.ac b/configure.ac AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) RUBY_EXEC_PREFIX='' -@@ -4312,6 +4316,7 @@ +@@ -3941,6 +3945,7 @@ AC_SUBST(sitearchdir)dnl AC_SUBST(vendordir)dnl AC_SUBST(vendorlibdir)dnl AC_SUBST(vendorarchdir)dnl @@ -33,11 +34,11 @@ diff -Naur a/configure.ac b/configure.ac AC_SUBST(CONFIGURE, "`echo $0 | sed 's|.*/||'`")dnl AC_SUBST(configure_args, "`echo "${ac_configure_args}" | sed 's/\\$/$$/g'`")dnl - -diff -Naur a/loadpath.c b/loadpath.c ---- a/loadpath.c 2020-07-27 16:38:47.589749033 +0800 -+++ b/loadpath.c 2020-07-27 16:24:09.948494621 +0800 -@@ -94,6 +94,10 @@ +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 @@ -48,10 +49,10 @@ diff -Naur a/loadpath.c b/loadpath.c RUBY_LIB "\0" #ifdef RUBY_THINARCH RUBY_ARCH_LIB_FOR(RUBY_THINARCH) "\0" - -diff -Naur a/template/verconf.h.tmpl b/template/verconf.h.tmpl ---- a/template/verconf.h.tmpl 2020-07-27 16:38:47.589749033 +0800 -+++ b/template/verconf.h.tmpl 2020-07-27 16:24:09.948494621 +0800 +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}" @@ -62,29 +63,35 @@ diff -Naur a/template/verconf.h.tmpl b/template/verconf.h.tmpl % % R = {} % R["ruby_version"] = '"RUBY_LIB_VERSION"' - -diff -Naur a/tool/rbinstall.rb b/tool/rbinstall.rb ---- a/tool/rbinstall.rb 2020-07-27 16:22:12.328326341 +0800 -+++ b/tool/rbinstall.rb 2020-07-27 16:31:57.009162449 +0800 -@@ -335,6 +335,7 @@ +diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb +index e9110a17ca..76a1f0a315 100755 +--- a/tool/rbinstall.rb ++++ b/tool/rbinstall.rb +@@ -349,6 +349,7 @@ def CONFIG.[](name, mandatory = false) vendorlibdir = CONFIG["vendorlibdir"] vendorarchlibdir = CONFIG["vendorarchdir"] end +rubygemsdir = CONFIG["rubygemsdir"] mandir = CONFIG["mandir", true] docdir = CONFIG["docdir", true] - configure_args = Shellwords.shellwords(CONFIG["configure_args"]) -@@ -541,7 +542,13 @@ + 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] -+ noinst += %w[rubygems.rb rubygems/ datadir.rb] if rubygemsdir ++ # 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[obsolete.rb] -+ install_recursive(File.join(srcdir, "lib", "rubygems"), File.join(rubygemsdir, "rubygems"), :mode => $data_mode) ++ noinst = %w[*.txt *.rdoc *.gemspec] ++ install_recursive(File.join(srcdir, "lib", "rubygems"), File.join(rubygemsdir, "rubygems"), :no_install => noinst, :mode => $data_mode) + install(File.join(srcdir, "lib", "rubygems.rb"), File.join(rubygemsdir, "rubygems.rb"), :mode => $data_mode) ++ install_recursive(File.join(srcdir, "lib", "bundler"), File.join(rubylibdir, "bundler"), :no_install => noinst, :mode => $data_mode) ++ install(File.join(srcdir, "lib", "bundler.rb"), rubylibdir, :mode => $data_mode) + end end install?(:local, :comm, :hdr, :'comm-hdr') do +-- +1.8.3.1 + diff --git a/ruby-2.2.3-Generate-preludes-using-miniruby.patch b/ruby-2.2.3-Generate-preludes-using-miniruby.patch deleted file mode 100644 index ca66d28..0000000 --- a/ruby-2.2.3-Generate-preludes-using-miniruby.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 07eb5f5e775dec01a92a8b13910eaced9e8ee0cd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Tue, 2 Dec 2014 10:56:58 +0100 -Subject: [PATCH] Generate preludes using miniruby. - ---- - common.mk | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/common.mk b/common.mk -index 168dc52..20c218a 100644 ---- a/common.mk -+++ b/common.mk -@@ -962,9 +962,9 @@ $(MINIPRELUDE_C): $(COMPILE_PRELUDE) - $(srcdir)/template/prelude.c.tmpl - - $(PRELUDE_C): $(COMPILE_PRELUDE) \ -- $(PRELUDE_SCRIPTS) -+ $(PRELUDE_SCRIPTS) $(PREP) - $(ECHO) generating $@ -- $(Q) $(BASERUBY) $(srcdir)/tool/generic_erb.rb -I$(srcdir) -c -o $@ \ -+ $(Q) $(MINIRUBY) $(srcdir)/tool/generic_erb.rb -I$(srcdir) -c -o $@ \ - $(srcdir)/template/prelude.c.tmpl $(PRELUDE_SCRIPTS) - - {$(VPATH)}golf_prelude.c: $(COMPILE_PRELUDE) {$(srcdir)}golf_prelude.rb --- -2.6.3 - diff --git a/ruby-2.3.0-ruby_version.patch b/ruby-2.3.0-ruby_version.patch index 8f57319..b0a73a9 100644 --- a/ruby-2.3.0-ruby_version.patch +++ b/ruby-2.3.0-ruby_version.patch @@ -12,15 +12,15 @@ ruby_version_dir_name now specifies custom version string for versioned directories, e.g. instead of default X.Y.Z, you can specify whatever string. --- - configure.ac | 64 ++++++++++++++++++++++++++++------------------------- + configure.ac | 64 ++++++++++++++++++++++++--------------------- template/ruby.pc.in | 1 + 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/configure.ac b/configure.ac -index 8ea969412f..a00f2b6776 100644 +index 80b137e380..63cd3b4f8b 100644 --- a/configure.ac +++ b/configure.ac -@@ -4202,9 +4202,6 @@ AS_CASE(["$target_os"], +@@ -3832,9 +3832,6 @@ AS_CASE(["$target_os"], rubyw_install_name='$(RUBYW_INSTALL_NAME)' ]) @@ -30,7 +30,7 @@ index 8ea969412f..a00f2b6776 100644 rubyarchprefix=${multiarch+'${archlibdir}/${RUBY_BASE_NAME}'}${multiarch-'${rubylibprefix}/${arch}'} AC_ARG_WITH(rubyarchprefix, AS_HELP_STRING([--with-rubyarchprefix=DIR], -@@ -4227,56 +4224,62 @@ AC_ARG_WITH(ridir, +@@ -3857,56 +3854,62 @@ AC_ARG_WITH(ridir, AC_SUBST(ridir) AC_SUBST(RI_BASE_NAME) @@ -120,7 +120,7 @@ index 8ea969412f..a00f2b6776 100644 AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) -@@ -4293,6 +4296,7 @@ AC_SUBST(sitearchincludedir)dnl +@@ -3923,6 +3926,7 @@ AC_SUBST(sitearchincludedir)dnl AC_SUBST(arch)dnl AC_SUBST(sitearch)dnl AC_SUBST(ruby_version)dnl @@ -165,74 +165,66 @@ index 970cb91..5bf8230 100644 - version = RbConfig::CONFIG['ruby_version'] + version = RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] - BASE = if RbConfig::CONFIG.key? 'ridir' then - File.join RbConfig::CONFIG['ridir'], version + 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 -@@ -417,7 +417,7 @@ def CONFIG.[](name, mandatory = false) +@@ -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, :mode => $data_mode) + install_recursive($rdocdir, ridatadir, :no_install => rdoc_noinst, :mode => $data_mode) end -- -2.1.0 +2.23.0 -From f8d136f9a46d1fe87eba622ab9665935d05e981b Mon Sep 17 00:00:00 2001 +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 | 11 ++++++----- - test/rubygems/test_gem.rb | 5 +++-- - 2 files changed, 9 insertions(+), 7 deletions(-) + 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 55ca080..75eea2b 100644 +index d4ff4a262c..3f9a5bf590 100644 --- a/lib/rubygems/defaults.rb +++ b/lib/rubygems/defaults.rb -@@ -32,20 +32,20 @@ def self.default_dir +@@ -38,13 +38,13 @@ def self.default_dir [ File.dirname(RbConfig::CONFIG['sitedir']), 'Gems', -- RbConfig::CONFIG['ruby_version'] +- RbConfig::CONFIG['ruby_version'], + RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] ] - elsif RbConfig::CONFIG['rubylibprefix'] then - [ - RbConfig::CONFIG['rubylibprefix'], - 'gems', -- RbConfig::CONFIG['ruby_version'] -+ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] - ] else [ - RbConfig::CONFIG['libdir'], - ruby_engine, + RbConfig::CONFIG['rubylibprefix'], 'gems', -- RbConfig::CONFIG['ruby_version'] +- RbConfig::CONFIG['ruby_version'], + RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] ] end -@@ -75,7 +75,8 @@ def self.default_rubygems_dirs - - def self.user_dir - parts = [Gem.user_home, '.gem', ruby_engine] +@@ -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 -@@ -172,7 +173,7 @@ def self.vendor_dir # :nodoc: +@@ -252,7 +253,7 @@ def self.vendor_dir # :nodoc: return nil unless RbConfig::CONFIG.key? 'vendordir' File.join RbConfig::CONFIG['vendordir'], 'gems', @@ -242,10 +234,10 @@ index 55ca080..75eea2b 100644 ## diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb -index 0428bea..b6e090e 100644 +index b25068405d..e9fef4a311 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb -@@ -1156,7 +1156,8 @@ def test_self_use_paths +@@ -1440,7 +1440,8 @@ def test_self_use_paths def test_self_user_dir parts = [@userhome, '.gem', Gem.ruby_engine] @@ -253,17 +245,17 @@ index 0428bea..b6e090e 100644 + ruby_version_dir_name = RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] + parts << ruby_version_dir_name unless ruby_version_dir_name.empty? - assert_equal File.join(parts), Gem.user_dir - end -@@ -1283,7 +1284,7 @@ def test_self_user_home_user_drive_and_path - def test_self_vendor_dir - expected = - File.join RbConfig::CONFIG['vendordir'], 'gems', -- RbConfig::CONFIG['ruby_version'] -+ RbConfig::CONFIG['ruby_version_dir_name'] || RbConfig::CONFIG['ruby_version'] + FileUtils.mkdir_p File.join(parts) - assert_equal expected, Gem.vendor_dir - end +@@ -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 @@ -282,15 +274,15 @@ diff --git a/configure.ac b/configure.ac index a00f2b6776..999e2d6d5d 100644 --- a/configure.ac +++ b/configure.ac -@@ -164,7 +164,7 @@ RUBY_BASE_NAME=`echo ruby | sed "$program_transform_name"` +@@ -107,7 +107,7 @@ RUBY_BASE_NAME=`echo ruby | sed "$program_transform_name"` RUBYW_BASE_NAME=`echo rubyw | sed "$program_transform_name"` AC_SUBST(RUBY_BASE_NAME) AC_SUBST(RUBYW_BASE_NAME) -AC_SUBST(RUBY_VERSION_NAME, '${RUBY_BASE_NAME}-${ruby_version}') +AC_SUBST(RUBY_VERSION_NAME, '${RUBY_BASE_NAME}-${ruby_version_dir_name}') - AC_CANONICAL_TARGET - test x"$target_alias" = x && + dnl checks for alternative programs + AC_CANONICAL_BUILD -- 2.1.0 diff --git a/ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch b/ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch index 2dc17e3..599a6e6 100644 --- a/ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch +++ b/ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch @@ -8,109 +8,23 @@ on Red Hat platforms. This workaround rhbz#1361037 --- - test/fiddle/helper.rb | 92 --------------------------------------------------- - 1 file changed, 92 deletions(-) + test/fiddle/helper.rb | 3 +++ + 1 file changed, 3 insertions(+) diff --git a/test/fiddle/helper.rb b/test/fiddle/helper.rb index 1da3d93..65148a1 100644 --- a/test/fiddle/helper.rb +++ b/test/fiddle/helper.rb -@@ -6,95 +6,6 @@ +@@ -139,6 +139,9 @@ + libc_so = libm_so = "/usr/lib/libSystem.B.dylib" + end - libc_so = libm_so = nil - --case RUBY_PLATFORM --when /cygwin/ -- libc_so = "cygwin1.dll" -- libm_so = "cygwin1.dll" --when /linux/ -- libdir = '/lib' -- case [0].pack('L!').size -- when 4 -- # 32-bit ruby -- libdir = '/lib32' if File.directory? '/lib32' -- when 8 -- # 64-bit ruby -- libdir = '/lib64' if File.directory? '/lib64' -- end -- libc_so = File.join(libdir, "libc.so.6") -- libm_so = File.join(libdir, "libm.so.6") --when /mingw/, /mswin/ -- require "rbconfig" -- crtname = RbConfig::CONFIG["RUBY_SO_NAME"][/msvc\w+/] || 'ucrtbase' -- libc_so = libm_so = "#{crtname}.dll" --when /darwin/ -- libc_so = "/usr/lib/libc.dylib" -- libm_so = "/usr/lib/libm.dylib" --when /kfreebsd/ -- libc_so = "/lib/libc.so.0.1" -- libm_so = "/lib/libm.so.1" --when /gnu/ #GNU/Hurd -- libc_so = "/lib/libc.so.0.3" -- libm_so = "/lib/libm.so.6" --when /mirbsd/ -- libc_so = "/usr/lib/libc.so.41.10" -- libm_so = "/usr/lib/libm.so.7.0" --when /freebsd/ -- libc_so = "/lib/libc.so.7" -- libm_so = "/lib/libm.so.5" --when /bsd|dragonfly/ -- libc_so = "/usr/lib/libc.so" -- libm_so = "/usr/lib/libm.so" --when /solaris/ -- libdir = '/lib' -- case [0].pack('L!').size -- when 4 -- # 32-bit ruby -- libdir = '/lib' if File.directory? '/lib' -- when 8 -- # 64-bit ruby -- libdir = '/lib/64' if File.directory? '/lib/64' -- end -- libc_so = File.join(libdir, "libc.so") -- libm_so = File.join(libdir, "libm.so") --when /aix/ -- pwd=Dir.pwd -- libc_so = libm_so = "#{pwd}/libaixdltest.so" -- unless File.exist? libc_so -- cobjs=%w!strcpy.o! -- mobjs=%w!floats.o sin.o! -- funcs=%w!sin sinf strcpy strncpy! -- expfile='dltest.exp' -- require 'tmpdir' -- Dir.mktmpdir do |dir| -- begin -- Dir.chdir dir -- %x!/usr/bin/ar x /usr/lib/libc.a #{cobjs.join(' ')}! -- %x!/usr/bin/ar x /usr/lib/libm.a #{mobjs.join(' ')}! -- %x!echo "#{funcs.join("\n")}\n" > #{expfile}! -- require 'rbconfig' -- if RbConfig::CONFIG["GCC"] = 'yes' -- lflag='-Wl,' -- else -- lflag='' -- end -- flags="#{lflag}-bE:#{expfile} #{lflag}-bnoentry -lm" -- %x!#{RbConfig::CONFIG["LDSHARED"]} -o #{libc_so} #{(cobjs+mobjs).join(' ')} #{flags}! -- ensure -- Dir.chdir pwd -- end -- end -- end --else -- libc_so = ARGV[0] if ARGV[0] && ARGV[0][0] == ?/ -- libm_so = ARGV[1] if ARGV[1] && ARGV[1][0] == ?/ -- if( !(libc_so && libm_so) ) -- $stderr.puts("libc and libm not found: #{$0} ") -- end --end -- --libc_so = nil if !libc_so || (libc_so[0] == ?/ && !File.file?(libc_so)) --libm_so = nil if !libm_so || (libm_so[0] == ?/ && !File.file?(libm_so)) -- ++# Just ignore the heuristic, because it is not reliable on all platforms. ++libc_so = libm_so = nil ++ if !libc_so || !libm_so ruby = EnvUtil.rubybin - ldd = `ldd #{ruby}` + # When the ruby binary is 32-bit and the host is 64-bit, -- 2.9.2 diff --git a/ruby-2.5.0-Add-Gem.operating_system_defaults.patch b/ruby-2.5.0-Add-Gem.operating_system_defaults.patch deleted file mode 100644 index 6838701..0000000 --- a/ruby-2.5.0-Add-Gem.operating_system_defaults.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 60eb961c25f801ee43ca1be9393ab2f0a0546677 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Tue, 19 Dec 2017 14:00:20 +0100 -Subject: [PATCH] Add Gem.operating_system_defaults to allow packagers to - override defaults. - -This change allows Ruby packagers to override defaults and lazily query -them. - -This is very much the same change as #1644 to treat the -operating_system defaults the same way as platform defaults. ---- - lib/rubygems/config_file.rb | 2 +- - lib/rubygems/defaults.rb | 21 ++++++++++++++++++++- - test/rubygems/test_gem.rb | 7 +++++++ - 3 files changed, 28 insertions(+), 2 deletions(-) - -diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb -index a4efed0f5a..deee38e6d9 100644 ---- a/lib/rubygems/config_file.rb -+++ b/lib/rubygems/config_file.rb -@@ -48,7 +48,7 @@ class Gem::ConfigFile - # For Ruby packagers to set configuration defaults. Set in - # rubygems/defaults/operating_system.rb - -- OPERATING_SYSTEM_DEFAULTS = {} -+ OPERATING_SYSTEM_DEFAULTS = Gem.operating_system_defaults - - ## - # For Ruby implementers to set configuration defaults. Set in -diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb -index 43d57fc808..b8222877ae 100644 ---- a/lib/rubygems/defaults.rb -+++ b/lib/rubygems/defaults.rb -@@ -177,7 +177,26 @@ def self.vendor_dir # :nodoc: - end - - ## -- # Default options for gem commands. -+ # Default options for gem commands for Ruby packagers. -+ # -+ # The options here should be structured as an array of string "gem" -+ # command names as keys and a string of the default options as values. -+ # -+ # Example: -+ # -+ # def self.operating_system_defaults -+ # { -+ # 'install' => '--no-rdoc --no-ri --env-shebang', -+ # 'update' => '--no-rdoc --no-ri --env-shebang' -+ # } -+ # end -+ -+ def self.operating_system_defaults -+ {} -+ end -+ -+ ## -+ # Default options for gem commands for Ruby implementers. - # - # The options here should be structured as an array of string "gem" - # command names as keys and a string of the default options as values. -diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb -index 3225a05c6b..62b80c4945 100644 ---- a/test/rubygems/test_gem.rb -+++ b/test/rubygems/test_gem.rb -@@ -1802,6 +1802,13 @@ def test_use_gemdeps_specific - ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps - end - -+ def test_operating_system_defaults -+ operating_system_defaults = Gem.operating_system_defaults -+ -+ assert operating_system_defaults != nil -+ assert operating_system_defaults.is_a? Hash -+ end -+ - def test_platform_defaults - platform_defaults = Gem.platform_defaults - diff --git a/ruby-2.5.1-Avoid-need-of-C++-compiler-to-pass-the-test-suite.patch b/ruby-2.5.1-Avoid-need-of-C++-compiler-to-pass-the-test-suite.patch deleted file mode 100644 index 413a1da..0000000 --- a/ruby-2.5.1-Avoid-need-of-C++-compiler-to-pass-the-test-suite.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 51e2c91412a511196e58efea5b87c460b4fa6a20 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Thu, 26 Jul 2018 13:17:52 +0200 -Subject: [PATCH] Avoid need of C++ compiler to pass the test suite. - -The test suite fails when C++ compiler is not available on the system: - -~~~ -TestGemExtCmakeBuilder#test_self_build: -Gem::InstallError: cmake failed, exit code 1 - /builddir/build/BUILD/ruby-2.5.1/lib/rubygems/ext/builder.rb:92:in `run' - /builddir/build/BUILD/ruby-2.5.1/lib/rubygems/ext/cmake_builder.rb:10:in `build' - /builddir/build/BUILD/ruby-2.5.1/test/rubygems/test_gem_ext_cmake_builder.rb:37:in `block in test_self_build' - /builddir/build/BUILD/ruby-2.5.1/test/rubygems/test_gem_ext_cmake_builder.rb:36:in `chdir' - /builddir/build/BUILD/ruby-2.5.1/test/rubygems/test_gem_ext_cmake_builder.rb:36:in `test_self_build' -~~~ - -But there is nothing which would realy required C++. It is just CMake -default to check for C++. ---- - test/rubygems/test_gem_ext_cmake_builder.rb | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/test/rubygems/test_gem_ext_cmake_builder.rb b/test/rubygems/test_gem_ext_cmake_builder.rb -index 76d3cb2afe..2d449fc2fd 100644 ---- a/test/rubygems/test_gem_ext_cmake_builder.rb -+++ b/test/rubygems/test_gem_ext_cmake_builder.rb -@@ -25,6 +25,7 @@ def test_self_build - File.open File.join(@ext, 'CMakeLists.txt'), 'w' do |cmakelists| - cmakelists.write <<-eo_cmake - cmake_minimum_required(VERSION 2.6) -+project(self_build LANGUAGES NONE) - install (FILES test.txt DESTINATION bin) - eo_cmake - end diff --git a/ruby-2.6.0-library-options-to-MAINLIBS.patch b/ruby-2.6.0-library-options-to-MAINLIBS.patch deleted file mode 100644 index 199798d..0000000 --- a/ruby-2.6.0-library-options-to-MAINLIBS.patch +++ /dev/null @@ -1,177 +0,0 @@ -From bb3db69e2a0c210cc3a63940622db96a97eb7947 Mon Sep 17 00:00:00 2001 -From: nobu -Date: Fri, 2 Mar 2018 01:37:53 +0000 -Subject: [PATCH] configure.ac: library options to MAINLIBS - -* configure.ac (MAINLIBS): moved library options for main program - and static libruby, and append MAINLIBS to LIBRUBYARG_STATIC, as - these libraries are not needed for linking to shared libruby. - [ruby-core:85882] [Bug #14422] - -git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62627 b2dd03c8-39d4-4d8f-98ff-823fe69b080e ---- - configure.ac | 33 +++++++++++++++------------------ - template/ruby.pc.in | 1 + - win32/Makefile.sub | 6 ++++-- - 3 files changed, 20 insertions(+), 20 deletions(-) - -diff --git a/configure.ac b/configure.ac -index aebbae1969a5..733a0c992fd7 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -10,6 +10,7 @@ AC_DISABLE_OPTION_CHECKING - AC_ARG_VAR([cflags], [additional CFLAGS]) - AC_ARG_VAR([cppflags], [additional CPPFLAGS]) - AC_ARG_VAR([cxxflags], [additional CXXFLAGS]) -+ORIG_LIBS=$LIBS - - AC_DEFUN([RUBY_RM_RECURSIVE], [ - m4_version_prereq([2.70], [-1], [ -@@ -2938,13 +2939,11 @@ AS_IF([test x"$enable_pthread" = xyes], [ - AC_DEFINE(_THREAD_SAFE) - AC_DEFINE(HAVE_LIBPTHREAD) - AC_CHECK_HEADERS(pthread_np.h, [], [], [@%:@include ]) -- AS_CASE([$pthread_lib], -- [c], [], -- [root], [], -- [c_r], [MAINLIBS="-pthread $MAINLIBS"], -- [AS_CASE(["$target_os"], -- [openbsd*|mirbsd*], [LIBS="-pthread $LIBS"], -- [LIBS="-l$pthread_lib $LIBS"])]) -+ AS_CASE(["$pthread_lib:$target_os"], -+ [c:*], [], -+ [root:*], [], -+ [c_r:*|*:openbsd*|*:mirbsd*], [LIBS="-pthread $LIBS"], -+ [LIBS="-l$pthread_lib $LIBS"]) - ], [ - AC_MSG_WARN("Don't know how to find pthread library on your system -- thread support disabled") - ]) -@@ -3623,7 +3622,7 @@ LIBRUBY_A='lib$(RUBY_SO_NAME)-static.a' - LIBRUBY='$(LIBRUBY_A)' - LIBRUBYARG_STATIC='-l$(RUBY_SO_NAME)-static' - LIBRUBYARG='$(LIBRUBYARG_STATIC)' --SOLIBS= -+SOLIBS='$(MAINLIBS)' - - AS_CASE(["$target_os"], - [cygwin*|mingw*|haiku*|darwin*], [ -@@ -3689,9 +3688,6 @@ AS_CASE("$enable_shared", [yes], [ - LIBRUBY_RELATIVE=no - test -z "$CCDLFLAGS" || CFLAGS="$CFLAGS $CCDLFLAGS" - ENABLE_SHARED=yes -- AS_IF([test "$rb_cv_binary_elf" = yes], [ -- SOLIBS='$(LIBS)' -- ]) - - # libdir can be overridden in config.site file (on OpenSUSE at least). - libdir_basename=lib -@@ -3726,7 +3722,6 @@ AS_CASE("$enable_shared", [yes], [ - ]) - ], - [freebsd*|dragonfly*], [ -- SOLIBS='$(LIBS)' - LIBRUBY_SO='lib$(RUBY_SO_NAME).$(SOEXT).$(MAJOR)$(MINOR)' - LIBRUBY_SONAME='$(LIBRUBY_SO)' - AS_IF([test "$rb_cv_binary_elf" != "yes" ], [ -@@ -3735,7 +3730,6 @@ AS_CASE("$enable_shared", [yes], [ - ]) - ], - [netbsd*], [ -- SOLIBS='$(LIBS)' - LIBRUBY_SONAME='lib$(RUBY_SO_NAME).$(SOEXT).$(MAJOR)$(MINOR)' - LIBRUBY_SO="${LIBRUBY_SONAME}"'.$(TEENY)' - RUBY_APPEND_OPTIONS(LIBRUBY_DLDFLAGS, ['-Wl,-soname,$(LIBRUBY_SONAME)' "$LDFLAGS_OPTDIR"]) -@@ -3746,11 +3740,9 @@ AS_CASE("$enable_shared", [yes], [ - ]) - ], - [openbsd*|mirbsd*], [ -- SOLIBS='$(LIBS)' - LIBRUBY_SO='lib$(RUBY_SO_NAME).$(SOEXT).$(MAJOR).'`expr ${MINOR} \* 10 + ${TEENY}` - ], - [solaris*], [ -- SOLIBS='$(LIBS)' - LIBRUBY_SO='lib$(RUBY_SO_NAME).$(SOEXT).$(MAJOR)' - LIBRUBY_SONAME='lib$(RUBY_SO_NAME).$(SOEXT).$(RUBY_PROGRAM_VERSION)' - LIBRUBY_ALIASES='$(LIBRUBY_SONAME) lib$(RUBY_SO_NAME).$(SOEXT)' -@@ -3768,7 +3760,7 @@ AS_CASE("$enable_shared", [yes], [ - [aix*], [ - RUBY_APPEND_OPTIONS(LIBRUBY_DLDFLAGS, ["${linker_flag}-bnoentry" "$XLDFLAGS" "$LDFLAGS_OPTDIR"]) - LIBRUBYARG_SHARED='-L${libdir} -l${RUBY_SO_NAME}' -- SOLIBS='-lm -lc' -+ LIBS="$LIBS -lm -lc" - ], - [darwin*], [ - LIBRUBY_LDSHARED='$(CC) -dynamiclib' -@@ -3788,7 +3780,6 @@ AS_CASE("$enable_shared", [yes], [ - LIBRUBY_SO='lib$(RUBY_SO_NAME).$(SOEXT)' - LIBRUBY_SONAME='lib$(RUBY_BASE_NAME).$(RUBY_API_VERSION).$(SOEXT)' - LIBRUBY_ALIASES='$(LIBRUBY_SONAME) lib$(RUBY_INSTALL_NAME).$(SOEXT)' -- SOLIBS='$(LIBS)' - ], - [interix*], [ - LIBRUBYARG_SHARED='-L. -L${libdir} -l$(RUBY_SO_NAME)' -@@ -4031,7 +4022,6 @@ AS_CASE(["$target_os"], - ]) - LIBRUBY_ALIASES='' - FIRSTMAKEFILE=GNUmakefile:cygwin/GNUmakefile.in -- SOLIBS='$(LIBS)' - AS_IF([test x"$enable_shared" = xyes], [ - LIBRUBY='lib$(RUBY_SO_NAME).dll.a' - ], [ -@@ -4131,6 +4121,13 @@ AS_IF([test "${universal_binary-no}" = yes ], [ - [rb_cv_architecture_available=yes], [rb_cv_architecture_available=no])) - ]) - -+MAINLIBS="$LIBS" -+LIBS=$ORIG_LIBS -+AS_IF([test -n "${LIBS}"], [ -+ libspat=`echo "${LIBS}" | sed 's/[[][|.*$^]]/\\&/g;s/^ */ /;s/^ *$/ /'` -+ MAINFLAGS=`echo " $MAINLIBS " | sed "s|$libspat"'||;s/^ *//;s/ *$//'` -+]) -+LIBRUBYARG_STATIC="${LIBRUBYARG_STATIC} \$(MAINLIBS)" - CPPFLAGS="$CPPFLAGS "'$(DEFS)' - test -z "$CPPFLAGS" || CPPFLAGS="$CPPFLAGS "; CPPFLAGS="$CPPFLAGS"'${cppflags}' - AS_IF([test -n "${cflags+set}"], [ -diff --git a/template/ruby.pc.in b/template/ruby.pc.in -index d874f92c3b20..7ce4461c05df 100644 ---- a/template/ruby.pc.in -+++ b/template/ruby.pc.in -@@ -39,6 +39,7 @@ sitehdrdir=@sitehdrdir@ - rubyarchhdrdir=@rubyarchhdrdir@ - vendorarchhdrdir=@vendorarchhdrdir@ - sitearchhdrdir=@sitearchhdrdir@ -+MAINLIBS=@MAINLIBS@ - SOEXT=@SOEXT@ - LIBPATH=@LIBPATH@ - LIBRUBY_A=@LIBRUBY_A@ -diff --git a/win32/Makefile.sub b/win32/Makefile.sub -index 8673c121641e..f8316cccb68e 100644 ---- a/win32/Makefile.sub -+++ b/win32/Makefile.sub -@@ -279,6 +279,7 @@ MJIT_DEBUGFLAGS = $(DEBUGFLAGS) - CPPFLAGS = $(DEFS) $(ARCHDEFS) $(CPPFLAGS) - - DLDFLAGS = $(LDFLAGS) -dll -+MAINLIBS = $(LIBS) - SOLIBS = - RCFILES = $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(RUBY_SO_NAME).rc - !ifndef RCFLAGS -@@ -821,7 +822,8 @@ s,@CPPFLAGS@,$(CPPFLAGS),;t t - s,@CXXFLAGS@,$(CXXFLAGS),;t t - s,@FFLAGS@,$(FFLAGS),;t t - s,@LDFLAGS@,$(LDFLAGS),;t t --s,@LIBS@,$(LIBS),;t t -+s,@LIBS@,,;t t -+s,@MAINLIBS@,$(MAINLIBS),;t t - s,@exec_prefix@,$${prefix},;t t - s,@prefix@,$(prefix),;t t - s,@program_transform_name@,s,.*,$(PROGRAM_PREFIX)&$(PROGRAM_SUFFIX),,;t t -@@ -909,7 +911,7 @@ s,@LIBRUBY_SO@,$$(RUBY_SO_NAME).dll,;t t - s,@LIBRUBY_ALIASES@,$(LIBRUBY_ALIASES),;t t - s,@LIBRUBY@,$$(RUBY_SO_NAME).lib,;t t - s,@LIBRUBYARG@,$$(LIBRUBYARG_SHARED),;t t --s,@LIBRUBYARG_STATIC@,$$(LIBRUBY_A),;t t -+s,@LIBRUBYARG_STATIC@,$$(LIBRUBY_A) $$(MAINLIBS),;t t - s,@LIBRUBYARG_SHARED@,$$(LIBRUBY),;t t - s,@SOLIBS@,$(SOLIBS),;t t - s,@DLDLIBS@,$(DLDLIBS),;t t 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-2.5.8.tar.xz b/ruby-3.0.3.tar.xz similarity index 51% rename from ruby-2.5.8.tar.xz rename to ruby-3.0.3.tar.xz index fdb92ec..7b56e82 100644 Binary files a/ruby-2.5.8.tar.xz and b/ruby-3.0.3.tar.xz differ diff --git a/ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch b/ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch new file mode 100644 index 0000000..cede1aa --- /dev/null +++ b/ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch @@ -0,0 +1,1004 @@ +From 6bbdaef1a578fdbfc6a5bf82402ba4d3fd733d4a Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 21 Mar 2017 18:23:53 +0900 +Subject: [PATCH 1/6] pkey: assume generic PKeys contain private components + +The EVP interface cannot tell whether if a pkey contains the private +components or not. Assume it does if it does not respond to #private?. +This fixes the NoMethodError on calling #sign on a generic PKey. +--- + ext/openssl/ossl_pkey.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 610a83fd2d..8d41623e80 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -252,12 +252,19 @@ GetPrivPKeyPtr(VALUE obj) + { + EVP_PKEY *pkey; + +- if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) { +- ossl_raise(rb_eArgError, "Private key is needed."); +- } + GetPKey(obj, pkey); ++ if (OSSL_PKEY_IS_PRIVATE(obj)) ++ return pkey; ++ /* ++ * The EVP API does not provide a way to check if the EVP_PKEY has private ++ * components. Assuming it does... ++ */ ++ if (!rb_respond_to(obj, id_private_q)) ++ return pkey; ++ if (RTEST(rb_funcallv(obj, id_private_q, 0, NULL))) ++ return pkey; + +- return pkey; ++ rb_raise(rb_eArgError, "private key is needed"); + } + + EVP_PKEY * +-- +2.32.0 + + +From 86508f74b3d41166ed6091b7b31f18a26478c347 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 20 Mar 2017 23:18:26 +0900 +Subject: [PATCH 2/6] pkey: add PKey.generate_parameters and .generate_key + +Add two methods to create a PKey using the generic EVP interface. This +is useful for the PKey types we don't have a dedicated class. +--- + ext/openssl/ossl_pkey.c | 222 ++++++++++++++++++++++++++++++++++++++ + test/openssl/test_pkey.rb | 43 ++++++++ + 2 files changed, 265 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 8d41623e80..1f3dd39b9b 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -197,6 +197,226 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) + return ossl_pkey_new(pkey); + } + ++static VALUE ++pkey_gen_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) ++{ ++ VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1); ++ EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v; ++ ++ if (SYMBOL_P(key)) ++ key = rb_sym2str(key); ++ value = rb_String(value); ++ ++ if (EVP_PKEY_CTX_ctrl_str(ctx, StringValueCStr(key), StringValueCStr(value)) <= 0) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_ctrl_str(ctx, %+"PRIsVALUE", %+"PRIsVALUE")", ++ key, value); ++ return Qnil; ++} ++ ++static VALUE ++pkey_gen_apply_options0(VALUE args_v) ++{ ++ VALUE *args = (VALUE *)args_v; ++ ++ rb_block_call(args[1], rb_intern("each"), 0, NULL, ++ pkey_gen_apply_options_i, args[0]); ++ return Qnil; ++} ++ ++struct pkey_blocking_generate_arg { ++ EVP_PKEY_CTX *ctx; ++ EVP_PKEY *pkey; ++ int state; ++ int yield: 1; ++ int genparam: 1; ++ int stop: 1; ++}; ++ ++static VALUE ++pkey_gen_cb_yield(VALUE ctx_v) ++{ ++ EVP_PKEY_CTX *ctx = (void *)ctx_v; ++ int i, info_num; ++ VALUE *argv; ++ ++ info_num = EVP_PKEY_CTX_get_keygen_info(ctx, -1); ++ argv = ALLOCA_N(VALUE, info_num); ++ for (i = 0; i < info_num; i++) ++ argv[i] = INT2NUM(EVP_PKEY_CTX_get_keygen_info(ctx, i)); ++ ++ return rb_yield_values2(info_num, argv); ++} ++ ++static int ++pkey_gen_cb(EVP_PKEY_CTX *ctx) ++{ ++ struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx); ++ ++ if (arg->yield) { ++ int state; ++ rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state); ++ if (state) { ++ arg->stop = 1; ++ arg->state = state; ++ } ++ } ++ return !arg->stop; ++} ++ ++static void ++pkey_blocking_gen_stop(void *ptr) ++{ ++ struct pkey_blocking_generate_arg *arg = ptr; ++ arg->stop = 1; ++} ++ ++static void * ++pkey_blocking_gen(void *ptr) ++{ ++ struct pkey_blocking_generate_arg *arg = ptr; ++ ++ if (arg->genparam && EVP_PKEY_paramgen(arg->ctx, &arg->pkey) <= 0) ++ return NULL; ++ if (!arg->genparam && EVP_PKEY_keygen(arg->ctx, &arg->pkey) <= 0) ++ return NULL; ++ return arg->pkey; ++} ++ ++static VALUE ++pkey_generate(int argc, VALUE *argv, VALUE self, int genparam) ++{ ++ EVP_PKEY_CTX *ctx; ++ VALUE alg, options; ++ struct pkey_blocking_generate_arg gen_arg = { 0 }; ++ int state; ++ ++ rb_scan_args(argc, argv, "11", &alg, &options); ++ if (rb_obj_is_kind_of(alg, cPKey)) { ++ EVP_PKEY *base_pkey; ++ ++ GetPKey(alg, base_pkey); ++ ctx = EVP_PKEY_CTX_new(base_pkey, NULL/* engine */); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ } ++ else { ++ const EVP_PKEY_ASN1_METHOD *ameth; ++ ENGINE *tmpeng; ++ int pkey_id; ++ ++ StringValue(alg); ++ ameth = EVP_PKEY_asn1_find_str(&tmpeng, RSTRING_PTR(alg), ++ RSTRING_LENINT(alg)); ++ if (!ameth) ++ ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", alg); ++ EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); ++#if !defined(OPENSSL_NO_ENGINE) ++ if (tmpeng) ++ ENGINE_finish(tmpeng); ++#endif ++ ++ ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id"); ++ } ++ ++ if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_paramgen_init"); ++ } ++ if (!genparam && EVP_PKEY_keygen_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_keygen_init"); ++ } ++ ++ if (!NIL_P(options)) { ++ VALUE args[2]; ++ ++ args[0] = (VALUE)ctx; ++ args[1] = options; ++ rb_protect(pkey_gen_apply_options0, (VALUE)args, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } ++ ++ gen_arg.genparam = genparam; ++ gen_arg.ctx = ctx; ++ gen_arg.yield = rb_block_given_p(); ++ EVP_PKEY_CTX_set_app_data(ctx, &gen_arg); ++ EVP_PKEY_CTX_set_cb(ctx, pkey_gen_cb); ++ if (gen_arg.yield) ++ pkey_blocking_gen(&gen_arg); ++ else ++ rb_thread_call_without_gvl(pkey_blocking_gen, &gen_arg, ++ pkey_blocking_gen_stop, &gen_arg); ++ EVP_PKEY_CTX_free(ctx); ++ if (!gen_arg.pkey) { ++ if (gen_arg.state) { ++ ossl_clear_error(); ++ rb_jump_tag(gen_arg.state); ++ } ++ else { ++ ossl_raise(ePKeyError, genparam ? "EVP_PKEY_paramgen" : "EVP_PKEY_keygen"); ++ } ++ } ++ ++ return ossl_pkey_new(gen_arg.pkey); ++} ++ ++/* ++ * call-seq: ++ * OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey ++ * ++ * Generates new parameters for the algorithm. _algo_name_ is a String that ++ * represents the algorithm. The optional argument _options_ is a Hash that ++ * specifies the options specific to the algorithm. The order of the options ++ * can be important. ++ * ++ * A block can be passed optionally. The meaning of the arguments passed to ++ * the block varies depending on the implementation of the algorithm. The block ++ * may be called once or multiple times, or may not even be called. ++ * ++ * For the supported options, see the documentation for the 'openssl genpkey' ++ * utility command. ++ * ++ * == Example ++ * pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048) ++ * p pkey.p.num_bits #=> 2048 ++ */ ++static VALUE ++ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self) ++{ ++ return pkey_generate(argc, argv, self, 1); ++} ++ ++/* ++ * call-seq: ++ * OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey ++ * OpenSSL::PKey.generate_key(pkey [, options]) -> pkey ++ * ++ * Generates a new key (pair). ++ * ++ * If a String is given as the first argument, it generates a new random key ++ * for the algorithm specified by the name just as ::generate_parameters does. ++ * If an OpenSSL::PKey::PKey is given instead, it generates a new random key ++ * for the same algorithm as the key, using the parameters the key contains. ++ * ++ * See ::generate_parameters for the details of _options_ and the given block. ++ * ++ * == Example ++ * pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048) ++ * pkey_params.priv_key #=> nil ++ * pkey = OpenSSL::PKey.generate_key(pkey_params) ++ * pkey.priv_key #=> # 512, ++ "dsa_paramgen_q_bits" => 256, ++ }) ++ assert_instance_of OpenSSL::PKey::DSA, pkey ++ assert_equal 512, pkey.p.num_bits ++ assert_equal 256, pkey.q.num_bits ++ assert_equal nil, pkey.priv_key ++ ++ # Invalid options are checked ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ OpenSSL::PKey.generate_parameters("DSA", "invalid" => "option") ++ } ++ ++ # Parameter generation callback is called ++ cb_called = [] ++ assert_raise(RuntimeError) { ++ OpenSSL::PKey.generate_parameters("DSA") { |*args| ++ cb_called << args ++ raise "exit!" if cb_called.size == 3 ++ } ++ } ++ assert_not_empty cb_called ++ end ++ ++ def test_s_generate_key ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ # DSA key pair cannot be generated without parameters ++ OpenSSL::PKey.generate_key("DSA") ++ } ++ pkey_params = OpenSSL::PKey.generate_parameters("DSA", { ++ "dsa_paramgen_bits" => 512, ++ "dsa_paramgen_q_bits" => 256, ++ }) ++ pkey = OpenSSL::PKey.generate_key(pkey_params) ++ assert_instance_of OpenSSL::PKey::DSA, pkey ++ assert_equal 512, pkey.p.num_bits ++ assert_not_equal nil, pkey.priv_key ++ end + end +-- +2.32.0 + + +From 5713605e70c96e3215aab0e0341548af29b5088e Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 15 May 2017 23:47:47 +0900 +Subject: [PATCH 3/6] pkey: port PKey::PKey#sign and #verify to the EVP_Digest* + interface + +Use EVP_DigestSign*() and EVP_DigestVerify*() interface instead of the +old EVP_Sign*() and EVP_Verify*() functions. They were added in OpenSSL +1.0.0. + +Also, allow the digest to be specified as nil, as certain EVP_PKEY types +don't expect a digest algorithm. +--- + ext/openssl/ossl_pkey.c | 90 ++++++++++++++++++++++----------------- + test/openssl/test_pkey.rb | 12 ++++++ + 2 files changed, 63 insertions(+), 39 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 1f3dd39b9b..a0d73f5821 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -753,35 +753,47 @@ static VALUE + ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + { + EVP_PKEY *pkey; +- const EVP_MD *md; ++ const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; +- unsigned int buf_len; +- VALUE str; +- int result; ++ size_t siglen; ++ int state; ++ VALUE sig; + + pkey = GetPrivPKeyPtr(self); +- md = ossl_evp_get_digestbyname(digest); ++ if (!NIL_P(digest)) ++ md = ossl_evp_get_digestbyname(digest); + StringValue(data); +- str = rb_str_new(0, EVP_PKEY_size(pkey)); + + ctx = EVP_MD_CTX_new(); + if (!ctx) +- ossl_raise(ePKeyError, "EVP_MD_CTX_new"); +- if (!EVP_SignInit_ex(ctx, md, NULL)) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_SignInit_ex"); ++ ossl_raise(ePKeyError, "EVP_MD_CTX_new"); ++ if (EVP_DigestSignInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignInit"); ++ } ++ if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignUpdate"); ++ } ++ if (EVP_DigestSignFinal(ctx, NULL, &siglen) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignFinal"); + } +- if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_SignUpdate"); ++ if (siglen > LONG_MAX) ++ rb_raise(ePKeyError, "signature would be too large"); ++ sig = ossl_str_new(NULL, (long)siglen, &state); ++ if (state) { ++ EVP_MD_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(sig), ++ &siglen) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSignFinal"); + } +- result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey); + EVP_MD_CTX_free(ctx); +- if (!result) +- ossl_raise(ePKeyError, "EVP_SignFinal"); +- rb_str_set_len(str, buf_len); +- +- return str; ++ rb_str_set_len(sig, siglen); ++ return sig; + } + + /* +@@ -809,38 +821,38 @@ static VALUE + ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + { + EVP_PKEY *pkey; +- const EVP_MD *md; ++ const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; +- int siglen, result; ++ int ret; + + GetPKey(self, pkey); + ossl_pkey_check_public_key(pkey); +- md = ossl_evp_get_digestbyname(digest); ++ if (!NIL_P(digest)) ++ md = ossl_evp_get_digestbyname(digest); + StringValue(sig); +- siglen = RSTRING_LENINT(sig); + StringValue(data); + + ctx = EVP_MD_CTX_new(); + if (!ctx) +- ossl_raise(ePKeyError, "EVP_MD_CTX_new"); +- if (!EVP_VerifyInit_ex(ctx, md, NULL)) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_VerifyInit_ex"); ++ ossl_raise(ePKeyError, "EVP_MD_CTX_new"); ++ if (EVP_DigestVerifyInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestVerifyInit"); + } +- if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { +- EVP_MD_CTX_free(ctx); +- ossl_raise(ePKeyError, "EVP_VerifyUpdate"); ++ if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate"); + } +- result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey); ++ ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), ++ RSTRING_LEN(sig)); + EVP_MD_CTX_free(ctx); +- switch (result) { +- case 0: +- ossl_clear_error(); +- return Qfalse; +- case 1: +- return Qtrue; +- default: +- ossl_raise(ePKeyError, "EVP_VerifyFinal"); ++ if (ret < 0) ++ ossl_raise(ePKeyError, "EVP_DigestVerifyFinal"); ++ if (ret) ++ return Qtrue; ++ else { ++ ossl_clear_error(); ++ return Qfalse; + } + } + +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index a325a1ea2b..247ba84f83 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -68,4 +68,16 @@ def test_s_generate_key + assert_equal 512, pkey.p.num_bits + assert_not_equal nil, pkey.priv_key + end ++ ++ def test_hmac_sign_verify ++ pkey = OpenSSL::PKey.generate_key("HMAC", { "key" => "abcd" }) ++ ++ hmac = OpenSSL::HMAC.new("abcd", "SHA256").update("data").digest ++ assert_equal hmac, pkey.sign("SHA256", "data") ++ ++ # EVP_PKEY_HMAC does not support verify ++ assert_raise(OpenSSL::PKey::PKeyError) { ++ pkey.verify("SHA256", "data", hmac) ++ } ++ end + end +-- +2.32.0 + + +From 76566a2e1bab42a2e1587ecbec23779ee00020fc Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 15 May 2017 23:47:47 +0900 +Subject: [PATCH 4/6] pkey: support 'one-shot' signing and verification + +OpenSSL 1.1.1 added EVP_DigestSign() and EVP_DigestVerify() functions +to the interface. Some EVP_PKEY methods such as PureEdDSA algorithms +do not support the streaming mechanism and require us to use them. +--- + ext/openssl/ossl_pkey.c | 30 ++++++++++++++++++++++++++ + test/openssl/test_pkey.rb | 45 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 75 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index a0d73f5821..19544ec7f0 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -771,6 +771,26 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignInit"); + } ++#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER) ++ if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSign"); ++ } ++ if (siglen > LONG_MAX) ++ rb_raise(ePKeyError, "signature would be too large"); ++ sig = ossl_str_new(NULL, (long)siglen, &state); ++ if (state) { ++ EVP_MD_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen, ++ (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)) < 1) { ++ EVP_MD_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_DigestSign"); ++ } ++#else + if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignUpdate"); +@@ -791,6 +811,7 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignFinal"); + } ++#endif + EVP_MD_CTX_free(ctx); + rb_str_set_len(sig, siglen); + return sig; +@@ -839,6 +860,14 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestVerifyInit"); + } ++#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER) ++ ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig), ++ RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data), ++ RSTRING_LEN(data)); ++ EVP_MD_CTX_free(ctx); ++ if (ret < 0) ++ ossl_raise(ePKeyError, "EVP_DigestVerify"); ++#else + if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate"); +@@ -848,6 +877,7 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + EVP_MD_CTX_free(ctx); + if (ret < 0) + ossl_raise(ePKeyError, "EVP_DigestVerifyFinal"); ++#endif + if (ret) + return Qtrue; + else { +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index 247ba84f83..d811b9c75f 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -80,4 +80,49 @@ def test_hmac_sign_verify + pkey.verify("SHA256", "data", hmac) + } + end ++ ++ def test_ed25519 ++ # Test vector from RFC 8032 Section 7.1 TEST 2 ++ priv_pem = <<~EOF ++ -----BEGIN PRIVATE KEY----- ++ MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 ++ -----END PRIVATE KEY----- ++ EOF ++ pub_pem = <<~EOF ++ -----BEGIN PUBLIC KEY----- ++ MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= ++ -----END PUBLIC KEY----- ++ EOF ++ begin ++ priv = OpenSSL::PKey.read(priv_pem) ++ pub = OpenSSL::PKey.read(pub_pem) ++ rescue OpenSSL::PKey::PKeyError ++ # OpenSSL < 1.1.1 ++ pend "Ed25519 is not implemented" ++ end ++ assert_instance_of OpenSSL::PKey::PKey, priv ++ assert_instance_of OpenSSL::PKey::PKey, pub ++ assert_equal priv_pem, priv.private_to_pem ++ assert_equal pub_pem, priv.public_to_pem ++ assert_equal pub_pem, pub.public_to_pem ++ ++ sig = [<<~EOF.gsub(/[^0-9a-f]/, "")].pack("H*") ++ 92a009a9f0d4cab8720e820b5f642540 ++ a2b27b5416503f8fb3762223ebdb69da ++ 085ac1e43e15996e458f3613d0f11d8c ++ 387b2eaeb4302aeeb00d291612bb0c00 ++ EOF ++ data = ["72"].pack("H*") ++ assert_equal sig, priv.sign(nil, data) ++ assert_equal true, priv.verify(nil, sig, data) ++ assert_equal true, pub.verify(nil, sig, data) ++ assert_equal false, pub.verify(nil, sig, data.succ) ++ ++ # PureEdDSA wants nil as the message digest ++ assert_raise(OpenSSL::PKey::PKeyError) { priv.sign("SHA512", data) } ++ assert_raise(OpenSSL::PKey::PKeyError) { pub.verify("SHA512", sig, data) } ++ ++ # Ed25519 pkey type does not support key derivation ++ assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) } ++ end + end +-- +2.32.0 + + +From fabdd22bddc572ba3342ec0b09e3fef8ed6245b8 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 18 Mar 2017 21:58:46 +0900 +Subject: [PATCH 5/6] pkey: add PKey::PKey#derive + +Add OpenSSL::PKey::PKey#derive as the wrapper for EVP_PKEY_CTX_derive(). +This is useful for pkey types that we don't have dedicated classes, such +as X25519. +--- + ext/openssl/ossl_pkey.c | 52 ++++++++++++++++++++++++++++++++++++ + test/openssl/test_pkey.rb | 26 ++++++++++++++++++ + test/openssl/test_pkey_dh.rb | 13 +++++++++ + test/openssl/test_pkey_ec.rb | 16 +++++++++++ + 4 files changed, 107 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 19544ec7f0..df8b425a0f 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -886,6 +886,57 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + } + } + ++/* ++ * call-seq: ++ * pkey.derive(peer_pkey) -> string ++ * ++ * Derives a shared secret from _pkey_ and _peer_pkey_. _pkey_ must contain ++ * the private components, _peer_pkey_ must contain the public components. ++ */ ++static VALUE ++ossl_pkey_derive(int argc, VALUE *argv, VALUE self) ++{ ++ EVP_PKEY *pkey, *peer_pkey; ++ EVP_PKEY_CTX *ctx; ++ VALUE peer_pkey_obj, str; ++ size_t keylen; ++ int state; ++ ++ GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "1", &peer_pkey_obj); ++ GetPKey(peer_pkey_obj, peer_pkey); ++ ++ ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); ++ if (EVP_PKEY_derive_init(ctx) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive_init"); ++ } ++ if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer"); ++ } ++ if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive"); ++ } ++ if (keylen > LONG_MAX) ++ rb_raise(ePKeyError, "derived key would be too large"); ++ str = ossl_str_new(NULL, (long)keylen, &state); ++ if (state) { ++ EVP_PKEY_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ ossl_raise(ePKeyError, "EVP_PKEY_derive"); ++ } ++ EVP_PKEY_CTX_free(ctx); ++ rb_str_set_len(str, keylen); ++ return str; ++} ++ + /* + * INIT + */ +@@ -983,6 +1034,7 @@ Init_ossl_pkey(void) + + rb_define_method(cPKey, "sign", ossl_pkey_sign, 2); + rb_define_method(cPKey, "verify", ossl_pkey_verify, 3); ++ rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); + + id_private_q = rb_intern("private?"); + +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index d811b9c75f..5307fe5b08 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -125,4 +125,30 @@ def test_ed25519 + # Ed25519 pkey type does not support key derivation + assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) } + end ++ ++ def test_x25519 ++ # Test vector from RFC 7748 Section 6.1 ++ alice_pem = <<~EOF ++ -----BEGIN PRIVATE KEY----- ++ MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq ++ -----END PRIVATE KEY----- ++ EOF ++ bob_pem = <<~EOF ++ -----BEGIN PUBLIC KEY----- ++ MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08= ++ -----END PUBLIC KEY----- ++ EOF ++ shared_secret = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" ++ begin ++ alice = OpenSSL::PKey.read(alice_pem) ++ bob = OpenSSL::PKey.read(bob_pem) ++ rescue OpenSSL::PKey::PKeyError ++ # OpenSSL < 1.1.0 ++ pend "X25519 is not implemented" ++ end ++ assert_instance_of OpenSSL::PKey::PKey, alice ++ assert_equal alice_pem, alice.private_to_pem ++ assert_equal bob_pem, bob.public_to_pem ++ assert_equal [shared_secret].pack("H*"), alice.derive(bob) ++ end + end +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index 4a05626a12..9efc3ba68d 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -18,6 +18,19 @@ def test_new_break + end + end + ++ def test_derive_key ++ dh1 = Fixtures.pkey("dh1024").generate_key! ++ dh2 = Fixtures.pkey("dh1024").generate_key! ++ dh1_pub = OpenSSL::PKey.read(dh1.public_to_der) ++ dh2_pub = OpenSSL::PKey.read(dh2.public_to_der) ++ z = dh1.g.mod_exp(dh1.priv_key, dh1.p).mod_exp(dh2.priv_key, dh1.p).to_s(2) ++ assert_equal z, dh1.derive(dh2_pub) ++ assert_equal z, dh2.derive(dh1_pub) ++ ++ assert_equal z, dh1.compute_key(dh2.pub_key) ++ assert_equal z, dh2.compute_key(dh1.pub_key) ++ end ++ + def test_DHparams + dh1024 = Fixtures.pkey("dh1024") + asn1 = OpenSSL::ASN1::Sequence([ +diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb +index a0e6a23ff8..95d4338a51 100644 +--- a/test/openssl/test_pkey_ec.rb ++++ b/test/openssl/test_pkey_ec.rb +@@ -93,6 +93,22 @@ def test_sign_verify + assert_equal false, p256.verify("SHA256", signature1, data) + end + ++ def test_derive_key ++ # NIST CAVP, KAS_ECC_CDH_PrimitiveTest.txt, P-256 COUNT = 0 ++ qCAVSx = "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" ++ qCAVSy = "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac" ++ dIUT = "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534" ++ zIUT = "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b" ++ a = OpenSSL::PKey::EC.new("prime256v1") ++ a.private_key = OpenSSL::BN.new(dIUT, 16) ++ b = OpenSSL::PKey::EC.new("prime256v1") ++ uncompressed = OpenSSL::BN.new("04" + qCAVSx + qCAVSy, 16) ++ b.public_key = OpenSSL::PKey::EC::Point.new(b.group, uncompressed) ++ assert_equal [zIUT].pack("H*"), a.derive(b) ++ ++ assert_equal a.derive(b), a.dh_compute_key(b.public_key) ++ end ++ + def test_dsa_sign_verify + data1 = "foo" + data2 = "bar" +-- +2.32.0 + + +From 97078c7fa8a724c7c71f9850d31fc401239da228 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 18 Mar 2017 22:34:19 +0900 +Subject: [PATCH 6/6] pkey: reimplement PKey::DH#compute_key and + PKey::EC#dh_compute_key + +Use the new OpenSSL::PKey::PKey#derive instead of the raw +{EC,}DH_compute_key(), mainly to reduce amount of the C code. +--- + ext/openssl/lib/openssl/pkey.rb | 33 +++++++++++++++++++++++++++++++ + ext/openssl/ossl_pkey_dh.c | 35 --------------------------------- + ext/openssl/ossl_pkey_ec.c | 32 ------------------------------ + 3 files changed, 33 insertions(+), 67 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 9cc3276356..be60ac2beb 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -9,6 +9,24 @@ + module OpenSSL::PKey + class DH + include OpenSSL::Marshal ++ ++ # :call-seq: ++ # dh.compute_key(pub_bn) -> string ++ # ++ # Returns a String containing a shared secret computed from the other ++ # party's public value. ++ # ++ # This method is provided for backwards compatibility, and calls #derive ++ # internally. ++ # ++ # === Parameters ++ # * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by ++ # DH#public_key as that contains the DH parameters only. ++ def compute_key(pub_bn) ++ peer = dup ++ peer.set_key(pub_bn, nil) ++ derive(peer) ++ end + end + + class DSA +@@ -18,7 +36,22 @@ class DSA + if defined?(EC) + class EC + include OpenSSL::Marshal ++ ++ # :call-seq: ++ # ec.dh_compute_key(pubkey) -> string ++ # ++ # Derives a shared secret by ECDH. _pubkey_ must be an instance of ++ # OpenSSL::PKey::EC::Point and must belong to the same group. ++ # ++ # This method is provided for backwards compatibility, and calls #derive ++ # internally. ++ def dh_compute_key(pubkey) ++ peer = OpenSSL::PKey::EC.new(group) ++ peer.public_key = pubkey ++ derive(peer) ++ end + end ++ + class EC::Point + # :call-seq: + # point.to_bn([conversion_form]) -> OpenSSL::BN +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index bc50e5566b..5bc1c49ca1 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -476,40 +476,6 @@ ossl_dh_generate_key(VALUE self) + return self; + } + +-/* +- * call-seq: +- * dh.compute_key(pub_bn) -> aString +- * +- * Returns a String containing a shared secret computed from the other party's public value. +- * See DH_compute_key() for further information. +- * +- * === Parameters +- * * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by +- * DH#public_key as that contains the DH parameters only. +- */ +-static VALUE +-ossl_dh_compute_key(VALUE self, VALUE pub) +-{ +- DH *dh; +- const BIGNUM *pub_key, *dh_p; +- VALUE str; +- int len; +- +- GetDH(self, dh); +- DH_get0_pqg(dh, &dh_p, NULL, NULL); +- if (!dh_p) +- ossl_raise(eDHError, "incomplete DH"); +- pub_key = GetBNPtr(pub); +- len = DH_size(dh); +- str = rb_str_new(0, len); +- if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) { +- ossl_raise(eDHError, NULL); +- } +- rb_str_set_len(str, len); +- +- return str; +-} +- + /* + * Document-method: OpenSSL::PKey::DH#set_pqg + * call-seq: +@@ -587,7 +553,6 @@ Init_ossl_dh(void) + rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0); + rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0); + rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0); +- rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1); + + DEF_OSSL_PKEY_BN(cDH, dh, p); + DEF_OSSL_PKEY_BN(cDH, dh, q); +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index 6fe2533e2a..c2534251c3 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -487,37 +487,6 @@ static VALUE ossl_ec_key_check_key(VALUE self) + return Qtrue; + } + +-/* +- * call-seq: +- * key.dh_compute_key(pubkey) => String +- * +- * See the OpenSSL documentation for ECDH_compute_key() +- */ +-static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey) +-{ +- EC_KEY *ec; +- EC_POINT *point; +- int buf_len; +- VALUE str; +- +- GetEC(self, ec); +- GetECPoint(pubkey, point); +- +-/* BUG: need a way to figure out the maximum string size */ +- buf_len = 1024; +- str = rb_str_new(0, buf_len); +-/* BUG: take KDF as a block */ +- buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL); +- if (buf_len < 0) +- ossl_raise(eECError, "ECDH_compute_key"); +- +- rb_str_resize(str, buf_len); +- +- return str; +-} +- +-/* sign_setup */ +- + /* + * call-seq: + * key.dsa_sign_asn1(data) => String +@@ -1657,7 +1626,6 @@ void Init_ossl_ec(void) + rb_define_alias(cEC, "generate_key", "generate_key!"); + rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0); + +- rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1); + rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1); + rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2); + /* do_sign/do_verify */ +-- +2.32.0 + diff --git a/ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch b/ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch new file mode 100644 index 0000000..679411a --- /dev/null +++ b/ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch @@ -0,0 +1,358 @@ +From f2cf3afc6fa1e13e960f732c0bc658ad408ee219 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 12 Jun 2020 14:12:59 +0900 +Subject: [PATCH 1/3] pkey: fix potential memory leak in PKey#sign + +Fix potential leak of EVP_MD_CTX object in an error path. This path is +normally unreachable, since the size of a signature generated by any +supported algorithms would not be larger than LONG_MAX. +--- + ext/openssl/ossl_pkey.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index df8b425a0f..7488190e0e 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -777,8 +777,10 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSign"); + } +- if (siglen > LONG_MAX) ++ if (siglen > LONG_MAX) { ++ EVP_MD_CTX_free(ctx); + rb_raise(ePKeyError, "signature would be too large"); ++ } + sig = ossl_str_new(NULL, (long)siglen, &state); + if (state) { + EVP_MD_CTX_free(ctx); +@@ -799,8 +801,10 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignFinal"); + } +- if (siglen > LONG_MAX) ++ if (siglen > LONG_MAX) { ++ EVP_MD_CTX_free(ctx); + rb_raise(ePKeyError, "signature would be too large"); ++ } + sig = ossl_str_new(NULL, (long)siglen, &state); + if (state) { + EVP_MD_CTX_free(ctx); +-- +2.32.0 + + +From 8b30ce20eb9e03180c28288e29a96308e594f860 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 2 Apr 2021 23:58:48 +0900 +Subject: [PATCH 2/3] pkey: prepare pkey_ctx_apply_options() for usage by other + operations + +The routine to apply Hash to EVP_PKEY_CTX_ctrl_str() is currently used +by key generation, but it is useful for other operations too. Let's +change it to a slightly more generic name. +--- + ext/openssl/ossl_pkey.c | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 7488190e0e..fed4a2b81f 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -198,7 +198,7 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) + } + + static VALUE +-pkey_gen_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) ++pkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) + { + VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1); + EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v; +@@ -214,15 +214,25 @@ pkey_gen_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v)) + } + + static VALUE +-pkey_gen_apply_options0(VALUE args_v) ++pkey_ctx_apply_options0(VALUE args_v) + { + VALUE *args = (VALUE *)args_v; + + rb_block_call(args[1], rb_intern("each"), 0, NULL, +- pkey_gen_apply_options_i, args[0]); ++ pkey_ctx_apply_options_i, args[0]); + return Qnil; + } + ++static void ++pkey_ctx_apply_options(EVP_PKEY_CTX *ctx, VALUE options, int *state) ++{ ++ VALUE args[2]; ++ args[0] = (VALUE)ctx; ++ args[1] = options; ++ ++ rb_protect(pkey_ctx_apply_options0, (VALUE)args, state); ++} ++ + struct pkey_blocking_generate_arg { + EVP_PKEY_CTX *ctx; + EVP_PKEY *pkey; +@@ -330,11 +340,7 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam) + } + + if (!NIL_P(options)) { +- VALUE args[2]; +- +- args[0] = (VALUE)ctx; +- args[1] = options; +- rb_protect(pkey_gen_apply_options0, (VALUE)args, &state); ++ pkey_ctx_apply_options(ctx, options, &state); + if (state) { + EVP_PKEY_CTX_free(ctx); + rb_jump_tag(state); +-- +2.32.0 + + +From 4c7b0f91da666961d11908b94520db4e09ce4e67 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 18 Jul 2020 20:40:39 +0900 +Subject: [PATCH 3/3] pkey: allow setting algorithm-specific options in #sign + and #verify + +Similarly to OpenSSL::PKey.generate_key and .generate_parameters, let +OpenSSL::PKey::PKey#sign and #verify take an optional parameter for +specifying control strings for EVP_PKEY_CTX_ctrl_str(). +--- + ext/openssl/ossl_pkey.c | 113 ++++++++++++++++++++++------------ + test/openssl/test_pkey_rsa.rb | 34 +++++----- + 2 files changed, 89 insertions(+), 58 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index fed4a2b81f..22e9f19982 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -739,33 +739,51 @@ ossl_pkey_public_to_pem(VALUE self) + } + + /* +- * call-seq: +- * pkey.sign(digest, data) -> String ++ * call-seq: ++ * pkey.sign(digest, data [, options]) -> string + * +- * To sign the String _data_, _digest_, an instance of OpenSSL::Digest, must +- * be provided. The return value is again a String containing the signature. +- * A PKeyError is raised should errors occur. +- * Any previous state of the Digest instance is irrelevant to the signature +- * outcome, the digest instance is reset to its initial state during the +- * operation. ++ * Hashes and signs the +data+ using a message digest algorithm +digest+ and ++ * a private key +pkey+. + * +- * == Example +- * data = 'Sign me!' +- * digest = OpenSSL::Digest.new('SHA256') +- * pkey = OpenSSL::PKey::RSA.new(2048) +- * signature = pkey.sign(digest, data) ++ * See #verify for the verification operation. ++ * ++ * See also the man page EVP_DigestSign(3). ++ * ++ * +digest+:: ++ * A String that represents the message digest algorithm name, or +nil+ ++ * if the PKey type requires no digest algorithm. ++ * For backwards compatibility, this can be an instance of OpenSSL::Digest. ++ * Its state will not affect the signature. ++ * +data+:: ++ * A String. The data to be hashed and signed. ++ * +options+:: ++ * A Hash that contains algorithm specific control operations to \OpenSSL. ++ * See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details. ++ * +options+ parameter was added in version 2.3. ++ * ++ * Example: ++ * data = "Sign me!" ++ * pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) ++ * signopts = { rsa_padding_mode: "pss" } ++ * signature = pkey.sign("SHA256", data, signopts) ++ * ++ * # Creates a copy of the RSA key pkey, but without the private components ++ * pub_key = pkey.public_key ++ * puts pub_key.verify("SHA256", signature, data, signopts) # => true + */ + static VALUE +-ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) ++ossl_pkey_sign(int argc, VALUE *argv, VALUE self) + { + EVP_PKEY *pkey; ++ VALUE digest, data, options, sig; + const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; ++ EVP_PKEY_CTX *pctx; + size_t siglen; + int state; +- VALUE sig; + + pkey = GetPrivPKeyPtr(self); ++ rb_scan_args(argc, argv, "21", &digest, &data, &options); + if (!NIL_P(digest)) + md = ossl_evp_get_digestbyname(digest); + StringValue(data); +@@ -773,10 +791,17 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + ctx = EVP_MD_CTX_new(); + if (!ctx) + ossl_raise(ePKeyError, "EVP_MD_CTX_new"); +- if (EVP_DigestSignInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) { ++ if (EVP_DigestSignInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestSignInit"); + } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(pctx, options, &state); ++ if (state) { ++ EVP_MD_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } + #if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER) + if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data), + RSTRING_LEN(data)) < 1) { +@@ -828,35 +853,40 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) + } + + /* +- * call-seq: +- * pkey.verify(digest, signature, data) -> String ++ * call-seq: ++ * pkey.verify(digest, signature, data [, options]) -> true or false + * +- * To verify the String _signature_, _digest_, an instance of +- * OpenSSL::Digest, must be provided to re-compute the message digest of the +- * original _data_, also a String. The return value is +true+ if the +- * signature is valid, +false+ otherwise. A PKeyError is raised should errors +- * occur. +- * Any previous state of the Digest instance is irrelevant to the validation +- * outcome, the digest instance is reset to its initial state during the +- * operation. ++ * Verifies the +signature+ for the +data+ using a message digest algorithm ++ * +digest+ and a public key +pkey+. + * +- * == Example +- * data = 'Sign me!' +- * digest = OpenSSL::Digest.new('SHA256') +- * pkey = OpenSSL::PKey::RSA.new(2048) +- * signature = pkey.sign(digest, data) +- * pub_key = pkey.public_key +- * puts pub_key.verify(digest, signature, data) # => true ++ * Returns +true+ if the signature is successfully verified, +false+ otherwise. ++ * The caller must check the return value. ++ * ++ * See #sign for the signing operation and an example. ++ * ++ * See also the man page EVP_DigestVerify(3). ++ * ++ * +digest+:: ++ * See #sign. ++ * +signature+:: ++ * A String containing the signature to be verified. ++ * +data+:: ++ * See #sign. ++ * +options+:: ++ * See #sign. +options+ parameter was added in version 2.3. + */ + static VALUE +-ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) ++ossl_pkey_verify(int argc, VALUE *argv, VALUE self) + { + EVP_PKEY *pkey; ++ VALUE digest, sig, data, options; + const EVP_MD *md = NULL; + EVP_MD_CTX *ctx; +- int ret; ++ EVP_PKEY_CTX *pctx; ++ int state, ret; + + GetPKey(self, pkey); ++ rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options); + ossl_pkey_check_public_key(pkey); + if (!NIL_P(digest)) + md = ossl_evp_get_digestbyname(digest); +@@ -866,10 +896,17 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) + ctx = EVP_MD_CTX_new(); + if (!ctx) + ossl_raise(ePKeyError, "EVP_MD_CTX_new"); +- if (EVP_DigestVerifyInit(ctx, NULL, md, /* engine */NULL, pkey) < 1) { ++ if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_DigestVerifyInit"); + } ++ if (!NIL_P(options)) { ++ pkey_ctx_apply_options(pctx, options, &state); ++ if (state) { ++ EVP_MD_CTX_free(ctx); ++ rb_jump_tag(state); ++ } ++ } + #if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER) + ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig), + RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data), +@@ -1042,8 +1079,8 @@ Init_ossl_pkey(void) + rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0); + rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0); + +- rb_define_method(cPKey, "sign", ossl_pkey_sign, 2); +- rb_define_method(cPKey, "verify", ossl_pkey_verify, 3); ++ rb_define_method(cPKey, "sign", ossl_pkey_sign, -1); ++ rb_define_method(cPKey, "verify", ossl_pkey_verify, -1); + rb_define_method(cPKey, "derive", ossl_pkey_derive, -1); + + id_private_q = rb_intern("private?"); +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index 88164c3b52..d1e68dbc9f 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -117,27 +117,21 @@ def test_sign_verify + assert_equal false, rsa1024.verify("SHA256", signature1, data) + end + +- def test_digest_state_irrelevant_sign ++ def test_sign_verify_options + key = Fixtures.pkey("rsa1024") +- digest1 = OpenSSL::Digest.new('SHA1') +- digest2 = OpenSSL::Digest.new('SHA1') +- data = 'Sign me!' +- digest1 << 'Change state of digest1' +- sig1 = key.sign(digest1, data) +- sig2 = key.sign(digest2, data) +- assert_equal(sig1, sig2) +- end +- +- def test_digest_state_irrelevant_verify +- key = Fixtures.pkey("rsa1024") +- digest1 = OpenSSL::Digest.new('SHA1') +- digest2 = OpenSSL::Digest.new('SHA1') +- data = 'Sign me!' +- sig = key.sign(digest1, data) +- digest1.reset +- digest1 << 'Change state of digest1' +- assert(key.verify(digest1, sig, data)) +- assert(key.verify(digest2, sig, data)) ++ data = "Sign me!" ++ pssopts = { ++ "rsa_padding_mode" => "pss", ++ "rsa_pss_saltlen" => 20, ++ "rsa_mgf1_md" => "SHA1" ++ } ++ sig_pss = key.sign("SHA256", data, pssopts) ++ assert_equal 128, sig_pss.bytesize ++ assert_equal true, key.verify("SHA256", sig_pss, data, pssopts) ++ assert_equal true, key.verify_pss("SHA256", sig_pss, data, ++ salt_length: 20, mgf1_hash: "SHA1") ++ # Defaults to PKCS #1 v1.5 padding => verification failure ++ assert_equal false, key.verify("SHA256", sig_pss, data) + end + + def test_verify_empty_rsa +-- +2.32.0 + diff --git a/ruby-3.1.0-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-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..f03f28a --- /dev/null +++ b/ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch @@ -0,0 +1,142 @@ +From 8f948ed68a4ed6c05ff66d822711e3b70ae4bb3f Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 27 Sep 2021 13:32:03 +0900 +Subject: [PATCH 1/3] ext/openssl/ossl.h: add helper macros for + OpenSSL/LibreSSL versions + +Add following convenient macros: + + - OSSL_IS_LIBRESSL + - OSSL_OPENSSL_PREREQ(maj, min, pat) + - OSSL_LIBRESSL_PREREQ(maj, min, pat) +--- + ext/openssl/ossl.h | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h +index c20f506bda..a0cef29d74 100644 +--- a/ext/openssl/ossl.h ++++ b/ext/openssl/ossl.h +@@ -43,6 +43,18 @@ + #include + #include + ++#ifndef LIBRESSL_VERSION_NUMBER ++# define OSSL_IS_LIBRESSL 0 ++# define OSSL_OPENSSL_PREREQ(maj, min, pat) \ ++ (OPENSSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12)) ++# define OSSL_LIBRESSL_PREREQ(maj, min, pat) 0 ++#else ++# define OSSL_IS_LIBRESSL 1 ++# define OSSL_OPENSSL_PREREQ(maj, min, pat) 0 ++# define OSSL_LIBRESSL_PREREQ(maj, min, pat) \ ++ (LIBRESSL_VERSION_NUMBER >= (maj << 28) | (min << 20) | (pat << 12)) ++#endif ++ + /* + * Common Module + */ +-- +2.32.0 + + +From bbf235091e49807ece8f3a3df95bbfcc9d3ab43d Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 22 Feb 2020 05:37:01 +0900 +Subject: [PATCH 2/3] ts: use TS_VERIFY_CTX_set_certs instead of + TS_VERIFY_CTS_set_certs + +OpenSSL 3.0 fixed the typo in the function name and replaced the +current 'CTS' version with a macro. +--- + ext/openssl/extconf.rb | 5 ++++- + ext/openssl/openssl_missing.h | 5 +++++ + ext/openssl/ossl_ts.c | 2 +- + 3 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index 17d93443fc..09cae05b72 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -166,7 +166,7 @@ def find_openssl_library + have_func("TS_STATUS_INFO_get0_status") + have_func("TS_STATUS_INFO_get0_text") + have_func("TS_STATUS_INFO_get0_failure_info") +-have_func("TS_VERIFY_CTS_set_certs") ++have_func("TS_VERIFY_CTS_set_certs(NULL, NULL)", "openssl/ts.h") + have_func("TS_VERIFY_CTX_set_store") + have_func("TS_VERIFY_CTX_add_flags") + have_func("TS_RESP_CTX_set_time_cb") +@@ -175,6 +175,9 @@ def find_openssl_library + + # added in 1.1.1 + have_func("EVP_PKEY_check") ++ ++# added in 3.0.0 ++have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", "openssl/ts.h") + + Logging::message "=== Checking done. ===\n" + +diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h +index e575415f49..fe486bcfcf 100644 +--- a/ext/openssl/openssl_missing.h ++++ b/ext/openssl/openssl_missing.h +@@ -242,4 +242,9 @@ IMPL_PKEY_GETTER(EC_KEY, ec) + } while (0) + #endif + ++/* added in 3.0.0 */ ++#if !defined(HAVE_TS_VERIFY_CTX_SET_CERTS) ++# define TS_VERIFY_CTX_set_certs(ctx, crts) TS_VERIFY_CTS_set_certs(ctx, crts) ++#endif ++ + #endif /* _OSSL_OPENSSL_MISSING_H_ */ +diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c +index 692c0d620f..f1da7c1947 100644 +--- a/ext/openssl/ossl_ts.c ++++ b/ext/openssl/ossl_ts.c +@@ -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/3] ssl: use SSL_get_rbio() to check if SSL is started or not + +Use SSL_get_rbio() instead of SSL_get_fd(). SSL_get_fd() internally +calls SSL_get_rbio() and it's enough for our purpose. + +In OpenSSL 3.0, SSL_get_fd() leaves an entry in the OpenSSL error queue +if BIO has not been set up yet, and we would have to clean it up. +--- + ext/openssl/ossl_ssl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c +index 4b7efa39f5..ec430bfb0c 100644 +--- a/ext/openssl/ossl_ssl.c ++++ b/ext/openssl/ossl_ssl.c +@@ -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 + 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-SSL_read-EOF-handling.patch b/ruby-3.1.0-SSL_read-EOF-handling.patch new file mode 100644 index 0000000..1c5660f --- /dev/null +++ b/ruby-3.1.0-SSL_read-EOF-handling.patch @@ -0,0 +1,16 @@ +diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c +index 3b425ca..40e748c 100644 +--- a/ext/openssl/ossl_ssl.c ++++ b/ext/openssl/ossl_ssl.c +@@ -1870,6 +1870,11 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) + return str; + + GetSSL(self, ssl); ++ ++#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF ++ SSL_set_options(ssl, SSL_OP_IGNORE_UNEXPECTED_EOF); ++#endif ++ + io = rb_attr_get(self, id_i_io); + GetOpenFile(io, fptr); + if (ssl_started(ssl)) { diff --git a/ruby-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-Support-OpenSSL-3.0.patch b/ruby-3.1.0-Support-OpenSSL-3.0.patch new file mode 100644 index 0000000..e701ad0 --- /dev/null +++ b/ruby-3.1.0-Support-OpenSSL-3.0.patch @@ -0,0 +1,1101 @@ +From bc9cbef395fc8fc7f81c3911b92966abc693169a Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 24 Oct 2021 17:50:18 +0900 +Subject: [PATCH 01/10] test/openssl/test_cipher: update test_ciphers + +Do not attempt to actually use all algorithms. Not all algorithms listed +in OpenSSL::Cipher.ciphers are always available; some may belong to the +legacy provider in OpenSSL 3.0. +--- + test/openssl/test_cipher.rb | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb +index 178f5aba0e..395183b22d 100644 +--- a/test/openssl/test_cipher.rb ++++ b/test/openssl/test_cipher.rb +@@ -135,14 +135,11 @@ def test_ctr_if_exists + end + + def test_ciphers +- OpenSSL::Cipher.ciphers.each{|name| +- next if /netbsd/ =~ RUBY_PLATFORM && /idea|rc5/i =~ name +- begin +- assert_kind_of(OpenSSL::Cipher, OpenSSL::Cipher.new(name)) +- rescue OpenSSL::Cipher::CipherError => e +- raise unless /wrap/ =~ name and /wrap mode not allowed/ =~ e.message +- end +- } ++ ciphers = OpenSSL::Cipher.ciphers ++ assert_kind_of Array, ciphers ++ assert_include ciphers, "aes-128-cbc" ++ assert_include ciphers, "aes128" # alias of aes-128-cbc ++ assert_include ciphers, "aes-128-gcm" + end + + def test_AES +-- +2.32.0 + + +From f73998da49d2cd273b38b542ddd49a4ceaf5bfa9 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Wed, 3 Nov 2021 23:31:29 +0900 +Subject: [PATCH 02/10] test/openssl/test_pkey_rsa: test concatenated PEM + parsing + +PEM-encoded private keys are sometimes stored together with irrelevant +PEM blocks, such as the corresponding X.509 certificate. + +PEM_read_bio_*() family automatically skips unknown PEM blocks, but on +OpenSSL 3.0 we will be using the new OSSL_DECODER API instead, due to +some behavior changes around the password callback. + +Let's add a test case so that we won't break the current behavior. +--- + test/openssl/test_pkey_rsa.rb | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index 4548bdb2cf..327449ae03 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -306,6 +306,12 @@ def test_RSAPrivateKey + + assert_equal asn1.to_der, rsa1024.to_der + assert_equal pem, rsa1024.export ++ ++ # Unknown PEM prepended ++ cert = issue_cert(OpenSSL::X509::Name.new([["CN", "nobody"]]), rsa1024, 1, [], nil, nil) ++ str = cert.to_text + cert.to_pem + rsa1024.to_pem ++ key = OpenSSL::PKey::RSA.new(str) ++ assert_same_rsa rsa1024, key + end + + def test_RSAPrivateKey_encrypted +-- +2.32.0 + + +From eb44c4c0eff7a63f9b0bc5d7a7a0df014f1c1b62 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 20 Mar 2021 23:16:16 +0900 +Subject: [PATCH 03/10] pkey: use OSSL_DECODER to load encrypted PEM on OpenSSL + 3.0 + +The routines to load pkeys (PEM_read_bio_* and d2i_* functions) have +been rewritten around the newly introduced OSSL_DECODER API in OpenSSL +3.0. They now first try to decrypt and parse a PEM block, and then check +the kind. Since we try to parse a given string using each of them in +turn, this means the password callback may now be called more than once. + +Let's use the OSSL_DECODER API directly on OpenSSL 3.0 to avoid this +from happening. +--- + ext/openssl/ossl_pkey.c | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index ba909c7632..4eab598942 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -78,6 +78,45 @@ ossl_pkey_new(EVP_PKEY *pkey) + return obj; + } + ++#if OSSL_OPENSSL_PREREQ(3, 0, 0) ++# include ++ ++EVP_PKEY * ++ossl_pkey_read_generic(BIO *bio, VALUE pass) ++{ ++ void *ppass = (void *)pass; ++ OSSL_DECODER_CTX *dctx; ++ EVP_PKEY *pkey = NULL; ++ int pos = 0, pos2; ++ ++ dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, NULL, 0, NULL, NULL); ++ if (!dctx) ++ goto out; ++ if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1) ++ goto out; ++ ++ /* First check DER */ ++ if (OSSL_DECODER_from_bio(dctx, bio) == 1) ++ goto out; ++ ++ /* Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed */ ++ OSSL_BIO_reset(bio); ++ if (OSSL_DECODER_CTX_set_input_type(dctx, "PEM") != 1) ++ goto out; ++ while (OSSL_DECODER_from_bio(dctx, bio) != 1) { ++ if (BIO_eof(bio)) ++ goto out; ++ pos2 = BIO_tell(bio); ++ if (pos2 < 0 || pos2 <= pos) ++ goto out; ++ pos = pos2; ++ } ++ ++ out: ++ OSSL_DECODER_CTX_free(dctx); ++ return pkey; ++} ++#else + EVP_PKEY * + ossl_pkey_read_generic(BIO *bio, VALUE pass) + { +@@ -106,6 +145,7 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass) + out: + return pkey; + } ++#endif + + /* + * call-seq: +-- +2.32.0 + + +From 588165c3235a23f0df58c8ec50ad6f46a05580f1 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sat, 20 Mar 2021 23:16:41 +0900 +Subject: [PATCH 04/10] pkey: assume a pkey always has public key components on + OpenSSL 3.0 + +Do not check the key components in this way because they are not +necessarily accessible in this way. +--- + ext/openssl/ossl_pkey.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 4eab598942..a805b4dc99 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -428,9 +428,19 @@ ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self) + return pkey_generate(argc, argv, self, 0); + } + ++/* ++ * TODO: There is no convenient way to check the presence of public key ++ * components on OpenSSL 3.0. But since keys are immutable on 3.0, pkeys without ++ * these should only be created by OpenSSL::PKey.generate_parameters or by ++ * parsing DER-/PEM-encoded string. We would need another flag for that. ++ */ + void + ossl_pkey_check_public_key(const EVP_PKEY *pkey) + { ++#if OSSL_OPENSSL_PREREQ(3, 0, 0) ++ if (EVP_PKEY_missing_parameters(pkey)) ++ ossl_raise(ePKeyError, "parameters missing"); ++#else + void *ptr; + const BIGNUM *n, *e, *pubkey; + +@@ -466,6 +476,7 @@ ossl_pkey_check_public_key(const EVP_PKEY *pkey) + return; + } + ossl_raise(ePKeyError, "public key missing"); ++#endif + } + + EVP_PKEY * +-- +2.32.0 + + +From 4c362a1fad72fd570985e4f401ba534456252cb3 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 12 Apr 2021 10:43:46 +0900 +Subject: [PATCH 05/10] pkey: use EVP_PKEY_CTX_new_from_name() on OpenSSL 3.0 + +Replace EVP_PKEY_CTX_new_id() with the new EVP_PKEY_CTX_new_from_name() +which takes the algorithm name as a string rather than a NID. +--- + ext/openssl/ossl_pkey.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index a805b4dc99..73a54eb2fb 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -315,6 +315,11 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); + } + else { ++#if OSSL_OPENSSL_PREREQ(3, 0, 0) ++ ctx = EVP_PKEY_CTX_new_from_name(NULL, StringValueCStr(alg), NULL); ++ if (!ctx) ++ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_from_name"); ++#else + const EVP_PKEY_ASN1_METHOD *ameth; + ENGINE *tmpeng; + int pkey_id; +@@ -333,6 +338,7 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam) + ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */); + if (!ctx) + ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id"); ++#endif + } + + if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) { +-- +2.32.0 + + +From 013c8552b845a8607f9a0639a07e1515fe067cd3 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 12 Apr 2021 13:55:10 +0900 +Subject: [PATCH 06/10] pkey: do not check NULL argument in ossl_pkey_new() + +Since the function takes the ownership, the caller is supposed to know +that the lifetime of the object - that is, it is never NULL. In fact, +it is properly checked by the caller in all code paths. +--- + ext/openssl/ossl_pkey.c | 6 +----- + ext/openssl/ossl_pkey.h | 1 + + 2 files changed, 2 insertions(+), 5 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 73a54eb2fb..5320d70a48 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -38,12 +38,8 @@ static VALUE + pkey_new0(EVP_PKEY *pkey) + { + VALUE klass, obj; +- int type; + +- if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE) +- ossl_raise(rb_eRuntimeError, "pkey is empty"); +- +- switch (type) { ++ switch (EVP_PKEY_base_id(pkey)) { + #if !defined(OPENSSL_NO_RSA) + case EVP_PKEY_RSA: klass = cRSA; break; + #endif +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index 629c16ae1f..d57e9c0f15 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -35,6 +35,7 @@ extern const rb_data_type_t ossl_evp_pkey_type; + } \ + } while (0) + ++/* Takes ownership of the EVP_PKEY */ + VALUE ossl_pkey_new(EVP_PKEY *); + void ossl_pkey_check_public_key(const EVP_PKEY *); + EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE); +-- +2.32.0 + + +From 2a9f958d71922303f223d4dcc15049d7dfa962a9 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 12 Apr 2021 18:32:40 +0900 +Subject: [PATCH 07/10] pkey: lazily initialize EVP_PKEY + +Allocate an EVP_PKEY when the content is ready: when #initialize +or #initialize_copy is called, rather than when OpenSSL::PKey::PKey is +allocated. + +This simplifies #initialize's and the upcoming generic #initialize_copy +implementation. +--- + ext/openssl/ossl_pkey.c | 15 ++---- + ext/openssl/ossl_pkey.h | 19 +++----- + ext/openssl/ossl_pkey_dh.c | 69 ++++++++++++++++++++-------- + ext/openssl/ossl_pkey_dsa.c | 87 +++++++++++++++++++++-------------- + ext/openssl/ossl_pkey_ec.c | 92 ++++++++++++++++++++----------------- + ext/openssl/ossl_pkey_rsa.c | 91 +++++++++++++++++++++--------------- + 6 files changed, 217 insertions(+), 156 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 5320d70a48..9ddfaafe7c 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -54,8 +54,8 @@ pkey_new0(EVP_PKEY *pkey) + #endif + default: klass = cPKey; break; + } +- obj = NewPKey(klass); +- SetPKey(obj, pkey); ++ obj = rb_obj_alloc(klass); ++ RTYPEDDATA_DATA(obj) = pkey; + return obj; + } + +@@ -528,16 +528,7 @@ DupPKeyPtr(VALUE obj) + static VALUE + ossl_pkey_alloc(VALUE klass) + { +- EVP_PKEY *pkey; +- VALUE obj; +- +- obj = NewPKey(klass); +- if (!(pkey = EVP_PKEY_new())) { +- ossl_raise(ePKeyError, NULL); +- } +- SetPKey(obj, pkey); +- +- return obj; ++ return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL); + } + + /* +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index d57e9c0f15..ac386717d7 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -15,21 +15,14 @@ extern VALUE cPKey; + extern VALUE ePKeyError; + extern const rb_data_type_t ossl_evp_pkey_type; + +-#define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue) +-#define OSSL_PKEY_SET_PUBLIC(obj) rb_iv_set((obj), "private", Qfalse) +-#define OSSL_PKEY_IS_PRIVATE(obj) (rb_iv_get((obj), "private") == Qtrue) ++/* For ENGINE */ ++#define OSSL_PKEY_SET_PRIVATE(obj) rb_ivar_set((obj), rb_intern("private"), Qtrue) ++#define OSSL_PKEY_IS_PRIVATE(obj) (rb_attr_get((obj), rb_intern("private")) == Qtrue) + +-#define NewPKey(klass) \ +- TypedData_Wrap_Struct((klass), &ossl_evp_pkey_type, 0) +-#define SetPKey(obj, pkey) do { \ +- if (!(pkey)) { \ +- rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \ +- } \ +- RTYPEDDATA_DATA(obj) = (pkey); \ +- OSSL_PKEY_SET_PUBLIC(obj); \ +-} while (0) ++#define GetPKey0(obj, pkey) \ ++ TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)) + #define GetPKey(obj, pkey) do {\ +- TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \ ++ GetPKey0((obj), (pkey)); \ + if (!(pkey)) { \ + rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\ + } \ +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index ca782bbe59..7d8e0fa502 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -76,7 +76,10 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) + BIO *in; + VALUE arg; + +- GetPKey(self, pkey); ++ GetPKey0(self, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); ++ + /* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */ + if (rb_scan_args(argc, argv, "01", &arg) == 0) { + dh = DH_new(); +@@ -84,22 +87,44 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) + ossl_raise(eDHError, "DH_new"); + } + else { +- arg = ossl_to_der_if_possible(arg); +- in = ossl_obj2bio(&arg); +- dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); +- if (!dh){ +- OSSL_BIO_reset(in); +- dh = d2i_DHparams_bio(in, NULL); +- } +- BIO_free(in); +- if (!dh) { +- ossl_raise(eDHError, NULL); +- } ++ int type; ++ ++ arg = ossl_to_der_if_possible(arg); ++ in = ossl_obj2bio(&arg); ++ ++ /* First try DER-encoded parameters */ ++ dh = d2i_DHparams_bio(in, NULL); ++ OSSL_BIO_reset(in); ++ if (dh) { ++ BIO_free(in); ++ goto legacy; ++ } ++ ++ /* Use the generic routine - parses PEM-encoded parameters */ ++ pkey = ossl_pkey_read_generic(in, Qnil); ++ BIO_free(in); ++ if (!pkey) ++ ossl_raise(eDHError, "could not parse pkey"); ++ ++ type = EVP_PKEY_base_id(pkey); ++ if (type != EVP_PKEY_DH) { ++ EVP_PKEY_free(pkey); ++ rb_raise(eDHError, "incorrect pkey type: %s", OBJ_nid2sn(type)); ++ } ++ RTYPEDDATA_DATA(self) = pkey; ++ return self; + } +- if (!EVP_PKEY_assign_DH(pkey, dh)) { +- DH_free(dh); +- ossl_raise(eDHError, NULL); ++ ++ legacy: ++ if (dh) { ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) { ++ EVP_PKEY_free(pkey); ++ DH_free(dh); ++ ossl_raise(eDHError, "EVP_PKEY_assign_DH"); ++ } + } ++ RTYPEDDATA_DATA(self) = pkey; + return self; + } + +@@ -110,15 +135,14 @@ ossl_dh_initialize_copy(VALUE self, VALUE other) + DH *dh, *dh_other; + const BIGNUM *pub, *priv; + +- GetPKey(self, pkey); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) +- ossl_raise(eDHError, "DH already initialized"); ++ GetPKey0(self, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + GetDH(other, dh_other); + + dh = DHparams_dup(dh_other); + if (!dh) + ossl_raise(eDHError, "DHparams_dup"); +- EVP_PKEY_assign_DH(pkey, dh); + + DH_get0_key(dh_other, &pub, &priv); + if (pub) { +@@ -133,6 +157,13 @@ ossl_dh_initialize_copy(VALUE self, VALUE other) + DH_set0_key(dh, pub2, priv2); + } + ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) { ++ EVP_PKEY_free(pkey); ++ DH_free(dh); ++ ossl_raise(eDHError, "EVP_PKEY_assign_DH"); ++ } ++ RTYPEDDATA_DATA(self) = pkey; + return self; + } + +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index 7af00eebec..1bba6c54b7 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -83,12 +83,16 @@ VALUE eDSAError; + static VALUE + ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) + { +- EVP_PKEY *pkey, *tmp; +- DSA *dsa = NULL; ++ EVP_PKEY *pkey; ++ DSA *dsa; + BIO *in; + VALUE arg, pass; ++ int type; ++ ++ GetPKey0(self, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + +- GetPKey(self, pkey); + /* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ + rb_scan_args(argc, argv, "02", &arg, &pass); + if (argc == 0) { +@@ -97,36 +101,41 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) + ossl_raise(eDSAError, "DSA_new"); + } + else { +- pass = ossl_pem_passwd_value(pass); +- arg = ossl_to_der_if_possible(arg); +- in = ossl_obj2bio(&arg); +- +- tmp = ossl_pkey_read_generic(in, pass); +- if (tmp) { +- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_DSA) +- rb_raise(eDSAError, "incorrect pkey type: %s", +- OBJ_nid2sn(EVP_PKEY_base_id(tmp))); +- dsa = EVP_PKEY_get1_DSA(tmp); +- EVP_PKEY_free(tmp); ++ pass = ossl_pem_passwd_value(pass); ++ arg = ossl_to_der_if_possible(arg); ++ in = ossl_obj2bio(&arg); ++ ++ dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey, ++ PEM_STRING_DSA_PUBLIC, ++ in, NULL, NULL, NULL); ++ OSSL_BIO_reset(in); ++ if (dsa) ++ goto legacy; ++ ++ pkey = ossl_pkey_read_generic(in, pass); ++ BIO_free(in); ++ if (!pkey) ++ ossl_raise(eDSAError, "Neither PUB key nor PRIV key"); ++ ++ type = EVP_PKEY_base_id(pkey); ++ if (type != EVP_PKEY_DSA) { ++ EVP_PKEY_free(pkey); ++ rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type)); + } +- if (!dsa) { +- OSSL_BIO_reset(in); +-#define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \ +- (d2i_of_void *)d2i_DSAPublicKey, PEM_STRING_DSA_PUBLIC, (bp), (void **)(x), (cb), (u)) +- dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL); +-#undef PEM_read_bio_DSAPublicKey +- } +- BIO_free(in); +- if (!dsa) { +- ossl_clear_error(); +- ossl_raise(eDSAError, "Neither PUB key nor PRIV key"); +- } +- } +- if (!EVP_PKEY_assign_DSA(pkey, dsa)) { +- DSA_free(dsa); +- ossl_raise(eDSAError, NULL); ++ RTYPEDDATA_DATA(self) = pkey; ++ return self; + } + ++ legacy: ++ if (dsa) { ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) { ++ EVP_PKEY_free(pkey); ++ DSA_free(dsa); ++ ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); ++ } ++ } ++ RTYPEDDATA_DATA(self) = pkey; + return self; + } + +@@ -136,16 +145,24 @@ ossl_dsa_initialize_copy(VALUE self, VALUE other) + EVP_PKEY *pkey; + DSA *dsa, *dsa_new; + +- GetPKey(self, pkey); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) +- ossl_raise(eDSAError, "DSA already initialized"); ++ GetPKey0(self, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + GetDSA(other, dsa); + +- dsa_new = ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, (d2i_of_void *)d2i_DSAPrivateKey, (char *)dsa); ++ dsa_new = (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, ++ (d2i_of_void *)d2i_DSAPrivateKey, ++ (char *)dsa); + if (!dsa_new) + ossl_raise(eDSAError, "ASN1_dup"); + +- EVP_PKEY_assign_DSA(pkey, dsa_new); ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) { ++ EVP_PKEY_free(pkey); ++ DSA_free(dsa_new); ++ ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); ++ } ++ RTYPEDDATA_DATA(self) = pkey; + + return self; + } +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index f52e67079d..bec9937bc6 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -114,13 +114,16 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg) + VALUE obj; + + obj = rb_obj_alloc(klass); +- GetPKey(obj, pkey); + + ec = ec_key_new_from_group(arg); +- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) { ++ EVP_PKEY_free(pkey); + EC_KEY_free(ec); + ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); + } ++ RTYPEDDATA_DATA(obj) = pkey; ++ + if (!EC_KEY_generate_key(ec)) + ossl_raise(eECError, "EC_KEY_generate_key"); + +@@ -141,51 +144,55 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg) + static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) + { + EVP_PKEY *pkey; +- EC_KEY *ec = NULL; ++ EC_KEY *ec; ++ BIO *in; + VALUE arg, pass; ++ int type; + +- GetPKey(self, pkey); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) +- ossl_raise(eECError, "EC_KEY already initialized"); ++ GetPKey0(self, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + + rb_scan_args(argc, argv, "02", &arg, &pass); +- + if (NIL_P(arg)) { + if (!(ec = EC_KEY_new())) +- ossl_raise(eECError, NULL); +- } else if (rb_obj_is_kind_of(arg, cEC)) { +- EC_KEY *other_ec = NULL; +- +- GetEC(arg, other_ec); +- if (!(ec = EC_KEY_dup(other_ec))) +- ossl_raise(eECError, NULL); +- } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { +- ec = ec_key_new_from_group(arg); +- } else { +- BIO *in = ossl_obj2bio(&arg); +- EVP_PKEY *tmp; ++ ossl_raise(eECError, "EC_KEY_new"); ++ } ++ else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { ++ ec = ec_key_new_from_group(arg); ++ } ++ else { + pass = ossl_pem_passwd_value(pass); +- tmp = ossl_pkey_read_generic(in, pass); +- if (tmp) { +- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_EC) +- rb_raise(eECError, "incorrect pkey type: %s", +- OBJ_nid2sn(EVP_PKEY_base_id(tmp))); +- ec = EVP_PKEY_get1_EC_KEY(tmp); +- EVP_PKEY_free(tmp); ++ arg = ossl_to_der_if_possible(arg); ++ in = ossl_obj2bio(&arg); ++ ++ pkey = ossl_pkey_read_generic(in, pass); ++ BIO_free(in); ++ if (!pkey) { ++ ossl_clear_error(); ++ ec = ec_key_new_from_group(arg); ++ goto legacy; + } +- BIO_free(in); + +- if (!ec) { +- ossl_clear_error(); +- ec = ec_key_new_from_group(arg); +- } ++ type = EVP_PKEY_base_id(pkey); ++ if (type != EVP_PKEY_EC) { ++ EVP_PKEY_free(pkey); ++ rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type)); ++ } ++ RTYPEDDATA_DATA(self) = pkey; ++ return self; + } + +- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { +- EC_KEY_free(ec); +- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); ++ legacy: ++ if (ec) { ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) { ++ EVP_PKEY_free(pkey); ++ EC_KEY_free(ec); ++ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); ++ } + } +- ++ RTYPEDDATA_DATA(self) = pkey; + return self; + } + +@@ -195,18 +202,21 @@ ossl_ec_key_initialize_copy(VALUE self, VALUE other) + EVP_PKEY *pkey; + EC_KEY *ec, *ec_new; + +- GetPKey(self, pkey); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) +- ossl_raise(eECError, "EC already initialized"); ++ GetPKey0(self, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + GetEC(other, ec); + + ec_new = EC_KEY_dup(ec); + if (!ec_new) + ossl_raise(eECError, "EC_KEY_dup"); +- if (!EVP_PKEY_assign_EC_KEY(pkey, ec_new)) { +- EC_KEY_free(ec_new); +- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); ++ ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_new) != 1) { ++ EC_KEY_free(ec_new); ++ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); + } ++ RTYPEDDATA_DATA(self) = pkey; + + return self; + } +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 8ebd3ec559..446150c8af 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -76,12 +76,16 @@ VALUE eRSAError; + static VALUE + ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + { +- EVP_PKEY *pkey, *tmp; +- RSA *rsa = NULL; ++ EVP_PKEY *pkey; ++ RSA *rsa; + BIO *in; + VALUE arg, pass; ++ int type; ++ ++ GetPKey0(self, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + +- GetPKey(self, pkey); + /* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ + rb_scan_args(argc, argv, "02", &arg, &pass); + if (argc == 0) { +@@ -90,37 +94,45 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + ossl_raise(eRSAError, "RSA_new"); + } + else { +- pass = ossl_pem_passwd_value(pass); +- arg = ossl_to_der_if_possible(arg); +- in = ossl_obj2bio(&arg); +- +- tmp = ossl_pkey_read_generic(in, pass); +- if (tmp) { +- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_RSA) +- rb_raise(eRSAError, "incorrect pkey type: %s", +- OBJ_nid2sn(EVP_PKEY_base_id(tmp))); +- rsa = EVP_PKEY_get1_RSA(tmp); +- EVP_PKEY_free(tmp); ++ pass = ossl_pem_passwd_value(pass); ++ arg = ossl_to_der_if_possible(arg); ++ in = ossl_obj2bio(&arg); ++ ++ /* First try RSAPublicKey format */ ++ rsa = d2i_RSAPublicKey_bio(in, NULL); ++ OSSL_BIO_reset(in); ++ if (rsa) ++ goto legacy; ++ rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); ++ OSSL_BIO_reset(in); ++ if (rsa) ++ goto legacy; ++ ++ /* Use the generic routine */ ++ pkey = ossl_pkey_read_generic(in, pass); ++ BIO_free(in); ++ if (!pkey) ++ ossl_raise(eRSAError, "Neither PUB key nor PRIV key"); ++ ++ type = EVP_PKEY_base_id(pkey); ++ if (type != EVP_PKEY_RSA) { ++ EVP_PKEY_free(pkey); ++ rb_raise(eRSAError, "incorrect pkey type: %s", OBJ_nid2sn(type)); + } +- if (!rsa) { +- OSSL_BIO_reset(in); +- rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL); +- } +- if (!rsa) { +- OSSL_BIO_reset(in); +- rsa = d2i_RSAPublicKey_bio(in, NULL); +- } +- BIO_free(in); +- if (!rsa) { +- ossl_clear_error(); +- ossl_raise(eRSAError, "Neither PUB key nor PRIV key"); +- } +- } +- if (!EVP_PKEY_assign_RSA(pkey, rsa)) { +- RSA_free(rsa); +- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); ++ RTYPEDDATA_DATA(self) = pkey; ++ return self; + } + ++ legacy: ++ if (rsa) { ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa) != 1) { ++ EVP_PKEY_free(pkey); ++ RSA_free(rsa); ++ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); ++ } ++ } ++ RTYPEDDATA_DATA(self) = pkey; + return self; + } + +@@ -130,16 +142,23 @@ ossl_rsa_initialize_copy(VALUE self, VALUE other) + EVP_PKEY *pkey; + RSA *rsa, *rsa_new; + +- GetPKey(self, pkey); +- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) +- ossl_raise(eRSAError, "RSA already initialized"); ++ GetPKey0(self, pkey); ++ if (pkey) ++ rb_raise(rb_eTypeError, "pkey already initialized"); + GetRSA(other, rsa); + +- rsa_new = ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey, (d2i_of_void *)d2i_RSAPrivateKey, (char *)rsa); ++ rsa_new = (RSA *)ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey, ++ (d2i_of_void *)d2i_RSAPrivateKey, ++ (char *)rsa); + if (!rsa_new) + ossl_raise(eRSAError, "ASN1_dup"); + +- EVP_PKEY_assign_RSA(pkey, rsa_new); ++ pkey = EVP_PKEY_new(); ++ if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa_new) != 1) { ++ RSA_free(rsa_new); ++ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); ++ } ++ RTYPEDDATA_DATA(self) = pkey; + + return self; + } +-- +2.32.0 + + +From 0ea28ac73e094bbb379b0915a67d44582e5e20da Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Thu, 22 Apr 2021 18:29:30 +0900 +Subject: [PATCH 08/10] pkey: deprecate OpenSSL::PKey::{RSA,DSA,DH}#set_* + methods + +The underlying OpenSSL functions, {RSA,DSA,DH}_set_*() are removed in +OpenSSL 3.0. + +Since the plan is to make EVP_PKEY immutable, there will be no direct +replacement for them and we have no choice here. + +It is suggested for users to use OpenSSL::PKey.from_data instead, +which construct a pkey from all necessary parameters at once. +--- + ext/openssl/ossl_pkey.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index ac386717d7..f6ad961937 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -130,6 +130,8 @@ static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALU + BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\ + BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\ + \ ++ rb_warning(#_keytype"#set_"#_group"= is incompatible with " \ ++ "OpenSSL 3.0; check OpenSSL::PKey.from_data"); \ + Get##_type(self, obj); \ + if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \ + (orig_bn2 && !(bn2 = BN_dup(orig_bn2))) || \ +@@ -160,6 +162,8 @@ static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \ + BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\ + BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\ + \ ++ rb_warning(#_keytype"#set_"#_group"= is incompatible with " \ ++ "OpenSSL 3.0; check OpenSSL::PKey.from_data"); \ + Get##_type(self, obj); \ + if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \ + (orig_bn2 && !(bn2 = BN_dup(orig_bn2)))) { \ +-- +2.32.0 + + +From 6fda9b5c292fbaae2eb7d6c8e15f1ff53ae7e50c Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Tue, 21 Sep 2021 18:29:59 +0900 +Subject: [PATCH 09/10] test/openssl/test_pkey_ec: update test_check_key for + OpenSSL 3.0 + +OpenSSL::PKey::EC#generate_key! or #private_key= will not work on +OpenSSL 3.0. +--- + test/openssl/test_pkey_ec.rb | 32 +++++++++++++++++++------------- + 1 file changed, 19 insertions(+), 13 deletions(-) + +diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb +index d62f1b5eb8..730ad28062 100644 +--- a/test/openssl/test_pkey_ec.rb ++++ b/test/openssl/test_pkey_ec.rb +@@ -60,22 +60,28 @@ def test_marshal + end + + def test_check_key +- key = OpenSSL::PKey::EC.new("prime256v1").generate_key! +- assert_equal(true, key.check_key) +- assert_equal(true, key.private?) +- assert_equal(true, key.public?) +- key2 = OpenSSL::PKey::EC.new(key.group) +- assert_equal(false, key2.private?) +- assert_equal(false, key2.public?) +- key2.public_key = key.public_key +- assert_equal(false, key2.private?) +- assert_equal(true, key2.public?) +- key2.private_key = key.private_key ++ key0 = Fixtures.pkey("p256") ++ assert_equal(true, key0.check_key) ++ assert_equal(true, key0.private?) ++ assert_equal(true, key0.public?) ++ ++ key1 = OpenSSL::PKey.read(key0.public_to_der) ++ assert_equal(true, key1.check_key) ++ assert_equal(false, key1.private?) ++ assert_equal(true, key1.public?) ++ ++ key2 = OpenSSL::PKey.read(key0.private_to_der) + assert_equal(true, key2.private?) + assert_equal(true, key2.public?) + assert_equal(true, key2.check_key) +- key2.private_key += 1 +- assert_raise(OpenSSL::PKey::ECError) { key2.check_key } ++ ++ # EC#private_key= is deprecated in 3.0 and won't work on OpenSSL 3.0 ++ if !openssl?(3, 0, 0) ++ EnvUtil.suppress_warning do ++ key2.private_key += 1 ++ assert_raise(OpenSSL::PKey::ECError) { key2.check_key } ++ end ++ end + end + + def test_sign_verify +-- +2.32.0 + + +From b63c0cb012981613463bdf4d80dcaedfa494a0d0 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 22 Oct 2021 16:24:07 +0900 +Subject: [PATCH 10/10] pkey/dh: deprecate OpenSSL::PKey::DH#generate_key! + +OpenSSL 3.0.0 has made keys immutable, so PKey::DH#generate_key! can't +work on it anymore. + +It's advised to use OpenSSL::PKey.generate_key instead. +--- + ext/openssl/lib/openssl/pkey.rb | 26 ++++++++++++++++++++++---- + test/openssl/test_pkey_dh.rb | 33 ++++++++++++++++++--------------- + 2 files changed, 40 insertions(+), 19 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index f6bf5892b0..cad376855d 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -61,14 +61,32 @@ def compute_key(pub_bn) + # called first in order to generate the per-session keys before performing + # the actual key exchange. + # ++ # Deprecated in version 3.0. This method is incompatible with ++ # OpenSSL 3.0.0 or later. ++ # + # See also OpenSSL::PKey.generate_key. + # + # Example: +- # dh = OpenSSL::PKey::DH.new(2048) +- # public_key = dh.public_key #contains no private/public key yet +- # public_key.generate_key! +- # puts public_key.private? # => true ++ # # DEPRECATED USAGE: This will not work on OpenSSL 3.0 or later ++ # dh0 = OpenSSL::PKey::DH.new(2048) ++ # dh = dh0.public_key # #public_key only copies the DH parameters (contrary to the name) ++ # dh.generate_key! ++ # puts dh.private? # => true ++ # puts dh0.pub_key == dh.pub_key #=> false ++ # ++ # # With OpenSSL::PKey.generate_key ++ # dh0 = OpenSSL::PKey::DH.new(2048) ++ # dh = OpenSSL::PKey.generate_key(dh0) ++ # puts dh0.pub_key == dh.pub_key #=> false + def generate_key! ++ msg = "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \ ++ "use OpenSSL::PKey.generate_key instead" ++ if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000 ++ raise DHError, msg ++ else ++ warn "#{caller(1, 1)[0]}: warning: #{msg}" ++ end ++ + unless priv_key + tmp = OpenSSL::PKey.generate_key(self) + set_key(tmp.pub_key, tmp.priv_key) +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index 757704caf6..248f4ebb42 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -26,14 +26,19 @@ def test_new_break + end + + def test_derive_key +- dh1 = Fixtures.pkey("dh1024").generate_key! +- dh2 = Fixtures.pkey("dh1024").generate_key! ++ params = Fixtures.pkey("dh1024") ++ dh1 = OpenSSL::PKey.generate_key(params) ++ dh2 = OpenSSL::PKey.generate_key(params) + dh1_pub = OpenSSL::PKey.read(dh1.public_to_der) + dh2_pub = OpenSSL::PKey.read(dh2.public_to_der) ++ + z = dh1.g.mod_exp(dh1.priv_key, dh1.p).mod_exp(dh2.priv_key, dh1.p).to_s(2) + assert_equal z, dh1.derive(dh2_pub) + assert_equal z, dh2.derive(dh1_pub) + ++ assert_raise(OpenSSL::PKey::PKeyError) { params.derive(dh1_pub) } ++ assert_raise(OpenSSL::PKey::PKeyError) { dh1_pub.derive(params) } ++ + assert_equal z, dh1.compute_key(dh2.pub_key) + assert_equal z, dh2.compute_key(dh1.pub_key) + end +@@ -74,19 +79,17 @@ def test_public_key + end + + def test_generate_key +- dh = Fixtures.pkey("dh1024").public_key # creates a copy +- assert_no_key(dh) +- dh.generate_key! +- assert_key(dh) +- end +- +- def test_key_exchange +- dh = Fixtures.pkey("dh1024") +- dh2 = dh.public_key +- dh.generate_key! +- dh2.generate_key! +- assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key)) +- end ++ EnvUtil.suppress_warning { # Deprecated in v3.0.0; incompatible with OpenSSL 3.0 ++ dh = Fixtures.pkey("dh1024").public_key # creates a copy with params only ++ assert_no_key(dh) ++ dh.generate_key! ++ assert_key(dh) ++ ++ dh2 = dh.public_key ++ dh2.generate_key! ++ assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key)) ++ } ++ end if !openssl?(3, 0, 0) + + def test_params_ok? + dh0 = Fixtures.pkey("dh1024") +-- +2.32.0 + diff --git a/ruby-3.1.0-Use-EVP-API-in-more-places.patch b/ruby-3.1.0-Use-EVP-API-in-more-places.patch new file mode 100644 index 0000000..4938949 --- /dev/null +++ b/ruby-3.1.0-Use-EVP-API-in-more-places.patch @@ -0,0 +1,831 @@ +From cf070378020088cd7e69b1cb08be68152ab8a078 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 17 May 2020 18:25:38 +0900 +Subject: [PATCH 1/3] pkey: implement #to_text using EVP API + +Use EVP_PKEY_print_private() instead of the low-level API *_print() +functions, such as RSA_print(). + +EVP_PKEY_print_*() family was added in OpenSSL 1.0.0. + +Note that it falls back to EVP_PKEY_print_public() and +EVP_PKEY_print_params() as necessary. This is required for EVP_PKEY_DH +type for which _private() fails if the private component is not set in +the pkey object. + +Since the new API works in the same way for all key types, we now +implement #to_text in the base class OpenSSL::PKey::PKey rather than in +each subclass. +--- + ext/openssl/ossl_pkey.c | 38 +++++++++++++++++++++++++++++++++++++ + ext/openssl/ossl_pkey_dh.c | 29 ---------------------------- + ext/openssl/ossl_pkey_dsa.c | 29 ---------------------------- + ext/openssl/ossl_pkey_ec.c | 27 -------------------------- + ext/openssl/ossl_pkey_rsa.c | 31 ------------------------------ + test/openssl/test_pkey.rb | 5 +++++ + 6 files changed, 43 insertions(+), 116 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index f9282b9417..21cd4b2cda 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -539,6 +539,43 @@ ossl_pkey_inspect(VALUE self) + OBJ_nid2sn(nid)); + } + ++/* ++ * call-seq: ++ * pkey.to_text -> string ++ * ++ * Dumps key parameters, public key, and private key components contained in ++ * the key into a human-readable text. ++ * ++ * This is intended for debugging purpose. ++ * ++ * See also the man page EVP_PKEY_print_private(3). ++ */ ++static VALUE ++ossl_pkey_to_text(VALUE self) ++{ ++ EVP_PKEY *pkey; ++ BIO *bio; ++ ++ GetPKey(self, pkey); ++ if (!(bio = BIO_new(BIO_s_mem()))) ++ ossl_raise(ePKeyError, "BIO_new"); ++ ++ if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1) ++ goto out; ++ OSSL_BIO_reset(bio); ++ if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1) ++ goto out; ++ ++ BIO_free(bio); ++ ossl_raise(ePKeyError, "EVP_PKEY_print_params"); ++ ++ out: ++ return ossl_membio2str(bio); ++} ++ + VALUE + ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der) + { +@@ -1039,6 +1076,7 @@ Init_ossl_pkey(void) + rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0); + rb_define_method(cPKey, "oid", ossl_pkey_oid, 0); + rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0); ++ rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0); + rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1); + rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1); + rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0); +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index 6b477b077c..acd3bf474e 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -266,34 +266,6 @@ ossl_dh_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * dh.to_text -> aString +- * +- * Prints all parameters of key to buffer +- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! +- * Don't use :-)) (I's up to you) +- */ +-static VALUE +-ossl_dh_to_text(VALUE self) +-{ +- DH *dh; +- BIO *out; +- VALUE str; +- +- GetDH(self, dh); +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eDHError, NULL); +- } +- if (!DHparams_print(out, dh)) { +- BIO_free(out); +- ossl_raise(eDHError, NULL); +- } +- str = ossl_membio2str(out); +- +- return str; +-} +- + /* + * call-seq: + * dh.public_key -> aDH +@@ -426,7 +398,6 @@ Init_ossl_dh(void) + rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1); + rb_define_method(cDH, "public?", ossl_dh_is_public, 0); + rb_define_method(cDH, "private?", ossl_dh_is_private, 0); +- rb_define_method(cDH, "to_text", ossl_dh_to_text, 0); + rb_define_method(cDH, "export", ossl_dh_export, 0); + rb_define_alias(cDH, "to_pem", "export"); + rb_define_alias(cDH, "to_s", "export"); +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index 1c5a8a737e..f017cceb4a 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -264,34 +264,6 @@ ossl_dsa_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * dsa.to_text -> aString +- * +- * Prints all parameters of key to buffer +- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! +- * Don't use :-)) (I's up to you) +- */ +-static VALUE +-ossl_dsa_to_text(VALUE self) +-{ +- DSA *dsa; +- BIO *out; +- VALUE str; +- +- GetDSA(self, dsa); +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eDSAError, NULL); +- } +- if (!DSA_print(out, dsa, 0)) { /* offset = 0 */ +- BIO_free(out); +- ossl_raise(eDSAError, NULL); +- } +- str = ossl_membio2str(out); +- +- return str; +-} +- + /* + * call-seq: + * dsa.public_key -> aDSA +@@ -469,7 +441,6 @@ Init_ossl_dsa(void) + + rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0); + rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0); +- rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0); + rb_define_method(cDSA, "export", ossl_dsa_export, -1); + rb_define_alias(cDSA, "to_pem", "export"); + rb_define_alias(cDSA, "to_s", "export"); +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index c2534251c3..ecb8305184 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -417,32 +417,6 @@ ossl_ec_key_to_der(VALUE self) + else + return ossl_pkey_export_spki(self, 1); + } +- +-/* +- * call-seq: +- * key.to_text => String +- * +- * See the OpenSSL documentation for EC_KEY_print() +- */ +-static VALUE ossl_ec_key_to_text(VALUE self) +-{ +- EC_KEY *ec; +- BIO *out; +- VALUE str; +- +- GetEC(self, ec); +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eECError, "BIO_new(BIO_s_mem())"); +- } +- if (!EC_KEY_print(out, ec, 0)) { +- BIO_free(out); +- ossl_raise(eECError, "EC_KEY_print"); +- } +- str = ossl_membio2str(out); +- +- return str; +-} +- + /* + * call-seq: + * key.generate_key! => self +@@ -1633,7 +1607,6 @@ void Init_ossl_ec(void) + rb_define_method(cEC, "export", ossl_ec_key_export, -1); + rb_define_alias(cEC, "to_pem", "export"); + rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0); +- rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0); + + + rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc); +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 43f82cb29e..7a7e66dbda 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -587,36 +587,6 @@ ossl_rsa_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * rsa.to_text => String +- * +- * THIS METHOD IS INSECURE, PRIVATE INFORMATION CAN LEAK OUT!!! +- * +- * Dumps all parameters of a keypair to a String +- * +- * Don't use :-)) (It's up to you) +- */ +-static VALUE +-ossl_rsa_to_text(VALUE self) +-{ +- RSA *rsa; +- BIO *out; +- VALUE str; +- +- GetRSA(self, rsa); +- if (!(out = BIO_new(BIO_s_mem()))) { +- ossl_raise(eRSAError, NULL); +- } +- if (!RSA_print(out, rsa, 0)) { /* offset = 0 */ +- BIO_free(out); +- ossl_raise(eRSAError, NULL); +- } +- str = ossl_membio2str(out); +- +- return str; +-} +- + /* + * call-seq: + * rsa.public_key -> RSA +@@ -738,7 +708,6 @@ Init_ossl_rsa(void) + + rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0); + rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0); +- rb_define_method(cRSA, "to_text", ossl_rsa_to_text, 0); + rb_define_method(cRSA, "export", ossl_rsa_export, -1); + rb_define_alias(cRSA, "to_pem", "export"); + rb_define_alias(cRSA, "to_s", "export"); +diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb +index 5307fe5b08..3630458b3c 100644 +--- a/test/openssl/test_pkey.rb ++++ b/test/openssl/test_pkey.rb +@@ -151,4 +151,9 @@ def test_x25519 + assert_equal bob_pem, bob.public_to_pem + assert_equal [shared_secret].pack("H*"), alice.derive(bob) + end ++ ++ def test_to_text ++ rsa = Fixtures.pkey("rsa1024") ++ assert_include rsa.to_text, "publicExponent" ++ end + end +-- +2.32.0 + + +From 0c45b22e485bfa62f4d704b08e3704e6444118c4 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Thu, 15 Apr 2021 19:11:32 +0900 +Subject: [PATCH 2/3] pkey: implement {DH,DSA,RSA}#public_key in Ruby + +The low-level API that is used to implement #public_key is deprecated +in OpenSSL 3.0. It is actually very simple to implement in another way, +using existing methods only, in much shorter code. Let's do it. + +While we are at it, the documentation is updated to recommend against +using #public_key. Now that OpenSSL::PKey::PKey implements public_to_der +method, there is no real use case for #public_key in newly written Ruby +programs. +--- + ext/openssl/lib/openssl/pkey.rb | 55 ++++++++++++++++++++++++++++ + ext/openssl/ossl_pkey_dh.c | 63 +++++++-------------------------- + ext/openssl/ossl_pkey_dsa.c | 42 ---------------------- + ext/openssl/ossl_pkey_rsa.c | 58 +----------------------------- + test/openssl/test_pkey_rsa.rb | 37 ++++++++++--------- + 5 files changed, 87 insertions(+), 168 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 53ee52f98b..569559e1ce 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -10,6 +10,30 @@ module OpenSSL::PKey + class DH + include OpenSSL::Marshal + ++ # :call-seq: ++ # dh.public_key -> dhnew ++ # ++ # Returns a new DH instance that carries just the \DH parameters. ++ # ++ # Contrary to the method name, the returned DH object contains only ++ # parameters and not the public key. ++ # ++ # This method is provided for backwards compatibility. In most cases, there ++ # is no need to call this method. ++ # ++ # For the purpose of re-generating the key pair while keeping the ++ # parameters, check OpenSSL::PKey.generate_key. ++ # ++ # Example: ++ # # OpenSSL::PKey::DH.generate by default generates a random key pair ++ # dh1 = OpenSSL::PKey::DH.generate(2048) ++ # p dh1.priv_key #=> # ++ # dhcopy = dh1.public_key ++ # p dhcopy.priv_key #=> nil ++ def public_key ++ DH.new(to_der) ++ end ++ + # :call-seq: + # dh.compute_key(pub_bn) -> string + # +@@ -89,6 +113,22 @@ def new(*args, &blk) # :nodoc: + class DSA + include OpenSSL::Marshal + ++ # :call-seq: ++ # dsa.public_key -> dsanew ++ # ++ # Returns a new DSA instance that carries just the \DSA parameters and the ++ # public key. ++ # ++ # This method is provided for backwards compatibility. In most cases, there ++ # is no need to call this method. ++ # ++ # For the purpose of serializing the public key, to PEM or DER encoding of ++ # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and ++ # PKey#public_to_der. ++ def public_key ++ OpenSSL::PKey.read(public_to_der) ++ end ++ + class << self + # :call-seq: + # DSA.generate(size) -> dsa +@@ -159,6 +199,21 @@ def to_bn(conversion_form = group.point_conversion_form) + class RSA + include OpenSSL::Marshal + ++ # :call-seq: ++ # rsa.public_key -> rsanew ++ # ++ # Returns a new RSA instance that carries just the public key components. ++ # ++ # This method is provided for backwards compatibility. In most cases, there ++ # is no need to call this method. ++ # ++ # For the purpose of serializing the public key, to PEM or DER encoding of ++ # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and ++ # PKey#public_to_der. ++ def public_key ++ OpenSSL::PKey.read(public_to_der) ++ end ++ + class << self + # :call-seq: + # RSA.generate(size, exponent = 65537) -> RSA +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index acd3bf474e..a512b209d3 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -266,48 +266,6 @@ ossl_dh_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * dh.public_key -> aDH +- * +- * Returns a new DH instance that carries just the public information, i.e. +- * the prime _p_ and the generator _g_, but no public/private key yet. Such +- * a pair may be generated using DH#generate_key!. The "public key" needed +- * for a key exchange with DH#compute_key is considered as per-session +- * information and may be retrieved with DH#pub_key once a key pair has +- * been generated. +- * If the current instance already contains private information (and thus a +- * valid public/private key pair), this information will no longer be present +- * in the new instance generated by DH#public_key. This feature is helpful for +- * publishing the Diffie-Hellman parameters without leaking any of the private +- * per-session information. +- * +- * === Example +- * dh = OpenSSL::PKey::DH.new(2048) # has public and private key set +- * public_key = dh.public_key # contains only prime and generator +- * parameters = public_key.to_der # it's safe to publish this +- */ +-static VALUE +-ossl_dh_to_public_key(VALUE self) +-{ +- EVP_PKEY *pkey; +- DH *orig_dh, *dh; +- VALUE obj; +- +- obj = rb_obj_alloc(rb_obj_class(self)); +- GetPKey(obj, pkey); +- +- GetDH(self, orig_dh); +- dh = DHparams_dup(orig_dh); +- if (!dh) +- ossl_raise(eDHError, "DHparams_dup"); +- if (!EVP_PKEY_assign_DH(pkey, dh)) { +- DH_free(dh); +- ossl_raise(eDHError, "EVP_PKEY_assign_DH"); +- } +- return obj; +-} +- + /* + * call-seq: + * dh.params_ok? -> true | false +@@ -384,14 +342,20 @@ Init_ossl_dh(void) + * The per-session private key, an OpenSSL::BN. + * + * === Example of a key exchange +- * dh1 = OpenSSL::PKey::DH.new(2048) +- * der = dh1.public_key.to_der #you may send this publicly to the participating party +- * dh2 = OpenSSL::PKey::DH.new(der) +- * dh2.generate_key! #generate the per-session key pair +- * symm_key1 = dh1.compute_key(dh2.pub_key) +- * symm_key2 = dh2.compute_key(dh1.pub_key) ++ * # you may send the parameters (der) and own public key (pub1) publicly ++ * # to the participating party ++ * dh1 = OpenSSL::PKey::DH.new(2048) ++ * der = dh1.to_der ++ * pub1 = dh1.pub_key ++ * ++ * # the other party generates its per-session key pair ++ * dhparams = OpenSSL::PKey::DH.new(der) ++ * dh2 = OpenSSL::PKey.generate_key(dhparams) ++ * pub2 = dh2.pub_key + * +- * puts symm_key1 == symm_key2 # => true ++ * symm_key1 = dh1.compute_key(pub2) ++ * symm_key2 = dh2.compute_key(pub1) ++ * puts symm_key1 == symm_key2 # => true + */ + cDH = rb_define_class_under(mPKey, "DH", cPKey); + rb_define_method(cDH, "initialize", ossl_dh_initialize, -1); +@@ -402,7 +366,6 @@ Init_ossl_dh(void) + rb_define_alias(cDH, "to_pem", "export"); + rb_define_alias(cDH, "to_s", "export"); + rb_define_method(cDH, "to_der", ossl_dh_to_der, 0); +- rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0); + rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0); + + DEF_OSSL_PKEY_BN(cDH, dh, p); +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index f017cceb4a..ab9ac781e8 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -264,47 +264,6 @@ ossl_dsa_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * dsa.public_key -> aDSA +- * +- * Returns a new DSA instance that carries just the public key information. +- * If the current instance has also private key information, this will no +- * longer be present in the new instance. This feature is helpful for +- * publishing the public key information without leaking any of the private +- * information. +- * +- * === Example +- * dsa = OpenSSL::PKey::DSA.new(2048) # has public and private information +- * pub_key = dsa.public_key # has only the public part available +- * pub_key_der = pub_key.to_der # it's safe to publish this +- * +- * +- */ +-static VALUE +-ossl_dsa_to_public_key(VALUE self) +-{ +- EVP_PKEY *pkey, *pkey_new; +- DSA *dsa; +- VALUE obj; +- +- GetPKeyDSA(self, pkey); +- obj = rb_obj_alloc(rb_obj_class(self)); +- GetPKey(obj, pkey_new); +- +-#define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \ +- (i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa)) +- dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey)); +-#undef DSAPublicKey_dup +- if (!dsa) +- ossl_raise(eDSAError, "DSAPublicKey_dup"); +- if (!EVP_PKEY_assign_DSA(pkey_new, dsa)) { +- DSA_free(dsa); +- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); +- } +- return obj; +-} +- + /* + * call-seq: + * dsa.syssign(string) -> aString +@@ -445,7 +404,6 @@ Init_ossl_dsa(void) + rb_define_alias(cDSA, "to_pem", "export"); + rb_define_alias(cDSA, "to_s", "export"); + rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0); +- rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0); + rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1); + rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2); + +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 7a7e66dbda..1c5476cdcd 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -390,7 +390,7 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) + * data = "Sign me!" + * pkey = OpenSSL::PKey::RSA.new(2048) + * signature = pkey.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA256") +- * pub_key = pkey.public_key ++ * pub_key = OpenSSL::PKey.read(pkey.public_to_der) + * puts pub_key.verify_pss("SHA256", signature, data, + * salt_length: :auto, mgf1_hash: "SHA256") # => true + */ +@@ -587,61 +587,6 @@ ossl_rsa_get_params(VALUE self) + return hash; + } + +-/* +- * call-seq: +- * rsa.public_key -> RSA +- * +- * Makes new RSA instance containing the public key from the private key. +- */ +-static VALUE +-ossl_rsa_to_public_key(VALUE self) +-{ +- EVP_PKEY *pkey, *pkey_new; +- RSA *rsa; +- VALUE obj; +- +- GetPKeyRSA(self, pkey); +- obj = rb_obj_alloc(rb_obj_class(self)); +- GetPKey(obj, pkey_new); +- +- rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey)); +- if (!rsa) +- ossl_raise(eRSAError, "RSAPublicKey_dup"); +- if (!EVP_PKEY_assign_RSA(pkey_new, rsa)) { +- RSA_free(rsa); +- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); +- } +- return obj; +-} +- +-/* +- * TODO: Test me +- +-static VALUE +-ossl_rsa_blinding_on(VALUE self) +-{ +- RSA *rsa; +- +- GetRSA(self, rsa); +- +- if (RSA_blinding_on(rsa, ossl_bn_ctx) != 1) { +- ossl_raise(eRSAError, NULL); +- } +- return self; +-} +- +-static VALUE +-ossl_rsa_blinding_off(VALUE self) +-{ +- RSA *rsa; +- +- GetRSA(self, rsa); +- RSA_blinding_off(rsa); +- +- return self; +-} +- */ +- + /* + * Document-method: OpenSSL::PKey::RSA#set_key + * call-seq: +@@ -712,7 +657,6 @@ Init_ossl_rsa(void) + rb_define_alias(cRSA, "to_pem", "export"); + rb_define_alias(cRSA, "to_s", "export"); + rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0); +- rb_define_method(cRSA, "public_key", ossl_rsa_to_public_key, 0); + rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, -1); + rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1); + rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1); +diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb +index d1e68dbc9f..5f8d04e754 100644 +--- a/test/openssl/test_pkey_rsa.rb ++++ b/test/openssl/test_pkey_rsa.rb +@@ -69,29 +69,28 @@ def test_private + end + + def test_new +- key = OpenSSL::PKey::RSA.new 512 +- pem = key.public_key.to_pem +- OpenSSL::PKey::RSA.new pem +- assert_equal([], OpenSSL.errors) +- end ++ key = OpenSSL::PKey::RSA.new(512) ++ assert_equal 512, key.n.num_bits ++ assert_equal 65537, key.e ++ assert_not_nil key.d + +- def test_new_exponent_default +- assert_equal(65537, OpenSSL::PKey::RSA.new(512).e) ++ # Specify public exponent ++ key2 = OpenSSL::PKey::RSA.new(512, 3) ++ assert_equal 512, key2.n.num_bits ++ assert_equal 3, key2.e ++ assert_not_nil key2.d + end + +- def test_new_with_exponent +- 1.upto(30) do |idx| +- e = (2 ** idx) + 1 +- key = OpenSSL::PKey::RSA.new(512, e) +- assert_equal(e, key.e) +- end +- end ++ def test_s_generate ++ key1 = OpenSSL::PKey::RSA.generate(512) ++ assert_equal 512, key1.n.num_bits ++ assert_equal 65537, key1.e + +- def test_generate +- key = OpenSSL::PKey::RSA.generate(512, 17) +- assert_equal 512, key.n.num_bits +- assert_equal 17, key.e +- assert_not_nil key.d ++ # Specify public exponent ++ key2 = OpenSSL::PKey::RSA.generate(512, 3) ++ assert_equal 512, key2.n.num_bits ++ assert_equal 3, key2.e ++ assert_not_nil key2.d + end + + def test_new_break +-- +2.32.0 + + +From 2150af0e55b2a25c24f62006e27e0aec3dc81b57 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Fri, 10 Jul 2020 14:34:51 +0900 +Subject: [PATCH 3/3] pkey/dh, pkey/ec: use EVP_PKEY_check() family + +Use EVP_PKEY_param_check() instead of DH_check() if available. Also, +use EVP_PKEY_public_check() instead of EC_KEY_check_key(). + +EVP_PKEY_*check() is part of the EVP API and is meant to replace those +low-level functions. They were added by OpenSSL 1.1.1. It is currently +not provided by LibreSSL. +--- + ext/openssl/extconf.rb | 3 +++ + ext/openssl/ossl_pkey_dh.c | 27 +++++++++++++++++++++++---- + ext/openssl/ossl_pkey_ec.c | 23 +++++++++++++++++++---- + test/openssl/test_pkey_dh.rb | 16 ++++++++++++++++ + 4 files changed, 61 insertions(+), 8 deletions(-) + +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index b3c6647faf..17d93443fc 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -173,6 +173,9 @@ def find_openssl_library + have_func("EVP_PBE_scrypt") + have_func("SSL_CTX_set_post_handshake_auth") + ++# added in 1.1.1 ++have_func("EVP_PKEY_check") ++ + Logging::message "=== Checking done. ===\n" + + create_header +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index a512b209d3..ca782bbe59 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -273,19 +273,38 @@ ossl_dh_get_params(VALUE self) + * Validates the Diffie-Hellman parameters associated with this instance. + * It checks whether a safe prime and a suitable generator are used. If this + * is not the case, +false+ is returned. ++ * ++ * See also the man page EVP_PKEY_param_check(3). + */ + static VALUE + ossl_dh_check_params(VALUE self) + { ++ int ret; ++#ifdef HAVE_EVP_PKEY_CHECK ++ EVP_PKEY *pkey; ++ EVP_PKEY_CTX *pctx; ++ ++ GetPKey(self, pkey); ++ pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!pctx) ++ ossl_raise(eDHError, "EVP_PKEY_CTX_new"); ++ ret = EVP_PKEY_param_check(pctx); ++ EVP_PKEY_CTX_free(pctx); ++#else + DH *dh; + int codes; + + GetDH(self, dh); +- if (!DH_check(dh, &codes)) { +- return Qfalse; +- } ++ ret = DH_check(dh, &codes) == 1 && codes == 0; ++#endif + +- return codes == 0 ? Qtrue : Qfalse; ++ if (ret == 1) ++ return Qtrue; ++ else { ++ /* DH_check_ex() will put error entry on failure */ ++ ossl_clear_error(); ++ return Qfalse; ++ } + } + + /* +diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c +index ecb8305184..829529d4b9 100644 +--- a/ext/openssl/ossl_pkey_ec.c ++++ b/ext/openssl/ossl_pkey_ec.c +@@ -443,20 +443,35 @@ static VALUE ossl_ec_key_generate_key(VALUE self) + } + + /* +- * call-seq: +- * key.check_key => true ++ * call-seq: ++ * key.check_key => true + * +- * Raises an exception if the key is invalid. ++ * Raises an exception if the key is invalid. + * +- * See the OpenSSL documentation for EC_KEY_check_key() ++ * See also the man page EVP_PKEY_public_check(3). + */ + static VALUE ossl_ec_key_check_key(VALUE self) + { ++#ifdef HAVE_EVP_PKEY_CHECK ++ EVP_PKEY *pkey; ++ EVP_PKEY_CTX *pctx; ++ int ret; ++ ++ GetPKey(self, pkey); ++ pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); ++ if (!pctx) ++ ossl_raise(eDHError, "EVP_PKEY_CTX_new"); ++ ret = EVP_PKEY_public_check(pctx); ++ EVP_PKEY_CTX_free(pctx); ++ if (ret != 1) ++ ossl_raise(eECError, "EVP_PKEY_public_check"); ++#else + EC_KEY *ec; + + GetEC(self, ec); + if (EC_KEY_check_key(ec) != 1) + ossl_raise(eECError, "EC_KEY_check_key"); ++#endif + + return Qtrue; + } +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index 279ce1984c..f80af8f841 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -86,6 +86,22 @@ def test_key_exchange + assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key)) + end + ++ def test_params_ok? ++ dh0 = Fixtures.pkey("dh1024") ++ ++ dh1 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([ ++ OpenSSL::ASN1::Integer(dh0.p), ++ OpenSSL::ASN1::Integer(dh0.g) ++ ])) ++ assert_equal(true, dh1.params_ok?) ++ ++ dh2 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([ ++ OpenSSL::ASN1::Integer(dh0.p + 1), ++ OpenSSL::ASN1::Integer(dh0.g) ++ ])) ++ assert_equal(false, dh2.params_ok?) ++ end ++ + def test_dup + dh = Fixtures.pkey("dh1024") + dh2 = dh.dup +-- +2.32.0 + diff --git a/ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch b/ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch new file mode 100644 index 0000000..acb706e --- /dev/null +++ b/ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch @@ -0,0 +1,1113 @@ +From e8504c6248c4b0e5e961f57f004e1133c20c88a5 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 5 Apr 2021 00:30:01 +0900 +Subject: [PATCH 1/5] pkey: fix interrupt handling in + OpenSSL::PKey.generate_key + +rb_thread_call_without_gvl() can be interrupted, but it may be able to +resume the operation. Call rb_thread_check_ints() to see if it raises +an exception or not. +--- + ext/openssl/ossl_pkey.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index 22e9f19982..d76f0600d1 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -239,7 +239,7 @@ struct pkey_blocking_generate_arg { + int state; + int yield: 1; + int genparam: 1; +- int stop: 1; ++ int interrupted: 1; + }; + + static VALUE +@@ -261,23 +261,31 @@ static int + pkey_gen_cb(EVP_PKEY_CTX *ctx) + { + struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx); ++ int state; + + if (arg->yield) { +- int state; + rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state); + if (state) { +- arg->stop = 1; + arg->state = state; ++ return 0; ++ } ++ } ++ if (arg->interrupted) { ++ arg->interrupted = 0; ++ state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL); ++ if (state) { ++ arg->state = state; ++ return 0; + } + } +- return !arg->stop; ++ return 1; + } + + static void + pkey_blocking_gen_stop(void *ptr) + { + struct pkey_blocking_generate_arg *arg = ptr; +- arg->stop = 1; ++ arg->interrupted = 1; + } + + static void * +-- +2.32.0 + + +From f433d1b680e7ac5ef13fc15b0844267222438cf3 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 17 May 2020 20:48:23 +0900 +Subject: [PATCH 2/5] pkey/dh: use high level EVP interface to generate + parameters and keys + +Implement PKey::DH.new(size, gen), PKey::DH.generate(size, gen), and +PKey::DH#generate_key! using PKey.generate_parameters and .generate_key +instead of the low level DH functions. + +Note that the EVP interface can enforce additional restrictions - for +example, DH key shorter than 2048 bits is no longer accepted by default +in OpenSSL 3.0. The test code is updated accordingly. +--- + ext/openssl/lib/openssl/pkey.rb | 57 ++++++++++ + ext/openssl/ossl_pkey_dh.c | 186 ++++++-------------------------- + test/openssl/test_pkey_dh.rb | 15 ++- + 3 files changed, 101 insertions(+), 157 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index be60ac2beb..5a3d0ed1ef 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -27,6 +27,63 @@ def compute_key(pub_bn) + peer.set_key(pub_bn, nil) + derive(peer) + end ++ ++ # :call-seq: ++ # dh.generate_key! -> self ++ # ++ # Generates a private and public key unless a private key already exists. ++ # If this DH instance was generated from public \DH parameters (e.g. by ++ # encoding the result of DH#public_key), then this method needs to be ++ # called first in order to generate the per-session keys before performing ++ # the actual key exchange. ++ # ++ # See also OpenSSL::PKey.generate_key. ++ # ++ # Example: ++ # dh = OpenSSL::PKey::DH.new(2048) ++ # public_key = dh.public_key #contains no private/public key yet ++ # public_key.generate_key! ++ # puts public_key.private? # => true ++ def generate_key! ++ unless priv_key ++ tmp = OpenSSL::PKey.generate_key(self) ++ set_key(tmp.pub_key, tmp.priv_key) ++ end ++ self ++ end ++ ++ class << self ++ # :call-seq: ++ # DH.generate(size, generator = 2) -> dh ++ # ++ # Creates a new DH instance from scratch by generating random parameters ++ # and a key pair. ++ # ++ # See also OpenSSL::PKey.generate_parameters and ++ # OpenSSL::PKey.generate_key. ++ # ++ # +size+:: ++ # The desired key size in bits. ++ # +generator+:: ++ # The generator. ++ def generate(size, generator = 2, &blk) ++ dhparams = OpenSSL::PKey.generate_parameters("DH", { ++ "dh_paramgen_prime_len" => size, ++ "dh_paramgen_generator" => generator, ++ }, &blk) ++ OpenSSL::PKey.generate_key(dhparams) ++ end ++ ++ # Handle DH.new(size, generator) form here; new(str) and new() forms ++ # are handled by #initialize ++ def new(*args, &blk) # :nodoc: ++ if args[0].is_a?(Integer) ++ generate(*args, &blk) ++ else ++ super ++ end ++ end ++ end + end + + class DSA +diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c +index 5bc1c49ca1..6b477b077c 100644 +--- a/ext/openssl/ossl_pkey_dh.c ++++ b/ext/openssl/ossl_pkey_dh.c +@@ -32,147 +32,56 @@ VALUE eDHError; + /* + * Private + */ +-struct dh_blocking_gen_arg { +- DH *dh; +- int size; +- int gen; +- BN_GENCB *cb; +- int result; +-}; +- +-static void * +-dh_blocking_gen(void *arg) +-{ +- struct dh_blocking_gen_arg *gen = (struct dh_blocking_gen_arg *)arg; +- gen->result = DH_generate_parameters_ex(gen->dh, gen->size, gen->gen, gen->cb); +- return 0; +-} +- +-static DH * +-dh_generate(int size, int gen) +-{ +- struct ossl_generate_cb_arg cb_arg = { 0 }; +- struct dh_blocking_gen_arg gen_arg; +- DH *dh = DH_new(); +- BN_GENCB *cb = BN_GENCB_new(); +- +- if (!dh || !cb) { +- DH_free(dh); +- BN_GENCB_free(cb); +- ossl_raise(eDHError, "malloc failure"); +- } +- +- if (rb_block_given_p()) +- cb_arg.yield = 1; +- BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); +- gen_arg.dh = dh; +- gen_arg.size = size; +- gen_arg.gen = gen; +- gen_arg.cb = cb; +- if (cb_arg.yield == 1) { +- /* we cannot release GVL when callback proc is supplied */ +- dh_blocking_gen(&gen_arg); +- } else { +- /* there's a chance to unblock */ +- rb_thread_call_without_gvl(dh_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); +- } +- +- BN_GENCB_free(cb); +- if (!gen_arg.result) { +- DH_free(dh); +- if (cb_arg.state) { +- /* Clear OpenSSL error queue before re-raising. */ +- ossl_clear_error(); +- rb_jump_tag(cb_arg.state); +- } +- ossl_raise(eDHError, "DH_generate_parameters_ex"); +- } +- +- if (!DH_generate_key(dh)) { +- DH_free(dh); +- ossl_raise(eDHError, "DH_generate_key"); +- } +- +- return dh; +-} +- +-/* +- * call-seq: +- * DH.generate(size [, generator]) -> dh +- * +- * Creates a new DH instance from scratch by generating the private and public +- * components alike. +- * +- * === Parameters +- * * _size_ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure. +- * * _generator_ is a small number > 1, typically 2 or 5. +- * +- */ +-static VALUE +-ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) +-{ +- EVP_PKEY *pkey; +- DH *dh ; +- int g = 2; +- VALUE size, gen, obj; +- +- if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) { +- g = NUM2INT(gen); +- } +- obj = rb_obj_alloc(klass); +- GetPKey(obj, pkey); +- +- dh = dh_generate(NUM2INT(size), g); +- if (!EVP_PKEY_assign_DH(pkey, dh)) { +- DH_free(dh); +- ossl_raise(eDHError, "EVP_PKEY_assign_DH"); +- } +- return obj; +-} +- + /* + * call-seq: + * DH.new -> dh + * DH.new(string) -> dh + * DH.new(size [, generator]) -> dh + * +- * Either generates a DH instance from scratch or by reading already existing +- * DH parameters from _string_. Note that when reading a DH instance from +- * data that was encoded from a DH instance by using DH#to_pem or DH#to_der +- * the result will *not* contain a public/private key pair yet. This needs to +- * be generated using DH#generate_key! first. ++ * Creates a new instance of OpenSSL::PKey::DH. ++ * ++ * If called without arguments, an empty instance without any parameter or key ++ * components is created. Use #set_pqg to manually set the parameters afterwards ++ * (and optionally #set_key to set private and public key components). ++ * ++ * If a String is given, tries to parse it as a DER- or PEM- encoded parameters. ++ * See also OpenSSL::PKey.read which can parse keys of any kinds. ++ * ++ * The DH.new(size [, generator]) form is an alias of DH.generate. + * +- * === Parameters +- * * _size_ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure. +- * * _generator_ is a small number > 1, typically 2 or 5. +- * * _string_ contains the DER or PEM encoded key. ++ * +string+:: ++ * A String that contains the DER or PEM encoded key. ++ * +size+:: ++ * See DH.generate. ++ * +generator+:: ++ * See DH.generate. + * +- * === Examples +- * DH.new # -> dh +- * DH.new(1024) # -> dh +- * DH.new(1024, 5) # -> dh +- * #Reading DH parameters +- * dh = DH.new(File.read('parameters.pem')) # -> dh, but no public/private key yet +- * dh.generate_key! # -> dh with public and private key ++ * Examples: ++ * # Creating an instance from scratch ++ * dh = DH.new ++ * dh.set_pqg(bn_p, nil, bn_g) ++ * ++ * # Generating a parameters and a key pair ++ * dh = DH.new(2048) # An alias of DH.generate(2048) ++ * ++ * # Reading DH parameters ++ * dh = DH.new(File.read('parameters.pem')) # -> dh, but no public/private key yet ++ * dh.generate_key! # -> dh with public and private key + */ + static VALUE + ossl_dh_initialize(int argc, VALUE *argv, VALUE self) + { + EVP_PKEY *pkey; + DH *dh; +- int g = 2; + BIO *in; +- VALUE arg, gen; ++ VALUE arg; + + GetPKey(self, pkey); +- if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) { +- dh = DH_new(); +- } +- else if (RB_INTEGER_TYPE_P(arg)) { +- if (!NIL_P(gen)) { +- g = NUM2INT(gen); +- } +- dh = dh_generate(NUM2INT(arg), g); ++ /* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */ ++ if (rb_scan_args(argc, argv, "01", &arg) == 0) { ++ dh = DH_new(); ++ if (!dh) ++ ossl_raise(eDHError, "DH_new"); + } + else { + arg = ossl_to_der_if_possible(arg); +@@ -449,33 +358,6 @@ ossl_dh_check_params(VALUE self) + return codes == 0 ? Qtrue : Qfalse; + } + +-/* +- * call-seq: +- * dh.generate_key! -> self +- * +- * Generates a private and public key unless a private key already exists. +- * If this DH instance was generated from public DH parameters (e.g. by +- * encoding the result of DH#public_key), then this method needs to be +- * called first in order to generate the per-session keys before performing +- * the actual key exchange. +- * +- * === Example +- * dh = OpenSSL::PKey::DH.new(2048) +- * public_key = dh.public_key #contains no private/public key yet +- * public_key.generate_key! +- * puts public_key.private? # => true +- */ +-static VALUE +-ossl_dh_generate_key(VALUE self) +-{ +- DH *dh; +- +- GetDH(self, dh); +- if (!DH_generate_key(dh)) +- ossl_raise(eDHError, "Failed to generate key"); +- return self; +-} +- + /* + * Document-method: OpenSSL::PKey::DH#set_pqg + * call-seq: +@@ -540,7 +422,6 @@ Init_ossl_dh(void) + * puts symm_key1 == symm_key2 # => true + */ + cDH = rb_define_class_under(mPKey, "DH", cPKey); +- rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1); + rb_define_method(cDH, "initialize", ossl_dh_initialize, -1); + rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1); + rb_define_method(cDH, "public?", ossl_dh_is_public, 0); +@@ -552,7 +433,6 @@ Init_ossl_dh(void) + rb_define_method(cDH, "to_der", ossl_dh_to_der, 0); + rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0); + rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0); +- rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0); + + DEF_OSSL_PKEY_BN(cDH, dh, p); + DEF_OSSL_PKEY_BN(cDH, dh, q); +diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb +index 9efc3ba68d..279ce1984c 100644 +--- a/test/openssl/test_pkey_dh.rb ++++ b/test/openssl/test_pkey_dh.rb +@@ -4,12 +4,19 @@ + if defined?(OpenSSL) && defined?(OpenSSL::PKey::DH) + + class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase +- NEW_KEYLEN = 256 ++ NEW_KEYLEN = 2048 + +- def test_new ++ def test_new_empty ++ dh = OpenSSL::PKey::DH.new ++ assert_equal nil, dh.p ++ assert_equal nil, dh.priv_key ++ end ++ ++ def test_new_generate ++ # This test is slow + dh = OpenSSL::PKey::DH.new(NEW_KEYLEN) + assert_key(dh) +- end ++ end if ENV["OSSL_TEST_ALL"] + + def test_new_break + assert_nil(OpenSSL::PKey::DH.new(NEW_KEYLEN) { break }) +@@ -80,7 +87,7 @@ def test_key_exchange + end + + def test_dup +- dh = OpenSSL::PKey::DH.new(NEW_KEYLEN) ++ dh = Fixtures.pkey("dh1024") + dh2 = dh.dup + assert_equal dh.to_der, dh2.to_der # params + assert_equal_params dh, dh2 # keys +-- +2.32.0 + + +From ba1d1d68ac2b489691eb3fe2052e77b3e57a372b Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 17 May 2020 20:48:23 +0900 +Subject: [PATCH 3/5] pkey/rsa: use high level EVP interface to generate + parameters and keys + +Implement PKey::RSA.new(size, exponent) and PKey::RSA.generate using +OpenSSL::PKey.generate_key instead of the low level RSA functions. +--- + ext/openssl/lib/openssl/pkey.rb | 30 ++++++++ + ext/openssl/ossl_pkey_rsa.c | 132 ++++---------------------------- + 2 files changed, 46 insertions(+), 116 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 5a3d0ed1ef..3bef06e3b3 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -128,5 +128,35 @@ def to_bn(conversion_form = group.point_conversion_form) + + class RSA + include OpenSSL::Marshal ++ ++ class << self ++ # :call-seq: ++ # RSA.generate(size, exponent = 65537) -> RSA ++ # ++ # Generates an \RSA keypair. ++ # ++ # See also OpenSSL::PKey.generate_key. ++ # ++ # +size+:: ++ # The desired key size in bits. ++ # +exponent+:: ++ # An odd Integer, normally 3, 17, or 65537. ++ def generate(size, exp = 0x10001, &blk) ++ OpenSSL::PKey.generate_key("RSA", { ++ "rsa_keygen_bits" => size, ++ "rsa_keygen_pubexp" => exp, ++ }, &blk) ++ end ++ ++ # Handle RSA.new(size, exponent) form here; new(str) and new() forms ++ # are handled by #initialize ++ def new(*args, &blk) # :nodoc: ++ if args[0].is_a?(Integer) ++ generate(*args, &blk) ++ else ++ super ++ end ++ end ++ end + end + end +diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c +index 3c298a2aea..43f82cb29e 100644 +--- a/ext/openssl/ossl_pkey_rsa.c ++++ b/ext/openssl/ossl_pkey_rsa.c +@@ -47,125 +47,28 @@ VALUE eRSAError; + /* + * Private + */ +-struct rsa_blocking_gen_arg { +- RSA *rsa; +- BIGNUM *e; +- int size; +- BN_GENCB *cb; +- int result; +-}; +- +-static void * +-rsa_blocking_gen(void *arg) +-{ +- struct rsa_blocking_gen_arg *gen = (struct rsa_blocking_gen_arg *)arg; +- gen->result = RSA_generate_key_ex(gen->rsa, gen->size, gen->e, gen->cb); +- return 0; +-} +- +-static RSA * +-rsa_generate(int size, unsigned long exp) +-{ +- int i; +- struct ossl_generate_cb_arg cb_arg = { 0 }; +- struct rsa_blocking_gen_arg gen_arg; +- RSA *rsa = RSA_new(); +- BIGNUM *e = BN_new(); +- BN_GENCB *cb = BN_GENCB_new(); +- +- if (!rsa || !e || !cb) { +- RSA_free(rsa); +- BN_free(e); +- BN_GENCB_free(cb); +- ossl_raise(eRSAError, "malloc failure"); +- } +- for (i = 0; i < (int)sizeof(exp) * 8; ++i) { +- if (exp & (1UL << i)) { +- if (BN_set_bit(e, i) == 0) { +- BN_free(e); +- RSA_free(rsa); +- BN_GENCB_free(cb); +- ossl_raise(eRSAError, "BN_set_bit"); +- } +- } +- } +- +- if (rb_block_given_p()) +- cb_arg.yield = 1; +- BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); +- gen_arg.rsa = rsa; +- gen_arg.e = e; +- gen_arg.size = size; +- gen_arg.cb = cb; +- if (cb_arg.yield == 1) { +- /* we cannot release GVL when callback proc is supplied */ +- rsa_blocking_gen(&gen_arg); +- } else { +- /* there's a chance to unblock */ +- rb_thread_call_without_gvl(rsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); +- } +- +- BN_GENCB_free(cb); +- BN_free(e); +- if (!gen_arg.result) { +- RSA_free(rsa); +- if (cb_arg.state) { +- /* must clear OpenSSL error stack */ +- ossl_clear_error(); +- rb_jump_tag(cb_arg.state); +- } +- ossl_raise(eRSAError, "RSA_generate_key_ex"); +- } +- +- return rsa; +-} +- + /* + * call-seq: +- * RSA.generate(size) => RSA instance +- * RSA.generate(size, exponent) => RSA instance ++ * RSA.new -> rsa ++ * RSA.new(encoded_key [, passphrase]) -> rsa ++ * RSA.new(encoded_key) { passphrase } -> rsa ++ * RSA.new(size [, exponent]) -> rsa + * +- * Generates an RSA keypair. _size_ is an integer representing the desired key +- * size. Keys smaller than 1024 should be considered insecure. _exponent_ is +- * an odd number normally 3, 17, or 65537. +- */ +-static VALUE +-ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) +-{ +-/* why does this method exist? why can't initialize take an optional exponent? */ +- EVP_PKEY *pkey; +- RSA *rsa; +- VALUE size, exp; +- VALUE obj; +- +- rb_scan_args(argc, argv, "11", &size, &exp); +- obj = rb_obj_alloc(klass); +- GetPKey(obj, pkey); +- +- rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp)); +- if (!EVP_PKEY_assign_RSA(pkey, rsa)) { +- RSA_free(rsa); +- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA"); +- } +- return obj; +-} +- +-/* +- * call-seq: +- * RSA.new(size [, exponent]) => RSA instance +- * RSA.new(encoded_key) => RSA instance +- * RSA.new(encoded_key, pass_phrase) => RSA instance ++ * Generates or loads an \RSA keypair. + * +- * Generates or loads an RSA keypair. If an integer _key_size_ is given it +- * represents the desired key size. Keys less than 1024 bits should be +- * considered insecure. ++ * If called without arguments, creates a new instance with no key components ++ * set. They can be set individually by #set_key, #set_factors, and ++ * #set_crt_params. + * +- * A key can instead be loaded from an _encoded_key_ which must be PEM or DER +- * encoded. A _pass_phrase_ can be used to decrypt the key. If none is given +- * OpenSSL will prompt for the pass phrase. ++ * If called with a String, tries to parse as DER or PEM encoding of an \RSA key. ++ * Note that, if _passphrase_ is not specified but the key is encrypted with a ++ * passphrase, \OpenSSL will prompt for it. ++ * See also OpenSSL::PKey.read which can parse keys of any kinds. + * +- * = Examples ++ * If called with a number, generates a new key pair. This form works as an ++ * alias of RSA.generate. + * ++ * Examples: + * OpenSSL::PKey::RSA.new 2048 + * OpenSSL::PKey::RSA.new File.read 'rsa.pem' + * OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my pass phrase' +@@ -179,15 +82,13 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) + VALUE arg, pass; + + GetPKey(self, pkey); ++ /* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ + rb_scan_args(argc, argv, "02", &arg, &pass); + if (argc == 0) { + rsa = RSA_new(); + if (!rsa) + ossl_raise(eRSAError, "RSA_new"); + } +- else if (RB_INTEGER_TYPE_P(arg)) { +- rsa = rsa_generate(NUM2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2ULONG(pass)); +- } + else { + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); +@@ -832,7 +733,6 @@ Init_ossl_rsa(void) + */ + cRSA = rb_define_class_under(mPKey, "RSA", cPKey); + +- rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1); + rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1); + rb_define_method(cRSA, "initialize_copy", ossl_rsa_initialize_copy, 1); + +-- +2.32.0 + + +From a6c4a8116c09243c39cc8d1e7ececcd8be0cfaf2 Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Sun, 17 May 2020 22:14:03 +0900 +Subject: [PATCH 4/5] pkey/dsa: use high level EVP interface to generate + parameters and keys + +Implement PKey::DSA.new(size) and PKey::DSA.generate using +OpenSSL::PKey.generate_parameters and .generate_key instead of the low +level DSA functions. +--- + ext/openssl/lib/openssl/pkey.rb | 30 +++++++ + ext/openssl/ossl_pkey_dsa.c | 140 ++++++-------------------------- + test/openssl/test_pkey_dsa.rb | 23 ++---- + 3 files changed, 64 insertions(+), 129 deletions(-) + +diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb +index 3bef06e3b3..53ee52f98b 100644 +--- a/ext/openssl/lib/openssl/pkey.rb ++++ b/ext/openssl/lib/openssl/pkey.rb +@@ -88,6 +88,36 @@ def new(*args, &blk) # :nodoc: + + class DSA + include OpenSSL::Marshal ++ ++ class << self ++ # :call-seq: ++ # DSA.generate(size) -> dsa ++ # ++ # Creates a new DSA instance by generating a private/public key pair ++ # from scratch. ++ # ++ # See also OpenSSL::PKey.generate_parameters and ++ # OpenSSL::PKey.generate_key. ++ # ++ # +size+:: ++ # The desired key size in bits. ++ def generate(size, &blk) ++ dsaparams = OpenSSL::PKey.generate_parameters("DSA", { ++ "dsa_paramgen_bits" => size, ++ }, &blk) ++ OpenSSL::PKey.generate_key(dsaparams) ++ end ++ ++ # Handle DSA.new(size) form here; new(str) and new() forms ++ # are handled by #initialize ++ def new(*args, &blk) # :nodoc: ++ if args[0].is_a?(Integer) ++ generate(*args, &blk) ++ else ++ super ++ end ++ end ++ end + end + + if defined?(EC) +diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c +index 0e68f7f27f..1c5a8a737e 100644 +--- a/ext/openssl/ossl_pkey_dsa.c ++++ b/ext/openssl/ossl_pkey_dsa.c +@@ -46,126 +46,39 @@ VALUE eDSAError; + /* + * Private + */ +-struct dsa_blocking_gen_arg { +- DSA *dsa; +- int size; +- int *counter; +- unsigned long *h; +- BN_GENCB *cb; +- int result; +-}; +- +-static void * +-dsa_blocking_gen(void *arg) +-{ +- struct dsa_blocking_gen_arg *gen = (struct dsa_blocking_gen_arg *)arg; +- gen->result = DSA_generate_parameters_ex(gen->dsa, gen->size, NULL, 0, +- gen->counter, gen->h, gen->cb); +- return 0; +-} +- +-static DSA * +-dsa_generate(int size) +-{ +- struct ossl_generate_cb_arg cb_arg = { 0 }; +- struct dsa_blocking_gen_arg gen_arg; +- DSA *dsa = DSA_new(); +- BN_GENCB *cb = BN_GENCB_new(); +- int counter; +- unsigned long h; +- +- if (!dsa || !cb) { +- DSA_free(dsa); +- BN_GENCB_free(cb); +- ossl_raise(eDSAError, "malloc failure"); +- } +- +- if (rb_block_given_p()) +- cb_arg.yield = 1; +- BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); +- gen_arg.dsa = dsa; +- gen_arg.size = size; +- gen_arg.counter = &counter; +- gen_arg.h = &h; +- gen_arg.cb = cb; +- if (cb_arg.yield == 1) { +- /* we cannot release GVL when callback proc is supplied */ +- dsa_blocking_gen(&gen_arg); +- } else { +- /* there's a chance to unblock */ +- rb_thread_call_without_gvl(dsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); +- } +- +- BN_GENCB_free(cb); +- if (!gen_arg.result) { +- DSA_free(dsa); +- if (cb_arg.state) { +- /* Clear OpenSSL error queue before re-raising. By the way, the +- * documentation of DSA_generate_parameters_ex() says the error code +- * can be obtained by ERR_get_error(), but the default +- * implementation, dsa_builtin_paramgen() doesn't put any error... */ +- ossl_clear_error(); +- rb_jump_tag(cb_arg.state); +- } +- ossl_raise(eDSAError, "DSA_generate_parameters_ex"); +- } +- +- if (!DSA_generate_key(dsa)) { +- DSA_free(dsa); +- ossl_raise(eDSAError, "DSA_generate_key"); +- } +- +- return dsa; +-} +- +-/* +- * call-seq: +- * DSA.generate(size) -> dsa +- * +- * Creates a new DSA instance by generating a private/public key pair +- * from scratch. +- * +- * === Parameters +- * * _size_ is an integer representing the desired key size. +- * +- */ +-static VALUE +-ossl_dsa_s_generate(VALUE klass, VALUE size) +-{ +- EVP_PKEY *pkey; +- DSA *dsa; +- VALUE obj; +- +- obj = rb_obj_alloc(klass); +- GetPKey(obj, pkey); +- +- dsa = dsa_generate(NUM2INT(size)); +- if (!EVP_PKEY_assign_DSA(pkey, dsa)) { +- DSA_free(dsa); +- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); +- } +- return obj; +-} +- + /* + * call-seq: + * DSA.new -> dsa +- * DSA.new(size) -> dsa + * DSA.new(string [, pass]) -> dsa ++ * DSA.new(size) -> dsa + * + * Creates a new DSA instance by reading an existing key from _string_. + * +- * === Parameters +- * * _size_ is an integer representing the desired key size. +- * * _string_ contains a DER or PEM encoded key. +- * * _pass_ is a string that contains an optional password. ++ * If called without arguments, creates a new instance with no key components ++ * set. They can be set individually by #set_pqg and #set_key. + * +- * === Examples +- * DSA.new -> dsa +- * DSA.new(1024) -> dsa +- * DSA.new(File.read('dsa.pem')) -> dsa +- * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa ++ * If called with a String, tries to parse as DER or PEM encoding of a \DSA key. ++ * See also OpenSSL::PKey.read which can parse keys of any kinds. ++ * ++ * If called with a number, generates random parameters and a key pair. This ++ * form works as an alias of DSA.generate. ++ * ++ * +string+:: ++ * A String that contains a DER or PEM encoded key. ++ * +pass+:: ++ * A String that contains an optional password. ++ * +size+:: ++ * See DSA.generate. + * ++ * Examples: ++ * p OpenSSL::PKey::DSA.new(1024) ++ * #=> # ++ * ++ * p OpenSSL::PKey::DSA.new(File.read('dsa.pem')) ++ * #=> # ++ * ++ * p OpenSSL::PKey::DSA.new(File.read('dsa.pem'), 'mypassword') ++ * #=> # + */ + static VALUE + ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) +@@ -176,15 +89,13 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) + VALUE arg, pass; + + GetPKey(self, pkey); ++ /* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ + rb_scan_args(argc, argv, "02", &arg, &pass); + if (argc == 0) { + dsa = DSA_new(); + if (!dsa) + ossl_raise(eDSAError, "DSA_new"); + } +- else if (argc == 1 && RB_INTEGER_TYPE_P(arg)) { +- dsa = dsa_generate(NUM2INT(arg)); +- } + else { + pass = ossl_pem_passwd_value(pass); + arg = ossl_to_der_if_possible(arg); +@@ -553,7 +464,6 @@ Init_ossl_dsa(void) + */ + cDSA = rb_define_class_under(mPKey, "DSA", cPKey); + +- rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1); + rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1); + rb_define_method(cDSA, "initialize_copy", ossl_dsa_initialize_copy, 1); + +diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb +index 4bf8a7b374..85bb6ec0ae 100644 +--- a/test/openssl/test_pkey_dsa.rb ++++ b/test/openssl/test_pkey_dsa.rb +@@ -5,31 +5,26 @@ + + class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase + def test_private +- key = OpenSSL::PKey::DSA.new(256) +- assert(key.private?) ++ key = Fixtures.pkey("dsa1024") ++ assert_equal true, key.private? + key2 = OpenSSL::PKey::DSA.new(key.to_der) +- assert(key2.private?) ++ assert_equal true, key2.private? + key3 = key.public_key +- assert(!key3.private?) ++ assert_equal false, key3.private? + key4 = OpenSSL::PKey::DSA.new(key3.to_der) +- assert(!key4.private?) ++ assert_equal false, key4.private? + end + + def test_new +- key = OpenSSL::PKey::DSA.new 256 ++ key = OpenSSL::PKey::DSA.new(2048) + pem = key.public_key.to_pem + OpenSSL::PKey::DSA.new pem +- if $0 == __FILE__ +- assert_nothing_raised { +- key = OpenSSL::PKey::DSA.new 2048 +- } +- end + end + + def test_new_break +- assert_nil(OpenSSL::PKey::DSA.new(512) { break }) ++ assert_nil(OpenSSL::PKey::DSA.new(2048) { break }) + assert_raise(RuntimeError) do +- OpenSSL::PKey::DSA.new(512) { raise } ++ OpenSSL::PKey::DSA.new(2048) { raise } + end + end + +@@ -184,7 +179,7 @@ def test_read_DSAPublicKey_pem + end + + def test_dup +- key = OpenSSL::PKey::DSA.new(256) ++ key = Fixtures.pkey("dsa1024") + key2 = key.dup + assert_equal key.params, key2.params + key2.set_pqg(key2.p + 1, key2.q, key2.g) +-- +2.32.0 + + +From ba5a3a5c3eabf969f5cd2232b022e440af803b5b Mon Sep 17 00:00:00 2001 +From: Kazuki Yamaguchi +Date: Mon, 5 Apr 2021 00:39:04 +0900 +Subject: [PATCH 5/5] pkey: remove unused ossl_generate_cb_2() helper function + +The previous series of commits re-implemented key generation with the +low level API with the EVP API. The BN_GENCB-based callback function is +no longer used. +--- + ext/openssl/extconf.rb | 3 -- + ext/openssl/openssl_missing.h | 12 ------ + ext/openssl/ossl_pkey.c | 73 +++++++---------------------------- + ext/openssl/ossl_pkey.h | 8 ---- + 4 files changed, 15 insertions(+), 81 deletions(-) + +diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb +index 693e55cd97..b3c6647faf 100644 +--- a/ext/openssl/extconf.rb ++++ b/ext/openssl/extconf.rb +@@ -136,9 +136,6 @@ def find_openssl_library + $defs.push("-DHAVE_OPAQUE_OPENSSL") + end + have_func("CRYPTO_lock") || $defs.push("-DHAVE_OPENSSL_110_THREADING_API") +-have_func("BN_GENCB_new") +-have_func("BN_GENCB_free") +-have_func("BN_GENCB_get_arg") + have_func("EVP_MD_CTX_new") + have_func("EVP_MD_CTX_free") + have_func("HMAC_CTX_new") +diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h +index 7d218f86f5..e575415f49 100644 +--- a/ext/openssl/openssl_missing.h ++++ b/ext/openssl/openssl_missing.h +@@ -34,18 +34,6 @@ int ossl_EC_curve_nist2nid(const char *); + #endif + + /* added in 1.1.0 */ +-#if !defined(HAVE_BN_GENCB_NEW) +-# define BN_GENCB_new() ((BN_GENCB *)OPENSSL_malloc(sizeof(BN_GENCB))) +-#endif +- +-#if !defined(HAVE_BN_GENCB_FREE) +-# define BN_GENCB_free(cb) OPENSSL_free(cb) +-#endif +- +-#if !defined(HAVE_BN_GENCB_GET_ARG) +-# define BN_GENCB_get_arg(cb) (cb)->arg +-#endif +- + #if !defined(HAVE_EVP_MD_CTX_NEW) + # define EVP_MD_CTX_new EVP_MD_CTX_create + #endif +diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c +index d76f0600d1..f9282b9417 100644 +--- a/ext/openssl/ossl_pkey.c ++++ b/ext/openssl/ossl_pkey.c +@@ -17,64 +17,6 @@ VALUE cPKey; + VALUE ePKeyError; + static ID id_private_q; + +-/* +- * callback for generating keys +- */ +-static VALUE +-call_check_ints0(VALUE arg) +-{ +- rb_thread_check_ints(); +- return Qnil; +-} +- +-static void * +-call_check_ints(void *arg) +-{ +- int state; +- rb_protect(call_check_ints0, Qnil, &state); +- return (void *)(VALUE)state; +-} +- +-int +-ossl_generate_cb_2(int p, int n, BN_GENCB *cb) +-{ +- VALUE ary; +- struct ossl_generate_cb_arg *arg; +- int state; +- +- arg = (struct ossl_generate_cb_arg *)BN_GENCB_get_arg(cb); +- if (arg->yield) { +- ary = rb_ary_new2(2); +- rb_ary_store(ary, 0, INT2NUM(p)); +- rb_ary_store(ary, 1, INT2NUM(n)); +- +- /* +- * can be break by raising exception or 'break' +- */ +- rb_protect(rb_yield, ary, &state); +- if (state) { +- arg->state = state; +- return 0; +- } +- } +- if (arg->interrupted) { +- arg->interrupted = 0; +- state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL); +- if (state) { +- arg->state = state; +- return 0; +- } +- } +- return 1; +-} +- +-void +-ossl_generate_cb_stop(void *ptr) +-{ +- struct ossl_generate_cb_arg *arg = (struct ossl_generate_cb_arg *)ptr; +- arg->interrupted = 1; +-} +- + static void + ossl_evp_pkey_free(void *ptr) + { +@@ -257,6 +199,21 @@ pkey_gen_cb_yield(VALUE ctx_v) + return rb_yield_values2(info_num, argv); + } + ++static VALUE ++call_check_ints0(VALUE arg) ++{ ++ rb_thread_check_ints(); ++ return Qnil; ++} ++ ++static void * ++call_check_ints(void *arg) ++{ ++ int state; ++ rb_protect(call_check_ints0, Qnil, &state); ++ return (void *)(VALUE)state; ++} ++ + static int + pkey_gen_cb(EVP_PKEY_CTX *ctx) + { +diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h +index 7dbaed47bc..629c16ae1f 100644 +--- a/ext/openssl/ossl_pkey.h ++++ b/ext/openssl/ossl_pkey.h +@@ -35,14 +35,6 @@ extern const rb_data_type_t ossl_evp_pkey_type; + } \ + } while (0) + +-struct ossl_generate_cb_arg { +- int yield; +- int interrupted; +- int state; +-}; +-int ossl_generate_cb_2(int p, int n, BN_GENCB *cb); +-void ossl_generate_cb_stop(void *ptr); +- + VALUE ossl_pkey_new(EVP_PKEY *); + void ossl_pkey_check_public_key(const EVP_PKEY *); + EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE); +-- +2.32.0 + diff --git a/ruby-3.1.0-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-autoconf-2.70-add-ac-prog-cc.patch b/ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch new file mode 100644 index 0000000..1bd20bd --- /dev/null +++ b/ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch @@ -0,0 +1,27 @@ +From 912a8dcfc5369d840dcd6bf0f88ee0bac7d902d6 Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Thu, 30 Sep 2021 18:24:37 +0900 +Subject: [PATCH] Needs `AC_PROG_CC` + +Although `AC_PROG_CC_C99` has been obsolete, `AC_PROG_CC` is not +and the latter is necessary not to make C++ compiler mandatory. +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index b24a8f59b0..c7059ee1ec 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -203,7 +203,7 @@ rb_test_CXXFLAGS=${CXXFLAGS+yes} + # BSD's ports and MacPorts prefix GNU binutils with 'g' + + dnl Seems necessarily in order to add -std=gnu99 option for gcc 4.9. +-m4_version_prereq([2.70], [], [AC_PROG_CC_C99]) ++m4_version_prereq([2.70], [AC_PROG_CC], [AC_PROG_CC_C99]) + + AC_PROG_CXX + AC_PROG_CPP +-- +2.31.1 + diff --git a/ruby-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.spec b/ruby.spec index 6e6cb1e..8359e78 100644 --- a/ruby.spec +++ b/ruby.spec @@ -1,11 +1,44 @@ +%global ruby_version 3.0.3 + +# Bundled libraries versions +%global rubygems_version 3.2.32 +%global rubygems_molinillo_version 0.7.0 + +# Default gems. +%global bundler_version 2.2.32 +%global bundler_connection_pool_version 2.3.0 +%global bundler_fileutils_version 1.4.1 +%global bundler_molinillo_version 0.7.0 +%global bundler_net_http_persistent_version 4.0.0 +%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 io_console_version 0.5.7 +%global json_version 2.5.1 +%global openssl_version 2.2.1 +%global psych_version 3.3.2 +%global rdoc_version 6.3.3 +%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 + Name: ruby -Version: 2.5.8 -Release: 114 +Version: %{ruby_version} +Release: 1 Summary: Object-oriented scripting language interpreter License: (Ruby or BSD) and Public Domain and MIT and CC0 and zlib and UCD URL: https://www.ruby-lang.org/en/ -Source0: http://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.8.tar.xz +Source0: http://cache.ruby-lang.org/pub/ruby/3.0/%{name}-%{version}.tar.xz Source1: operating_system.rb Source2: libruby.stp Source3: ruby-exercise.stp @@ -19,44 +52,139 @@ Source11: rubygems.con Source12: test_abrt.rb Source13: test_systemtap.rb -%{?load:%{SOURCE4}} -%{?load:%{SOURCE5}} +%{load:%{SOURCE4}} +%{load:%{SOURCE5}} -Patch0001: ruby-2.3.0-ruby_version.patch -Patch0002: ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch -Patch0003: ruby-2.1.0-Enable-configuration-of-archlibdir.patch -Patch0004: ruby-2.1.0-always-use-i386.patch -Patch0005: ruby-2.1.0-custom-rubygems-location.patch -Patch0006: ruby-1.9.3-mkmf-verbose.patch -Patch0007: ruby-2.1.0-Allow-to-specify-additional-preludes-by-configuratio.patch -Patch0008: ruby-2.2.3-Generate-preludes-using-miniruby.patch -Patch0009: ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch -Patch0010: ruby-2.5.0-Add-Gem.operating_system_defaults.patch -Patch0011: ruby-2.6.0-library-options-to-MAINLIBS.patch -Patch0012: ruby-2.5.1-Avoid-need-of-C++-compiler-to-pass-the-test-suite.patch -Patch6000: CVE-2019-19204.patch -Patch6001: CVE-2019-19246.patch -Patch6002: CVE-2019-16163.patch -Patch6003: CVE-2020-25613.patch -Patch6004: upgrade_lib_rexml.patch -Patch6005: upgrade_lib_rexml_test.patch -Patch6006: backport-CVE-2021-31799.patch -Patch6007: backport-CVE-2021-31810.patch -Patch6008: backport-CVE-2021-32066.patch +# 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 +# Workaround "an invalid stdio handle" error on PPC, due to recently introduced +# hardening features of glibc (rhbz#1361037). +# https://bugs.ruby-lang.org/issues/12666 +Patch9: ruby-2.3.1-Rely-on-ldd-to-detect-glibc.patch +# Fix DWARF5 support. +# https://bugzilla.redhat.com/show_bug.cgi?id=1920533 +# https://bugs.ruby-lang.org/issues/17585 +# https://github.com/ruby/ruby/pull/4240 +Patch15: ruby-3.1.0-Support-GCCs-DWARF-5.patch +# Fix segfaults with enabled LTO. +# https://bugs.ruby-lang.org/issues/18062 +# https://github.com/ruby/ruby/pull/4716 +Patch16: ruby-3.1.0-Get-rid-of-type-punning-pointer-casts.patch +# DWARF5/LTO fixes for SIGSEV handler. +# https://bugs.ruby-lang.org/issues/17052 +# https://github.com/ruby/ruby/commit/72317b333b85eed483ad00bcd4f40944019a7c13 +Patch17: ruby-3.1.0-Ignore-DW_FORM_ref_addr.patch +# https://bugs.ruby-lang.org/issues/17052#note-9 +# https://bugs.ruby-lang.org/attachments/download/8974/ruby-addr2line-DW_FORM_ref_addr.patch +# https://github.com/ruby/ruby/commit/a9977ba2f9863e3fb1b2346589ebbca67d80536c +Patch18: ruby-3.1.0-addr2line-DW_FORM_ref_addr.patch +# Avoid possible timeout errors in TestBugReporter#test_bug_reporter_add. +# https://bugs.ruby-lang.org/issues/16492 +Patch19: ruby-2.7.1-Timeout-the-test_bug_reporter_add-witout-raising-err.patch +# Add AC_PROG_CC to make C++ compiler dependency optional on autoconf >= 2.70. +# https://github.com/ruby/ruby/commit/912a8dcfc5369d840dcd6bf0f88ee0bac7d902d6 +Patch20: ruby-3.1.0-autoconf-2.70-add-ac-prog-cc.patch +# Allow to exclude test with fully qualified name. +# https://bugs.ruby-lang.org/issues/16936 +# https://github.com/ruby/ruby/pull/5026 +Patch21: ruby-3.1.0-Properly-exclude-test-cases.patch +# Fix loading of default gems. +# https://bugzilla.redhat.com/show_bug.cgi?id=2027099 +# https://github.com/rubygems/rubygems/pull/5154 +Patch22: rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch + +# Fix test broken by wrongly formatted distinguished name submitted to +# `OpenSSL::X509::Name.parse`. +# https://github.com/ruby/openssl/issues/470 +# https://github.com/rubygems/rubygems/pull/5030 +Patch31: rubygems-3.2.30-Provide-distinguished-name-which-will-be-correctly-p.patch + +# Refactor PEM/DER serialization code. +# https://github.com/ruby/openssl/pull/328 +Patch40: ruby-3.1.0-Refactor-PEM-DER-serialization-code.patch +# Implement more 'generic' operations using the EVP API. +# https://github.com/ruby/openssl/pull/329 +Patch41: ruby-3.1.0-Add-more-support-for-generic-pkey-types.patch +# Allow setting algorithm-specific options in #sign and #verify. +# https://github.com/ruby/openssl/pull/374 +Patch42: ruby-3.1.0-Allow-setting-algorithm-specific-options-in-sign-and-verify.patch +# Use high level EVP interface to generate parameters and keys. +# https://github.com/ruby/openssl/pull/397 +Patch43: ruby-3.1.0-Use-high-level-EVP-interface-to-generate-parameters-and-keys.patch +# Use EVP API in more places. +# https://github.com/ruby/openssl/pull/436 +Patch44: ruby-3.1.0-Use-EVP-API-in-more-places.patch +# Implement PKey#{encrypt,decrypt,sign_raw,verify_{raw,verify_recover}}. +# https://github.com/ruby/openssl/pull/382 +Patch45: ruby-3.1.0-Implement-PKey-encrypt-decrypt-sign_raw-verify_raw-and-verify_recover.patch +# Fix `OpenSSL::TestSSL#test_dup` test failure. +# https://github.com/ruby/openssl/commit/7b66eaa2dbabb6570dbbbdfac24c4dcdcc6793d7 +Patch46: ruby-3.1.0-test-openssl-utils-remove-dup_public-helper-method.patch +# Fix `OpenSSL::TestDigest#test_digest_constants` test case. +# https://github.com/ruby/openssl/commit/a3e59f4c2e200c76ef1d93945ff8737a05715e17 +Patch47: ruby-3.1.0-test-openssl-test_digest-do-not-test-constants-for-l.patch +# Fix `OpenSSL::TestSSL#test_connect_certificate_verify_failed_exception_message` +# test case. +# https://github.com/ruby/openssl/commit/b5a0a198505452c7457b192da2e5cd5dda04f23d +Patch48: ruby-3.1.0-test-openssl-test_ssl-relax-regex-to-match-OpenSSL-s.patch +# Fix `OpenSSL::TestPKCS12#test_{new_with_no_keys,new_with_one_key_and_one_cert}` +# test failures. +# https://github.com/ruby/openssl/commit/998406d18f2acf73090e9fd9d92a7b4227ac593b +Patch49: ruby-3.1.0-test-openssl-test_pkcs12-fix-test-failures-with-Open.patch +# Fix `OpenSSL::TestPKey#test_s_generate_key` test case. +# https://github.com/ruby/openssl/commit/c732387ee5aaa8c5a9717e8b3ffebb3d7430e99a +Patch50: ruby-3.1.0-test-openssl-test_pkey-use-EC-keys-for-PKey.generate.patch +# Miscellaneous changes for OpenSSL 3.0 support. +# https://github.com/ruby/openssl/pull/468 +Patch51: ruby-3.1.0-Miscellaneous-changes-for-OpenSSL-3.0-support.patch +# Support OpenSSL 3.0. +# https://github.com/ruby/openssl/pull/399 +Patch52: ruby-3.1.0-Support-OpenSSL-3.0.patch +# Fix `TestPumaControlCli#test_control_ssl` testcase in Puma. +# https://github.com/ruby/openssl/pull/399#issuecomment-966239736 +Patch53: ruby-3.1.0-SSL_read-EOF-handling.patch Provides: %{name}-libs = %{version}-%{release} Obsoletes: %{name}-libs < %{version}-%{release} -Provides: ruby(runtime_executable) = 2.5.1 ruby(release) = 2.5.1 bundled(ccan-build_assert) +Provides: ruby(runtime_executable) = %{version} ruby(release) = %{version} bundled(ccan-build_assert) Provides: bundled(ccan-check_type) bundled(ccan-container_of) bundled(ccan-list) Obsoletes: ruby-tcltk < 2.4.0 -Suggests: rubypick -Recommends: ruby(rubygems) >= 2.7.6 rubygem(bigdecimal) >= 1.3.4 -Recommends: rubygem(did_you_mean) >= 1.2.0 rubygem(openssl) >= 2.1.0 +# The Net::Telnet and XMLRPC were removed. https://bugs.ruby-lang.org/issues/16484 +Obsoletes: rubygem-net-telnet < 0.1.1-%{release} +Obsoletes: rubygem-xmlrpc < 0.3.0-%{release} +Suggests: rubypick +Recommends: ruby(rubygems) >= %{rubygems_version} rubygem(bigdecimal) >= %{bigdecimal_version} +Recommends: rubygem(did_you_mean) >= 1.2.0 rubygem(openssl) >= %{openssl_version} +Requires: %{name}-help = %{version}-%{release} BuildRequires: autoconf gdbm-devel gmp-devel libffi-devel openssl-devel libyaml-devel readline-devel -BuildRequires: procps git gcc systemtap-sdt-devel cmake +BuildRequires: procps git gcc systemtap-sdt-devel cmake perl ruby %description Ruby is a fast and easy interpreted scripting language for object-oriented programming. @@ -72,11 +200,11 @@ Headers and libraries for building extension libraries for extensions Ruby or Ru %package -n rubygems Summary: Ruby standard for wrapping ruby libraries -Version: 2.7.6 +Version: %{rubygems_version} License: Ruby or MIT -Requires: ruby(release) rubygem(openssl) >= 2.1.0 rubygem(psych) >= 3.0.2 -Recommends: rubygem(rdoc) >= 6.0.1.1 rubygem(io-console) >= 0.4.6 -Provides: gem = %{version}-%{release} ruby(rubygems) = %{version}-%{release} bundled(rubygem-molinillo) = 0.5.7 +Requires: ruby(release) rubygem(openssl) >= 2.1.0 rubygem(psych) >= %{psych_version} +Recommends: rubygem(rdoc) >= %{rdoc_version} rubygem(io-console) >= %{io_console_version} +Provides: gem = %{version}-%{release} ruby(rubygems) = %{version}-%{release} bundled(rubygem-molinillo) = %{rubygems_molinillo_version} BuildArch: noarch %description -n rubygems @@ -84,9 +212,9 @@ The Ruby standard for publishing and managing third party libraries provided by %package -n rubygems-devel Summary: For packaging RubyGems -Version: 2.7.6 +Version: %{rubygems_version} License: Ruby or MIT -Requires: ruby(rubygems) = %{version}-%{release} rubygem(json) >= 2.1.0 rubygem(rdoc) >= 6.0.1.1 +Requires: ruby(rubygems) = %{version}-%{release} rubygem(json) >= %{json_version} rubygem(rdoc) >= %{rdoc_version} BuildArch: noarch %description -n rubygems-devel @@ -94,19 +222,32 @@ Provide macros and development tools for packaging RubyGems. %package -n rubygem-rake Summary: make-like utility base on ruby -Version: 12.3.0 +Version: %{rake_version} License: MIT -Requires: ruby(release) ruby(rubygems) >= 2.7.6 +Requires: ruby(release) ruby(rubygems) >= %{rubygems_version} Provides: rake = %{version}-%{release} 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 irb Summary: The Interactive Ruby -Version: 2.5.8 -Requires: %{name}-libs = 2.5.8 +Version: %{ruby_version} +Requires: %{name}-libs = %{ruby_version} Provides: irb = %{version}-%{release} ruby(irb) = %{version}-%{release} BuildArch: noarch @@ -115,9 +256,9 @@ The irb is acronym for Interactive Ruby,It evaluates ruby expression from the te %package -n rubygem-rdoc Summary: Generate HTML and command-line documentation for Ruby projects -Version: 6.0.1.1 +Version: %{rdoc_version} License: GPLv2 and Ruby and MIT and OFL -Requires: ruby(release) ruby(rubygems) >= 2.7.6 ruby(irb) = 2.5.8 rubygem(io-console) >= 0.4.6 rubygem(json) >= 2.1.0 +Requires: ruby(release) ruby(rubygems) >= %{rubygems_version} ruby(irb) = 3.0.3 rubygem(io-console) >= %{io_console_version} rubygem(json) >= %{json_version} Provides: rdoc = %{version}-%{release} ri = %{version}-%{release} rubygem(rdoc) = %{version}-%{release} BuildArch: noarch @@ -137,9 +278,9 @@ This package provides documentation for ruby. %package -n rubygem-bigdecimal Summary: Provide arbitrary-precision floating point decimal arithmetic -Version: 1.3.4 +Version: %{bigdecimal_version} License: Ruby or BSD -Requires: ruby(release) ruby(rubygems) >= 2.7.6 +Requires: ruby(release) ruby(rubygems) >= %{rubygems_version} Provides: rubygem(bigdecimal) = %{version}-%{release} %description -n rubygem-bigdecimal @@ -147,9 +288,9 @@ BigDecimal provides similar support for very large or very accurate floating poi %package -n rubygem-did_you_mean Summary: "Did you mean?" experience in Ruby -Version: 1.2.0 +Version: %{did_you_mean_version} License: MIT -Requires: ruby(release) ruby(rubygems) >= 2.7.6 +Requires: ruby(release) ruby(rubygems) >= %{rubygems_version} Provides: rubygem(did_you_mean) = %{version}-%{release} BuildArch: noarch @@ -158,8 +299,8 @@ The error message will tell you the right one when you misspelled something. %package -n rubygem-io-console Summary: Simple console utilizing library -Version: 0.4.6 -Requires: ruby(release) ruby(rubygems) >= 2.7.6 +Version: %{io_console_version} +Requires: ruby(release) ruby(rubygems) >= %{rubygems_version} Provides: rubygem(io-console) = %{version}-%{release} %description -n rubygem-io-console @@ -168,9 +309,9 @@ such as curses and readline. %package -n rubygem-json Summary: JSON implementation as a Ruby extension in C -Version: 2.1.0 +Version: %{json_version} License: (Ruby or GPLv2) and UCD -Requires: ruby(release) ruby(rubygems) >= 2.7.6 +Requires: ruby(release) ruby(rubygems) >= %{rubygems_version} Provides: rubygem(json) = %{version}-%{release} %description -n rubygem-json @@ -178,9 +319,9 @@ According to RFC 4627,this package implements the JSON specification. %package -n rubygem-minitest Summary: Provide complete testing facilities -Version: 5.10.3 +Version: %{minitest_version} License: MIT -Requires: ruby(release) ruby(rubygems) >= 2.7.6 +Requires: ruby(release) ruby(rubygems) >= %{rubygems_version} Provides: rubygem(minitest) = %{version}-%{release} BuildArch: noarch @@ -193,9 +334,9 @@ minitest/pride - Show pride in the test and add color to the test output. %package -n rubygem-openssl Summary: Provide SSL、TLS and general purpose cryptography -Version: 2.1.2 +Version: %{openssl_version} License: Ruby or BSD -Requires: ruby(release) ruby(rubygems) >= 2.7.6 +Requires: ruby(release) ruby(rubygems) >= %{rubygems_version} Provides: rubygem(openssl) = %{version}-%{release} %description -n rubygem-openssl @@ -203,9 +344,9 @@ This package provides SSL、TLS and general purpose cryptography. %package -n rubygem-power_assert Summary: Power Assert for Ruby -Version: 1.1.1 +Version: %{power_assert_version} License: Ruby or BSD -Requires: ruby(release) ruby(rubygems) >= 2.7.6 +Requires: ruby(release) ruby(rubygems) >= %{rubygems_version} Provides: rubygem(power_assert) = %{version}-%{release} BuildArch: noarch @@ -215,30 +356,42 @@ it can indicate which value is incorrect when the condition is not met during te %package -n rubygem-psych Summary: Ruby's libyaml wrapper -Version: 3.0.2 +Version: %{psych_version} License: MIT -Requires: ruby(release) ruby(rubygems) >= 2.7.6 +Requires: ruby(release) ruby(rubygems) >= %{rubygems_version} Provides: rubygem(psych) = %{version}-%{release} %description -n rubygem-psych Psych is a YAML parser and emitter. According to wrapping libyaml, Psych knows how to serialize and de-serialize most Ruby objects to and from the YAML format. -%package -n rubygem-net-telnet -Summary: Provides telnet client functionality -Version: 0.1.1 -Requires: ruby(release) ruby(rubygems) >= 2.7.6 -Provides: rubygem(net-telnet) = %{version}-%{release} +%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-net-telnet -This package provides telnet client functionality. +%description -n rubygem-bundler +Bundler manages an application's dependencies through its entire life, across +many machines, systematically and repeatably. %package -n rubygem-test-unit Summary: Unit testing framework for Ruby -Version: 3.2.7 +Version: %{test_unit_version} License: (Ruby or BSD) and (Ruby or BSD or Python) and (Ruby or BSD or LGPLv2+) -Requires: ruby(release) ruby(rubygems) >= 2.7.6 rubygem(power_assert) +Requires: ruby(release) ruby(rubygems) >= %{rubygems_version} rubygem(power_assert) Provides: rubygem(test-unit) = %{version}-%{release} BuildArch: noarch @@ -246,25 +399,68 @@ BuildArch: noarch Test::Unit (test-unit) is unit testing framework for Ruby based on xUnit principles. writing tests, checking results and automated testing are provided in Ruby. -%package -n rubygem-xmlrpc -Summary: Lightweight protocol enables remote procedure calls over HTTP -Version: 0.3.0 -License: Ruby or BSD -Requires: ruby(release) ruby(rubygems) >= 2.7.6 -Provides: rubygem(xmlrpc) = %{version}-%{release} +%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-xmlrpc -This package is a lightweight protocol which can enable remote procedure calls over HTTP. +%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 -%autosetup -n ruby-2.5.8 -p1 +%autosetup -n ruby-%{ruby_version} -p1 rm -rf ext/psych/yaml rm -rf ext/fiddle/libffi* cp -a %{SOURCE3} . -cp -a %{SOURCE6} . %build autoconf @@ -274,20 +470,23 @@ autoconf --with-vendorarchdir='%{ruby_vendorarchdir}' --with-rubyhdrdir='%{_includedir}' -with-rubyarchhdrdir='%{_includedir}' \ --with-sitearchhdrdir='$(sitehdrdir)/$(arch)' --with-vendorarchhdrdir='$(vendorhdrdir)/$(arch)' \ --with-rubygemsdir='%{_datadir}/rubygems' --with-ruby-pc='%{name}.pc' --with-compress-debug-sections=no --disable-rpath \ - --enable-shared --with-ruby-version='' --enable-multiarch --with-prelude=./abrt_prelude.rb \ + --enable-shared --with-ruby-version='' --enable-multiarch \ + %make_build COPY="cp -p" Q= %install %make_install -sed -i 's/Version: \${ruby_version}/Version: 2.5.1/' %{buildroot}%{_libdir}/pkgconfig/%{name}.pc +sed -i 's/Version: \${ruby_version}/Version: %{ruby_version}/' %{buildroot}%{_libdir}/pkgconfig/%{name}.pc -for cert in rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem \ - rubygems.org/AddTrustExternalCARoot.pem index.rubygems.org/GlobalSignRootCA.pem +# 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}%{_datadir}/rubygems/rubygems/ssl_certs/$cert - rm -r $(dirname %{buildroot}%{_datadir}/rubygems/rubygems/ssl_certs/$cert) + rm -d $(dirname %{buildroot}%{_datadir}/rubygems/rubygems/ssl_certs/$cert) || : done test ! "$(ls -A %{buildroot}%{_datadir}/rubygems/rubygems/ssl_certs/ 2>/dev/null)" @@ -311,70 +510,70 @@ if [ -d %{buildroot}%{ruby_libdir}/gems ]; then fi install -d %{buildroot}%{_exec_prefix}/lib{,64}/gems/%{name} -install -d %{buildroot}%{gem_dir}/gems/rdoc-6.0.1.1/lib +install -d %{buildroot}%{gem_dir}/gems/rdoc-%{rdoc_version}/lib -mv %{buildroot}%{ruby_libdir}/rdoc* %{buildroot}%{gem_dir}/gems/rdoc-6.0.1.1/lib -mv %{buildroot}%{gem_dir}/specifications/default/rdoc-6.0.1.1.gemspec %{buildroot}%{gem_dir}/specifications +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 -install -d %{buildroot}%{gem_dir}/gems/bigdecimal-1.3.4/lib -install -d %{buildroot}%{_libdir}/gems/%{name}/bigdecimal-1.3.4 -mv %{buildroot}%{ruby_libdir}/bigdecimal %{buildroot}%{gem_dir}/gems/bigdecimal-1.3.4/lib -mv %{buildroot}%{ruby_libarchdir}/bigdecimal.so %{buildroot}%{_libdir}/gems/%{name}/bigdecimal-1.3.4 -mv %{buildroot}%{gem_dir}/specifications/default/bigdecimal-1.3.4.gemspec %{buildroot}%{gem_dir}/specifications -ln -s %{gem_dir}/gems/bigdecimal-1.3.4/lib/bigdecimal %{buildroot}%{ruby_libdir}/bigdecimal -ln -s %{_libdir}/gems/%{name}/bigdecimal-1.3.4/bigdecimal.so %{buildroot}%{ruby_libarchdir}/bigdecimal.so +install -d %{buildroot}%{gem_dir}/gems/bigdecimal-%{bigdecimal_version}/lib +install -d %{buildroot}%{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version} +mv %{buildroot}%{ruby_libdir}/bigdecimal %{buildroot}%{gem_dir}/gems/bigdecimal-%{bigdecimal_version}/lib +mv %{buildroot}%{ruby_libarchdir}/bigdecimal.so %{buildroot}%{_libdir}/gems/%{name}/bigdecimal-%{bigdecimal_version} +mv %{buildroot}%{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 -install -d %{buildroot}%{gem_dir}/gems/io-console-0.4.6/lib -install -d %{buildroot}%{_libdir}/gems/%{name}/io-console-0.4.6/io -mv %{buildroot}%{ruby_libdir}/io %{buildroot}%{gem_dir}/gems/io-console-0.4.6/lib -mv %{buildroot}%{ruby_libarchdir}/io/console.so %{buildroot}%{_libdir}/gems/%{name}/io-console-0.4.6/io -mv %{buildroot}%{gem_dir}/specifications/default/io-console-0.4.6.gemspec %{buildroot}%{gem_dir}/specifications -ln -s %{gem_dir}/gems/io-console-0.4.6/lib/io %{buildroot}%{ruby_libdir}/io -ln -s %{_libdir}/gems/%{name}/io-console-0.4.6/io/console.so %{buildroot}%{ruby_libarchdir}/io/console.so +install -d %{buildroot}%{gem_dir}/gems/io-console-%{io_console_version}/lib +install -d %{buildroot}%{_libdir}/gems/%{name}/io-console-%{io_console_version}/io +mv %{buildroot}%{ruby_libdir}/io %{buildroot}%{gem_dir}/gems/io-console-%{io_console_version}/lib +mv %{buildroot}%{ruby_libarchdir}/io/console.so %{buildroot}%{_libdir}/gems/%{name}/io-console-%{io_console_version}/io +mv %{buildroot}%{gem_dir}/specifications/default/io-console-%{io_console_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/io-console-%{io_console_version}/lib/io %{buildroot}%{ruby_libdir}/io +ln -s %{_libdir}/gems/%{name}/io-console-%{io_console_version}/io/console.so %{buildroot}%{ruby_libarchdir}/io/console.so -install -d %{buildroot}%{gem_dir}/gems/json-2.1.0/lib -install -d %{buildroot}%{_libdir}/gems/%{name}/json-2.1.0 -mv %{buildroot}%{ruby_libdir}/json* %{buildroot}%{gem_dir}/gems/json-2.1.0/lib -mv %{buildroot}%{ruby_libarchdir}/json/ %{buildroot}%{_libdir}/gems/%{name}/json-2.1.0/ -mv %{buildroot}%{gem_dir}/specifications/default/json-2.1.0.gemspec %{buildroot}%{gem_dir}/specifications -ln -s %{gem_dir}/gems/json-2.1.0/lib/json.rb %{buildroot}%{ruby_libdir}/json.rb -ln -s %{gem_dir}/gems/json-2.1.0/lib/json %{buildroot}%{ruby_libdir}/json -ln -s %{_libdir}/gems/%{name}/json-2.1.0/json/ %{buildroot}%{ruby_libarchdir}/json +install -d %{buildroot}%{gem_dir}/gems/json-%{json_version}/lib +install -d %{buildroot}%{_libdir}/gems/%{name}/json-%{json_version} +mv %{buildroot}%{ruby_libdir}/json* %{buildroot}%{gem_dir}/gems/json-%{json_version}/lib +mv %{buildroot}%{ruby_libarchdir}/json/ %{buildroot}%{_libdir}/gems/%{name}/json-%{json_version}/ +mv %{buildroot}%{gem_dir}/specifications/default/json-%{json_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/json-%{json_version}/lib/json.rb %{buildroot}%{ruby_libdir}/json.rb +ln -s %{gem_dir}/gems/json-%{json_version}/lib/json %{buildroot}%{ruby_libdir}/json +ln -s %{_libdir}/gems/%{name}/json-%{json_version}/json/ %{buildroot}%{ruby_libarchdir}/json -install -d %{buildroot}%{gem_dir}/gems/openssl-2.1.2/lib -install -d %{buildroot}%{_libdir}/gems/%{name}/openssl-2.1.2 -mv %{buildroot}%{ruby_libdir}/openssl* %{buildroot}%{gem_dir}/gems/openssl-2.1.2/lib -mv %{buildroot}%{ruby_libarchdir}/openssl.so %{buildroot}%{_libdir}/gems/%{name}/openssl-2.1.2/ -mv %{buildroot}%{gem_dir}/specifications/default/openssl-2.1.2.gemspec %{buildroot}%{gem_dir}/specifications +install -d %{buildroot}%{gem_dir}/gems/openssl-%{openssl_version}/lib +install -d %{buildroot}%{_libdir}/gems/%{name}/openssl-%{openssl_version} +mv %{buildroot}%{ruby_libdir}/openssl* %{buildroot}%{gem_dir}/gems/openssl-%{openssl_version}/lib +mv %{buildroot}%{ruby_libarchdir}/openssl.so %{buildroot}%{_libdir}/gems/%{name}/openssl-%{openssl_version}/ +mv %{buildroot}%{gem_dir}/specifications/default/openssl-%{openssl_version}.gemspec %{buildroot}%{gem_dir}/specifications install -d %{buildroot}%{ruby_libdir}/openssl -find %{buildroot}%{gem_dir}/gems/openssl-2.1.2/lib/openssl -maxdepth 1 -type f -exec \ - sh -c 'ln -s %{gem_dir}/gems/openssl-2.1.2/lib/openssl/`basename {}` %{buildroot}%{ruby_libdir}/openssl' \; -ln -s %{gem_dir}/gems/openssl-2.1.2/lib/openssl.rb %{buildroot}%{ruby_libdir}/openssl.rb -ln -s %{_libdir}/gems/%{name}/openssl-2.1.2/openssl.so %{buildroot}%{ruby_libarchdir}/openssl.so +find %{buildroot}%{gem_dir}/gems/openssl-%{openssl_version}/lib/openssl -maxdepth 1 -type f -exec \ + sh -c 'ln -s %{gem_dir}/gems/openssl-%{openssl_version}/lib/openssl/`basename {}` %{buildroot}%{ruby_libdir}/openssl' \; +ln -s %{gem_dir}/gems/openssl-%{openssl_version}/lib/openssl.rb %{buildroot}%{ruby_libdir}/openssl.rb +ln -s %{_libdir}/gems/%{name}/openssl-%{openssl_version}/openssl.so %{buildroot}%{ruby_libarchdir}/openssl.so -install -d %{buildroot}%{gem_dir}/gems/psych-3.0.2/lib -install -d %{buildroot}%{_libdir}/gems/%{name}/psych-3.0.2 -mv %{buildroot}%{ruby_libdir}/psych* %{buildroot}%{gem_dir}/gems/psych-3.0.2/lib -mv %{buildroot}%{ruby_libarchdir}/psych.so %{buildroot}%{_libdir}/gems/%{name}/psych-3.0.2/ -mv %{buildroot}%{gem_dir}/specifications/default/psych-3.0.2.gemspec %{buildroot}%{gem_dir}/specifications -ln -s %{gem_dir}/gems/psych-3.0.2/lib/psych %{buildroot}%{ruby_libdir}/psych -ln -s %{gem_dir}/gems/psych-3.0.2/lib/psych.rb %{buildroot}%{ruby_libdir}/psych.rb -ln -s %{_libdir}/gems/%{name}/psych-3.0.2/psych.so %{buildroot}%{ruby_libarchdir}/psych.so +install -d %{buildroot}%{gem_dir}/gems/psych-%{psych_version}/lib +install -d %{buildroot}%{_libdir}/gems/%{name}/psych-%{psych_version} +mv %{buildroot}%{ruby_libdir}/psych* %{buildroot}%{gem_dir}/gems/psych-%{psych_version}/lib +mv %{buildroot}%{ruby_libarchdir}/psych.so %{buildroot}%{_libdir}/gems/%{name}/psych-%{psych_version}/ +mv %{buildroot}%{gem_dir}/specifications/default/psych-%{psych_version}.gemspec %{buildroot}%{gem_dir}/specifications +ln -s %{gem_dir}/gems/psych-%{psych_version}/lib/psych %{buildroot}%{ruby_libdir}/psych +ln -s %{gem_dir}/gems/psych-%{psych_version}/lib/psych.rb %{buildroot}%{ruby_libdir}/psych.rb +ln -s %{_libdir}/gems/%{name}/psych-%{psych_version}/psych.so %{buildroot}%{ruby_libarchdir}/psych.so -find %{buildroot}%{gem_dir}/extensions/*-%{_target_os}/2.5.1/* -maxdepth 0 \ +find %{buildroot}%{gem_dir}/extensions/*-%{_target_os}/%{version}/* -maxdepth 0 \ -exec mv '{}' %{buildroot}%{_libdir}/gems/%{name}/ \; || echo "No gem binary extensions to move." sed -i '/^end$/ i\ - s.extensions = ["json/ext/parser.so", "json/ext/generator.so"]' %{buildroot}%{gem_dir}/specifications/json-2.1.0.gemspec + s.extensions = ["json/ext/parser.so", "json/ext/generator.so"]' %{buildroot}%{gem_dir}/specifications/json-%{json_version}.gemspec -mv %{buildroot}%{gem_dir}/gems/rake-12.3.3/doc/rake.1 %{buildroot}%{_mandir}/man1 +mv %{buildroot}%{gem_dir}/gems/rake-%{rake_version}/doc/rake.1 %{buildroot}%{_mandir}/man1 install -d %{buildroot}%{_datadir}/systemtap/tapset -sed -e "s|@LIBRARY_PATH@|%(echo %{_libdir} | sed 's/64//')*/libruby.so.2.5|" \ - %{SOURCE2} > %{buildroot}%{_datadir}/systemtap/tapset/libruby.so.2.5.stp +sed -e "s|@LIBRARY_PATH@|%(echo %{_libdir} | sed 's/64//')*/libruby.so.3.0|" \ + %{SOURCE2} > %{buildroot}%{_datadir}/systemtap/tapset/libruby.so.3.0.stp -sed -i -r "s|( \*.*\*)\/(.*)|\1\\\/\2|" %{buildroot}%{_datadir}/systemtap/tapset/libruby.so.2.5.stp +sed -i -r "s|( \*.*\*)\/(.*)|\1\\\/\2|" %{buildroot}%{_datadir}/systemtap/tapset/libruby.so.3.0.stp find doc -maxdepth 1 -type f ! -name '.*' ! -name '*.ja*' > .ruby-doc.en echo 'doc/images' >> .ruby-doc.en @@ -387,13 +586,15 @@ echo 'doc/pty' >> .ruby-doc.ja sed -i 's/^/%doc /' .ruby-doc.* sed -i 's/^/%lang(ja) /' .ruby-doc.ja +cp -a %{_libdir}/libruby.so.2.5 $RPM_BUILD_ROOT%{_libdir} + %check -[ "`make runruby TESTRUN_SCRIPT='bin/gem -v' | tail -1`" == '2.7.6.2' ] +[ "`make runruby TESTRUN_SCRIPT='bin/gem -v' | tail -1`" == '%{rubygems_version}' ] [ "`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`" == '0.5.7' ] + puts Gem::Resolver::Molinillo::VERSION\\\"\" | tail -1`" == '%{rubygems_molinillo_version}' ] touch abrt.rb @@ -402,7 +603,7 @@ make runruby TESTRUN_SCRIPT=%{SOURCE13} %files %license BSDL COPYING GPL LEGAL -%doc README.md NEWS +%doc README.md %lang(ja) %license COPYING.ja %{_bindir}/{erb,ruby} @@ -438,7 +639,7 @@ make runruby TESTRUN_SCRIPT=%{SOURCE13} %{ruby_libarchdir}/rbconfig.rb %{ruby_libarchdir}/rbconfig/sizeof.so -%{ruby_libarchdir}/{continuation.so,coverage.so,date_core.so,dbm.so} +%{ruby_libarchdir}/{continuation.so,coverage.so,date_core.so,dbm.so,monitor.so} %{ruby_libarchdir}/{etc.so,fcntl.so,fiber.so,fiddle.so,gdbm.so,digest.so,nkf.so,objspace.so,pathname.so,pty.so} %{ruby_libarchdir}/{readline.so,ripper.so,sdbm.so,socket.so,stringio.so,strscan.so,syslog.so,zlib.so} @@ -452,6 +653,45 @@ make runruby TESTRUN_SCRIPT=%{SOURCE13} %exclude %{ruby_libdir}/psych.rb %exclude %{ruby_libdir}/irb +%{_bindir}/racc +%{gem_dir}/gems/erb-2.2.0/libexec/erb +%{gem_dir}/gems/irb-1.3.5/exe/irb +%{gem_dir}/gems/racc-1.5.2/bin/racc +%{ruby_libdir}/benchmark/version.rb +%{ruby_libdir}/csv/core_ext/array.rb +%{ruby_libdir}/csv/core_ext/string.rb +%{ruby_libdir}/csv/delete_suffix.rb +%{ruby_libdir}/csv/fields_converter.rb +%{ruby_libdir}/csv/match_p.rb +%{ruby_libdir}/csv/parser.rb +%{ruby_libdir}/csv/row.rb +%{ruby_libdir}/csv/table.rb +%{ruby_libdir}/csv/version.rb +%{ruby_libdir}/csv/writer.rb +%{ruby_libdir}/logger/errors.rb +%{ruby_libdir}/logger/formatter.rb +%{ruby_libdir}/logger/log_device.rb +%{ruby_libdir}/logger/period.rb +%{ruby_libdir}/logger/severity.rb +%{ruby_libdir}/logger/version.rb +%{ruby_libdir}/reline/ansi.rb +%{ruby_libdir}/reline/config.rb +%{ruby_libdir}/reline/general_io.rb +%{ruby_libdir}/reline/history.rb +%{ruby_libdir}/reline/key_actor.rb +%{ruby_libdir}/reline/key_actor/base.rb +%{ruby_libdir}/reline/key_actor/emacs.rb +%{ruby_libdir}/reline/key_actor/vi_command.rb +%{ruby_libdir}/reline/key_actor/vi_insert.rb +%{ruby_libdir}/reline/key_stroke.rb +%{ruby_libdir}/reline/kill_ring.rb +%{ruby_libdir}/reline/line_editor.rb +%{ruby_libdir}/reline/unicode.rb +%{ruby_libdir}/reline/unicode/east_asian_width.rb +%{ruby_libdir}/reline/version.rb +%{ruby_libdir}/reline/windows.rb +%{ruby_libdir}/set/sorted_set.rb + %files devel %license BSDL COPYING GPL LEGAL %lang(ja) %license COPYING.ja @@ -490,8 +730,30 @@ make runruby TESTRUN_SCRIPT=%{SOURCE13} %files -n rubygem-rake %{_bindir}/rake -%{gem_dir}/gems/rake-12.3.3 -%{gem_dir}/specifications/rake-12.3.3.gemspec +%{gem_dir}/gems/rake-13.0.3 +%{gem_dir}/specifications/rake-13.0.3.gemspec + +%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 irb %{_bindir}/irb @@ -499,8 +761,8 @@ make runruby TESTRUN_SCRIPT=%{SOURCE13} %files -n rubygem-rdoc %{_bindir}/{rdoc,ri} -%{gem_dir}/gems/rdoc-6.0.1.1 -%{gem_dir}/specifications/rdoc-6.0.1.1.gemspec +%{gem_dir}/gems/rdoc-%{rdoc_version} +%{gem_dir}/specifications/rdoc-%{rdoc_version}.gemspec %files help -f .ruby-doc.en -f .ruby-doc.ja %doc README.md ChangeLog ruby-exercise.stp @@ -514,74 +776,411 @@ make runruby TESTRUN_SCRIPT=%{SOURCE13} %files -n rubygem-bigdecimal %{ruby_libdir}/bigdecimal %{ruby_libarchdir}/bigdecimal.so -%{_libdir}/gems/%{name}/bigdecimal-1.3.4 -%{gem_dir}/gems/bigdecimal-1.3.4 -%{gem_dir}/specifications/bigdecimal-1.3.4.gemspec +%{_libdir}/gems/%{name}/bigdecimal-3.0.0 +%{gem_dir}/gems/bigdecimal-3.0.0 +%{gem_dir}/specifications/bigdecimal-3.0.0.gemspec %files -n rubygem-did_you_mean -%{gem_dir}/gems/did_you_mean-1.2.0 -%{gem_dir}/specifications/did_you_mean-1.2.0.gemspec -%exclude %{gem_dir}/gems/did_you_mean-1.2.0/.* +%{ruby_libdir}/did_you_mean/core_ext/name_error.rb +%{ruby_libdir}/did_you_mean/experimental.rb +%{ruby_libdir}/did_you_mean/formatters/plain_formatter.rb +%{ruby_libdir}/did_you_mean/formatters/verbose_formatter.rb +%{ruby_libdir}/did_you_mean/jaro_winkler.rb +%{ruby_libdir}/did_you_mean/levenshtein.rb +%{ruby_libdir}/did_you_mean/spell_checker.rb +%{ruby_libdir}/did_you_mean/spell_checkers/key_error_checker.rb +%{ruby_libdir}/did_you_mean/spell_checkers/method_name_checker.rb +%{ruby_libdir}/did_you_mean/spell_checkers/name_error_checkers.rb +%{ruby_libdir}/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb +%{ruby_libdir}/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb +%{ruby_libdir}/did_you_mean/spell_checkers/null_checker.rb +%{ruby_libdir}/did_you_mean/spell_checkers/require_path_checker.rb +%{ruby_libdir}/did_you_mean/tree_spell_checker.rb +%{ruby_libdir}/did_you_mean/verbose.rb +%{ruby_libdir}/did_you_mean/version.rb %files -n rubygem-io-console %{ruby_libdir}/io %{ruby_libarchdir}/io/console.so -%{_libdir}/gems/%{name}/io-console-0.4.6 -%{gem_dir}/gems/io-console-0.4.6 -%{gem_dir}/specifications/io-console-0.4.6.gemspec +%{_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-2.1.0 -%{gem_dir}/gems/json-2.1.0 -%{gem_dir}/specifications/json-2.1.0.gemspec +%{_libdir}/gems/%{name}/json-%{json_version} +%{gem_dir}/gems/json-%{json_version} +%{gem_dir}/specifications/json-%{json_version}.gemspec %files -n rubygem-minitest -%{gem_dir}/gems/minitest-5.10.3 -%{gem_dir}/specifications/minitest-5.10.3.gemspec -%exclude %{gem_dir}/gems/minitest-5.10.3/.* +%{gem_dir}/gems/minitest-%{minitest_version} +%{gem_dir}/specifications/minitest-%{minitest_version}.gemspec +%exclude %{gem_dir}/gems/minitest-%{minitest_version}/.* %files -n rubygem-openssl %{ruby_libdir}/openssl %{ruby_libdir}/openssl.rb %{ruby_libarchdir}/openssl.so -%{_libdir}/gems/%{name}/openssl-2.1.2 -%{gem_dir}/gems/openssl-2.1.2 -%{gem_dir}/specifications/openssl-2.1.2.gemspec +%{_libdir}/gems/%{name}/openssl-%{openssl_version} +%{gem_dir}/gems/openssl-%{openssl_version} +%{gem_dir}/specifications/openssl-%{openssl_version}.gemspec %files -n rubygem-power_assert -%{gem_dir}/gems/power_assert-1.1.1 -%{gem_dir}/specifications/power_assert-1.1.1.gemspec -%exclude %{gem_dir}/gems/power_assert-1.1.1/.* +%{gem_dir}/gems/power_assert-%{power_assert_version} +%{gem_dir}/specifications/power_assert-%{power_assert_version}.gemspec +%exclude %{gem_dir}/gems/power_assert-%{power_assert_version}/.* %files -n rubygem-psych %{ruby_libdir}/psych %{ruby_libdir}/psych.rb %{ruby_libarchdir}/psych.so -%{_libdir}/gems/%{name}/psych-3.0.2 -%{gem_dir}/gems/psych-3.0.2 -%{gem_dir}/specifications/psych-3.0.2.gemspec +%{_libdir}/gems/%{name}/psych-%{psych_version} +%{gem_dir}/gems/psych-%{psych_version} +%{gem_dir}/specifications/psych-%{psych_version}.gemspec -%files -n rubygem-net-telnet -%{gem_dir}/gems/net-telnet-0.1.1 -%{gem_dir}/specifications/net-telnet-0.1.1.gemspec -%exclude %{gem_dir}/gems/net-telnet-0.1.1/.* +%files -n rubygem-bundler +%{_bindir}/bundle +%{_bindir}/bundler +%{gem_dir}/gems/bundler-%{bundler_version} +%{ruby_libdir}/bundler/build_metadata.rb +%{ruby_libdir}/bundler/capistrano.rb +%{ruby_libdir}/bundler/cli.rb +%{ruby_libdir}/bundler/cli/add.rb +%{ruby_libdir}/bundler/cli/binstubs.rb +%{ruby_libdir}/bundler/cli/cache.rb +%{ruby_libdir}/bundler/cli/check.rb +%{ruby_libdir}/bundler/cli/clean.rb +%{ruby_libdir}/bundler/cli/common.rb +%{ruby_libdir}/bundler/cli/config.rb +%{ruby_libdir}/bundler/cli/console.rb +%{ruby_libdir}/bundler/cli/doctor.rb +%{ruby_libdir}/bundler/cli/exec.rb +%{ruby_libdir}/bundler/cli/fund.rb +%{ruby_libdir}/bundler/cli/gem.rb +%{ruby_libdir}/bundler/cli/info.rb +%{ruby_libdir}/bundler/cli/init.rb +%{ruby_libdir}/bundler/cli/inject.rb +%{ruby_libdir}/bundler/cli/install.rb +%{ruby_libdir}/bundler/cli/issue.rb +%{ruby_libdir}/bundler/cli/list.rb +%{ruby_libdir}/bundler/cli/lock.rb +%{ruby_libdir}/bundler/cli/open.rb +%{ruby_libdir}/bundler/cli/outdated.rb +%{ruby_libdir}/bundler/cli/platform.rb +%{ruby_libdir}/bundler/cli/plugin.rb +%{ruby_libdir}/bundler/cli/pristine.rb +%{ruby_libdir}/bundler/cli/remove.rb +%{ruby_libdir}/bundler/cli/show.rb +%{ruby_libdir}/bundler/cli/update.rb +%{ruby_libdir}/bundler/cli/viz.rb +%{ruby_libdir}/bundler/compact_index_client.rb +%{ruby_libdir}/bundler/compact_index_client/cache.rb +%{ruby_libdir}/bundler/compact_index_client/gem_parser.rb +%{ruby_libdir}/bundler/compact_index_client/updater.rb +%{ruby_libdir}/bundler/constants.rb +%{ruby_libdir}/bundler/current_ruby.rb +%{ruby_libdir}/bundler/definition.rb +%{ruby_libdir}/bundler/dep_proxy.rb +%{ruby_libdir}/bundler/dependency.rb +%{ruby_libdir}/bundler/deployment.rb +%{ruby_libdir}/bundler/deprecate.rb +%{ruby_libdir}/bundler/digest.rb +%{ruby_libdir}/bundler/dsl.rb +%{ruby_libdir}/bundler/endpoint_specification.rb +%{ruby_libdir}/bundler/env.rb +%{ruby_libdir}/bundler/environment_preserver.rb +%{ruby_libdir}/bundler/errors.rb +%{ruby_libdir}/bundler/feature_flag.rb +%{ruby_libdir}/bundler/fetcher.rb +%{ruby_libdir}/bundler/fetcher/base.rb +%{ruby_libdir}/bundler/fetcher/compact_index.rb +%{ruby_libdir}/bundler/fetcher/dependency.rb +%{ruby_libdir}/bundler/fetcher/downloader.rb +%{ruby_libdir}/bundler/fetcher/index.rb +%{ruby_libdir}/bundler/friendly_errors.rb +%{ruby_libdir}/bundler/gem_helper.rb +%{ruby_libdir}/bundler/gem_helpers.rb +%{ruby_libdir}/bundler/gem_tasks.rb +%{ruby_libdir}/bundler/gem_version_promoter.rb +%{ruby_libdir}/bundler/gemdeps.rb +%{ruby_libdir}/bundler/graph.rb +%{ruby_libdir}/bundler/index.rb +%{ruby_libdir}/bundler/injector.rb +%{ruby_libdir}/bundler/inline.rb +%{ruby_libdir}/bundler/installer.rb +%{ruby_libdir}/bundler/installer/gem_installer.rb +%{ruby_libdir}/bundler/installer/parallel_installer.rb +%{ruby_libdir}/bundler/installer/standalone.rb +%{ruby_libdir}/bundler/lazy_specification.rb +%{ruby_libdir}/bundler/lockfile_generator.rb +%{ruby_libdir}/bundler/lockfile_parser.rb +%{ruby_libdir}/bundler/man/bundle-add.1 +%{ruby_libdir}/bundler/man/bundle-add.1.ronn +%{ruby_libdir}/bundler/man/bundle-binstubs.1 +%{ruby_libdir}/bundler/man/bundle-binstubs.1.ronn +%{ruby_libdir}/bundler/man/bundle-cache.1 +%{ruby_libdir}/bundler/man/bundle-cache.1.ronn +%{ruby_libdir}/bundler/man/bundle-check.1 +%{ruby_libdir}/bundler/man/bundle-check.1.ronn +%{ruby_libdir}/bundler/man/bundle-clean.1 +%{ruby_libdir}/bundler/man/bundle-clean.1.ronn +%{ruby_libdir}/bundler/man/bundle-config.1 +%{ruby_libdir}/bundler/man/bundle-config.1.ronn +%{ruby_libdir}/bundler/man/bundle-doctor.1 +%{ruby_libdir}/bundler/man/bundle-doctor.1.ronn +%{ruby_libdir}/bundler/man/bundle-exec.1 +%{ruby_libdir}/bundler/man/bundle-exec.1.ronn +%{ruby_libdir}/bundler/man/bundle-gem.1 +%{ruby_libdir}/bundler/man/bundle-gem.1.ronn +%{ruby_libdir}/bundler/man/bundle-info.1 +%{ruby_libdir}/bundler/man/bundle-info.1.ronn +%{ruby_libdir}/bundler/man/bundle-init.1 +%{ruby_libdir}/bundler/man/bundle-init.1.ronn +%{ruby_libdir}/bundler/man/bundle-inject.1 +%{ruby_libdir}/bundler/man/bundle-inject.1.ronn +%{ruby_libdir}/bundler/man/bundle-install.1 +%{ruby_libdir}/bundler/man/bundle-install.1.ronn +%{ruby_libdir}/bundler/man/bundle-list.1 +%{ruby_libdir}/bundler/man/bundle-list.1.ronn +%{ruby_libdir}/bundler/man/bundle-lock.1 +%{ruby_libdir}/bundler/man/bundle-lock.1.ronn +%{ruby_libdir}/bundler/man/bundle-open.1 +%{ruby_libdir}/bundler/man/bundle-open.1.ronn +%{ruby_libdir}/bundler/man/bundle-outdated.1 +%{ruby_libdir}/bundler/man/bundle-outdated.1.ronn +%{ruby_libdir}/bundler/man/bundle-platform.1 +%{ruby_libdir}/bundler/man/bundle-platform.1.ronn +%{ruby_libdir}/bundler/man/bundle-pristine.1 +%{ruby_libdir}/bundler/man/bundle-pristine.1.ronn +%{ruby_libdir}/bundler/man/bundle-remove.1 +%{ruby_libdir}/bundler/man/bundle-remove.1.ronn +%{ruby_libdir}/bundler/man/bundle-show.1 +%{ruby_libdir}/bundler/man/bundle-show.1.ronn +%{ruby_libdir}/bundler/man/bundle-update.1 +%{ruby_libdir}/bundler/man/bundle-update.1.ronn +%{ruby_libdir}/bundler/man/bundle-viz.1 +%{ruby_libdir}/bundler/man/bundle-viz.1.ronn +%{ruby_libdir}/bundler/man/bundle.1 +%{ruby_libdir}/bundler/man/bundle.1.ronn +%{ruby_libdir}/bundler/man/gemfile.5 +%{ruby_libdir}/bundler/man/gemfile.5.ronn +%{ruby_libdir}/bundler/match_platform.rb +%{ruby_libdir}/bundler/mirror.rb +%{ruby_libdir}/bundler/plugin.rb +%{ruby_libdir}/bundler/plugin/api.rb +%{ruby_libdir}/bundler/plugin/api/source.rb +%{ruby_libdir}/bundler/plugin/dsl.rb +%{ruby_libdir}/bundler/plugin/events.rb +%{ruby_libdir}/bundler/plugin/index.rb +%{ruby_libdir}/bundler/plugin/installer.rb +%{ruby_libdir}/bundler/plugin/installer/git.rb +%{ruby_libdir}/bundler/plugin/installer/rubygems.rb +%{ruby_libdir}/bundler/plugin/source_list.rb +%{ruby_libdir}/bundler/process_lock.rb +%{ruby_libdir}/bundler/psyched_yaml.rb +%{ruby_libdir}/bundler/remote_specification.rb +%{ruby_libdir}/bundler/resolver.rb +%{ruby_libdir}/bundler/resolver/spec_group.rb +%{ruby_libdir}/bundler/retry.rb +%{ruby_libdir}/bundler/ruby_dsl.rb +%{ruby_libdir}/bundler/ruby_version.rb +%{ruby_libdir}/bundler/rubygems_ext.rb +%{ruby_libdir}/bundler/rubygems_gem_installer.rb +%{ruby_libdir}/bundler/rubygems_integration.rb +%{ruby_libdir}/bundler/runtime.rb +%{ruby_libdir}/bundler/settings.rb +%{ruby_libdir}/bundler/settings/validator.rb +%{ruby_libdir}/bundler/setup.rb +%{ruby_libdir}/bundler/shared_helpers.rb +%{ruby_libdir}/bundler/similarity_detector.rb +%{ruby_libdir}/bundler/source.rb +%{ruby_libdir}/bundler/source/gemspec.rb +%{ruby_libdir}/bundler/source/git.rb +%{ruby_libdir}/bundler/source/git/git_proxy.rb +%{ruby_libdir}/bundler/source/metadata.rb +%{ruby_libdir}/bundler/source/path.rb +%{ruby_libdir}/bundler/source/path/installer.rb +%{ruby_libdir}/bundler/source/rubygems.rb +%{ruby_libdir}/bundler/source/rubygems/remote.rb +%{ruby_libdir}/bundler/source/rubygems_aggregate.rb +%{ruby_libdir}/bundler/source_list.rb +%{ruby_libdir}/bundler/source_map.rb +%{ruby_libdir}/bundler/spec_set.rb +%{ruby_libdir}/bundler/stub_specification.rb +%{ruby_libdir}/bundler/templates/Executable +%{ruby_libdir}/bundler/templates/Executable.bundler +%{ruby_libdir}/bundler/templates/Executable.standalone +%{ruby_libdir}/bundler/templates/Gemfile +%{ruby_libdir}/bundler/templates/gems.rb +%{ruby_libdir}/bundler/templates/newgem/CHANGELOG.md.tt +%{ruby_libdir}/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +%{ruby_libdir}/bundler/templates/newgem/Gemfile.tt +%{ruby_libdir}/bundler/templates/newgem/LICENSE.txt.tt +%{ruby_libdir}/bundler/templates/newgem/README.md.tt +%{ruby_libdir}/bundler/templates/newgem/Rakefile.tt +%{ruby_libdir}/bundler/templates/newgem/bin/console.tt +%{ruby_libdir}/bundler/templates/newgem/bin/setup.tt +%{ruby_libdir}/bundler/templates/newgem/circleci/config.yml.tt +%{ruby_libdir}/bundler/templates/newgem/exe/newgem.tt +%{ruby_libdir}/bundler/templates/newgem/ext/newgem/extconf.rb.tt +%{ruby_libdir}/bundler/templates/newgem/ext/newgem/newgem.c.tt +%{ruby_libdir}/bundler/templates/newgem/ext/newgem/newgem.h.tt +%{ruby_libdir}/bundler/templates/newgem/github/workflows/main.yml.tt +%{ruby_libdir}/bundler/templates/newgem/gitignore.tt +%{ruby_libdir}/bundler/templates/newgem/gitlab-ci.yml.tt +%{ruby_libdir}/bundler/templates/newgem/lib/newgem.rb.tt +%{ruby_libdir}/bundler/templates/newgem/lib/newgem/version.rb.tt +%{ruby_libdir}/bundler/templates/newgem/newgem.gemspec.tt +%{ruby_libdir}/bundler/templates/newgem/rspec.tt +%{ruby_libdir}/bundler/templates/newgem/rubocop.yml.tt +%{ruby_libdir}/bundler/templates/newgem/spec/newgem_spec.rb.tt +%{ruby_libdir}/bundler/templates/newgem/spec/spec_helper.rb.tt +%{ruby_libdir}/bundler/templates/newgem/standard.yml.tt +%{ruby_libdir}/bundler/templates/newgem/test/minitest/newgem_test.rb.tt +%{ruby_libdir}/bundler/templates/newgem/test/minitest/test_helper.rb.tt +%{ruby_libdir}/bundler/templates/newgem/test/test-unit/newgem_test.rb.tt +%{ruby_libdir}/bundler/templates/newgem/test/test-unit/test_helper.rb.tt +%{ruby_libdir}/bundler/templates/newgem/travis.yml.tt +%{ruby_libdir}/bundler/ui.rb +%{ruby_libdir}/bundler/ui/rg_proxy.rb +%{ruby_libdir}/bundler/ui/shell.rb +%{ruby_libdir}/bundler/ui/silent.rb +%{ruby_libdir}/bundler/uri_credentials_filter.rb +%{ruby_libdir}/bundler/vendor/connection_pool/lib/connection_pool.rb +%{ruby_libdir}/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +%{ruby_libdir}/bundler/vendor/connection_pool/lib/connection_pool/version.rb +%{ruby_libdir}/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +%{ruby_libdir}/bundler/vendor/fileutils/lib/fileutils.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/errors.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/resolution.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/resolver.rb +%{ruby_libdir}/bundler/vendor/molinillo/lib/molinillo/state.rb +%{ruby_libdir}/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +%{ruby_libdir}/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +%{ruby_libdir}/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +%{ruby_libdir}/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/actions.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/actions/create_file.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/actions/create_link.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/actions/directory.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/base.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/command.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/error.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/group.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/invocation.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/line_editor.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/line_editor/basic.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/line_editor/readline.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/nested_context.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/parser.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/parser/argument.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/parser/arguments.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/parser/option.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/parser/options.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/rake_compat.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/runner.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/shell.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/shell/basic.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/shell/color.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/shell/html.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/util.rb +%{ruby_libdir}/bundler/vendor/thor/lib/thor/version.rb +%{ruby_libdir}/bundler/vendor/tmpdir/lib/tmpdir.rb +%{ruby_libdir}/bundler/vendor/tsort/lib/tsort.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/common.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/file.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/ftp.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/generic.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/http.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/https.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/ldap.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/ldaps.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/mailto.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +%{ruby_libdir}/bundler/vendor/uri/lib/uri/version.rb +%{ruby_libdir}/bundler/vendored_fileutils.rb +%{ruby_libdir}/bundler/vendored_molinillo.rb +%{ruby_libdir}/bundler/vendored_persistent.rb +%{ruby_libdir}/bundler/vendored_thor.rb +%{ruby_libdir}/bundler/vendored_tmpdir.rb +%{ruby_libdir}/bundler/vendored_tsort.rb +%{ruby_libdir}/bundler/vendored_uri.rb +%{ruby_libdir}/bundler/version.rb +%{ruby_libdir}/bundler/version_ranges.rb +%{ruby_libdir}/bundler/vlad.rb +%{ruby_libdir}/bundler/worker.rb +%{ruby_libdir}/bundler/yaml_serializer.rb %files -n rubygem-test-unit -%{gem_dir}/gems/test-unit-3.2.7 -%{gem_dir}/specifications/test-unit-3.2.7.gemspec +%{gem_dir}/gems/test-unit-%{test_unit_version} +%{gem_dir}/specifications/test-unit-%{test_unit_version}.gemspec -%files -n rubygem-xmlrpc -%license %{gem_dir}/gems/xmlrpc-0.3.0/LICENSE.txt -%doc %{gem_dir}/gems/xmlrpc-0.3.0/README.md -%dir %{gem_dir}/gems/xmlrpc-0.3.0 +%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 -%{gem_dir}/gems/xmlrpc-0.3.0/{Gemfile,Rakefile,bin,lib,xmlrpc.gemspec} -%{gem_dir}/specifications/xmlrpc-0.3.0.gemspec -%exclude %{gem_dir}/gems/xmlrpc-0.3.0/.* +%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 +* Fri Dec 31 2021 shangyibin - 3.0.3-1 +- Upgrade to version 3.0.3 + * Sat Jul 31 2021 shixuantong - 2.5.8-114 - fix CVE-2021-31799 CVE-2021-31810 CVE-2021-32066 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..d61020d --- /dev/null +++ b/rubygems-3.2.33-Fix-loading-operating_system-rb-customizations-too-late.patch @@ -0,0 +1,262 @@ +From e80e7a3d0b3d72f7af7286b935702b3fab117008 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +Date: Wed, 8 Dec 2021 21:12:24 +0100 +Subject: [PATCH 1/5] More explicit require + +This class does not use `rubygems/deprecate`. It uses +`rubygems/version`, which in turn uses `rubygems/deprecate`. Make this +explicit. +--- + lib/rubygems/requirement.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb +index d2e28fab5b4..9edd6aa7d3c 100644 +--- a/lib/rubygems/requirement.rb ++++ b/lib/rubygems/requirement.rb +@@ -1,5 +1,5 @@ + # frozen_string_literal: true +-require_relative "deprecate" ++require_relative "version" + + ## + # A Requirement is a set of one or more version restrictions. It supports a + +From 4e46dcc17ee5cabbde43b8a34063b8ab042536f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +Date: Wed, 8 Dec 2021 21:17:30 +0100 +Subject: [PATCH 2/5] Remove ineffective autoloads + +These files are loaded on startup unconditionally, so we can require +them relatively when needed. +--- + lib/rubygems.rb | 4 +--- + lib/rubygems/specification.rb | 2 ++ + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/lib/rubygems.rb b/lib/rubygems.rb +index f803e47628e..b8747409304 100644 +--- a/lib/rubygems.rb ++++ b/lib/rubygems.rb +@@ -1310,19 +1310,17 @@ def default_gem_load_paths + autoload :Licenses, File.expand_path('rubygems/util/licenses', __dir__) + autoload :NameTuple, File.expand_path('rubygems/name_tuple', __dir__) + autoload :PathSupport, File.expand_path('rubygems/path_support', __dir__) +- autoload :Platform, File.expand_path('rubygems/platform', __dir__) + autoload :RequestSet, File.expand_path('rubygems/request_set', __dir__) +- autoload :Requirement, File.expand_path('rubygems/requirement', __dir__) + autoload :Resolver, File.expand_path('rubygems/resolver', __dir__) + autoload :Source, File.expand_path('rubygems/source', __dir__) + autoload :SourceList, File.expand_path('rubygems/source_list', __dir__) + autoload :SpecFetcher, File.expand_path('rubygems/spec_fetcher', __dir__) +- autoload :Specification, File.expand_path('rubygems/specification', __dir__) + autoload :Util, File.expand_path('rubygems/util', __dir__) + autoload :Version, File.expand_path('rubygems/version', __dir__) + end + + require_relative 'rubygems/exceptions' ++require_relative 'rubygems/specification' + + # REFACTOR: This should be pulled out into some kind of hacks file. + begin +diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb +index d3b96491a28..dc5e5ba0138 100644 +--- a/lib/rubygems/specification.rb ++++ b/lib/rubygems/specification.rb +@@ -9,6 +9,8 @@ + require_relative 'deprecate' + require_relative 'basic_specification' + require_relative 'stub_specification' ++require_relative 'platform' ++require_relative 'requirement' + require_relative 'specification_policy' + require_relative 'util/list' + + +From 96b6b3e04e8e4fec17f63079a0caf999a2709d71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +Date: Wed, 8 Dec 2021 21:45:16 +0100 +Subject: [PATCH 3/5] Load `operating_system.rb` customizations before setting + up default gems + +It's very common for packagers to configure gem paths in this file, for +example, `Gem.default_dir`. Also, setting up default gems requires these +paths to be set, so that we know which default gems need to be setup. + +If we setup default gems before loading `operatin_system.rb` +customizations, the wrong default gems will be setup. + +Unfortunately, default gems loaded by `operating_system.rb` can't be +upgraded if we do this, but it seems much of a smaller issue. I wasn't +even fully sure it was the right thing to do when I added that, and it +was not the culprit of the end user issue that led to making that +change. +--- + .github/workflows/install-rubygems.yml | 5 ---- + lib/rubygems.rb | 32 +++++++++++++------------- + test/rubygems/test_rubygems.rb | 23 ++++++++++++++++++ + 3 files changed, 39 insertions(+), 21 deletions(-) + +diff --git a/lib/rubygems.rb b/lib/rubygems.rb +index b8747409304..11474b6554c 100644 +--- a/lib/rubygems.rb ++++ b/lib/rubygems.rb +@@ -1323,22 +1323,6 @@ def default_gem_load_paths + require_relative 'rubygems/specification' + + # REFACTOR: This should be pulled out into some kind of hacks file. +-begin +- ## +- # Defaults the Ruby implementation wants to provide for RubyGems +- +- require "rubygems/defaults/#{RUBY_ENGINE}" +-rescue LoadError +-end +- +-## +-# Loads the default specs. +-Gem::Specification.load_defaults +- +-require_relative 'rubygems/core_ext/kernel_gem' +-require_relative 'rubygems/core_ext/kernel_require' +-require_relative 'rubygems/core_ext/kernel_warn' +- + begin + ## + # Defaults the operating system (or packager) wants to provide for RubyGems. +@@ -1354,3 +1338,19 @@ def default_gem_load_paths + "the problem and ask for help." + raise e.class, msg + end ++ ++begin ++ ## ++ # Defaults the Ruby implementation wants to provide for RubyGems ++ ++ require "rubygems/defaults/#{RUBY_ENGINE}" ++rescue LoadError ++end ++ ++## ++# Loads the default specs. ++Gem::Specification.load_defaults ++ ++require_relative 'rubygems/core_ext/kernel_gem' ++require_relative 'rubygems/core_ext/kernel_require' ++require_relative 'rubygems/core_ext/kernel_warn' +diff --git a/test/rubygems/test_rubygems.rb b/test/rubygems/test_rubygems.rb +index 493b9fdf4a3..fa77a299322 100644 +--- a/test/rubygems/test_rubygems.rb ++++ b/test/rubygems/test_rubygems.rb +@@ -22,6 +22,29 @@ def test_operating_system_other_exceptions + "the problem and ask for help." + end + ++ def test_operating_system_customizing_default_dir ++ pend "does not apply to truffleruby" if RUBY_ENGINE == 'truffleruby' ++ pend "loads a custom defaults/jruby file that gets in the middle" if RUBY_ENGINE == 'jruby' ++ ++ # On a non existing default dir, there should be no gems ++ ++ path = util_install_operating_system_rb <<-RUBY ++ module Gem ++ def self.default_dir ++ File.expand_path("foo") ++ end ++ end ++ RUBY ++ ++ output = Gem::Util.popen( ++ *ruby_with_rubygems_and_fake_operating_system_in_load_path(path), ++ '-e', ++ "require \"rubygems\"; puts Gem::Specification.stubs.map(&:full_name)", ++ {:err => [:child, :out]} ++ ).strip ++ assert_empty output ++ end ++ + private + + def util_install_operating_system_rb(content) + +From 52cfdd14fd1213a97aac12f01177e27779de9035 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +Date: Thu, 9 Dec 2021 06:08:31 +0100 +Subject: [PATCH 4/5] Install default fiddle on latest ruby on specs that need + it + +Otherwise first OS customizations load and activate that fiddle version, +but then when we change to `Gem.default_dir`, that fiddle version is no +longer there. +--- + bundler/spec/commands/clean_spec.rb | 2 +- + bundler/spec/install/gems/standalone_spec.rb | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb +index ffaf22dbb32..65231b35fac 100644 +--- a/spec/bundler/commands/clean_spec.rb ++++ b/spec/bundler/commands/clean_spec.rb +@@ -638,7 +638,7 @@ def should_not_have_gems(*gems) + s.executables = "irb" + end + +- realworld_system_gems "fiddle --version 1.0.6", "tsort --version 0.1.0", "pathname --version 0.1.0", "set --version 1.0.1" ++ realworld_system_gems "fiddle --version 1.0.8", "tsort --version 0.1.0", "pathname --version 0.1.0", "set --version 1.0.1" + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" +diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb +index db16a1b0e13..faefda25f45 100644 +--- a/spec/bundler/install/gems/standalone_spec.rb ++++ b/spec/bundler/install/gems/standalone_spec.rb +@@ -113,7 +113,7 @@ + skip "does not work on rubygems versions where `--install_dir` doesn't respect --default" unless Gem::Installer.for_spec(loaded_gemspec, :install_dir => "/foo").default_spec_file == "/foo/specifications/default/bundler-#{Bundler::VERSION}.gemspec" # Since rubygems 3.2.0.rc.2 + skip "does not work on old rubies because the realworld gems that need to be installed don't support them" if RUBY_VERSION < "2.7.0" + +- realworld_system_gems "fiddle --version 1.0.6", "tsort --version 0.1.0" ++ realworld_system_gems "fiddle --version 1.0.8", "tsort --version 0.1.0" + + necessary_system_gems = ["optparse --version 0.1.1", "psych --version 3.3.2", "yaml --version 0.1.1", "logger --version 1.4.3", "etc --version 1.2.0", "stringio --version 3.0.0"] + necessary_system_gems += ["shellwords --version 0.1.0", "base64 --version 0.1.0", "resolv --version 0.2.1"] if Gem.rubygems_version < Gem::Version.new("3.3.3.a") + +From c6a9c81021092c9157f5616a2bbe1323411a5bf8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Rodr=C3=ADguez?= +Date: Thu, 9 Dec 2021 12:46:23 +0100 +Subject: [PATCH 5/5] Resolve symlinks in LOAD_PATH when activating + pre-required default gems + +Some double load issues were reported a while ago by OS packagers where +if a gem has been required before rubygems, and then after, rubygems +require would cause a double load. + +We avoid this issue by activating the corresponding gem if we detect +that a file in the default LOAD_PATH that belongs to a default gem has +already been required when rubygems registers default gems. + +However, the fix does not take into account that the default LOAD_PATH +could potentially include symlinks. This change fixes the same double +load issue described above but for situations where the default +LOAD_PATH includes symlinks. +--- + lib/rubygems.rb | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/lib/rubygems.rb b/lib/rubygems.rb +index 11474b6554c..b7dda38d522 100644 +--- a/lib/rubygems.rb ++++ b/lib/rubygems.rb +@@ -1293,7 +1293,12 @@ def already_loaded?(file) + end + + def default_gem_load_paths +- @default_gem_load_paths ||= $LOAD_PATH[load_path_insert_index..-1] ++ @default_gem_load_paths ||= $LOAD_PATH[load_path_insert_index..-1].map do |lp| ++ expanded = File.expand_path(lp) ++ next expanded unless File.exist?(expanded) ++ ++ File.realpath(expanded) ++ end + end + end + diff --git a/rubygems.prov b/rubygems.prov index b7c9777..f23ec3f 100644 --- a/rubygems.prov +++ b/rubygems.prov @@ -9,9 +9,9 @@ module RubyGemsProv def self.normalize_prerelease(version) if version.prerelease? prerelease = version.version.sub /^#{version.release}\./, '' - "#{version.release}-0.1.#{prerelease}" + "#{version.release}~#{prerelease}" else - "#{version.release}-1" + version.release end end end diff --git a/rubygems.req b/rubygems.req index d75247d..38e4a9c 100644 --- a/rubygems.req +++ b/rubygems.req @@ -35,31 +35,35 @@ module RubyGemsReq # with RPM .spec file. def self.requirement_versions_to_rpm(requirement) self.expand_requirement(requirement.requirements).map do |op, version| - version == Gem::Version.new(0) ? "" : "#{op} #{version}" + version == Gem::Version.new(0) ? "" : " #{op} #{version}" end end + + # Compose dependency together with its requirements in RPM rich dependency + # string. + def self.compose_dependency_string(name, requirements) + dependency_strings = requirements.map { |requirement| name + requirement } + dependency_string = dependency_strings.join(' with ') + dependency_string.prepend('(').concat(')') if dependency_strings.length > 1 + dependency_string + end end # Report RubyGems dependency, versioned if required. def self.rubygems_dependency(specification) - Helpers::requirement_versions_to_rpm(specification.required_rubygems_version).each do |requirement| - dependency_string = "ruby(rubygems)" - dependency_string += " #{specification.required_rubygems_version}" if requirement&.length > 0 - puts dependency_string - end + 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_strings = Helpers::requirement_versions_to_rpm(dependency.requirement).map do |requirement| - requirement_string = "rubygem(#{dependency.name})" - requirement_string += " #{requirement}" if requirement&.length > 0 - requirement_string - end - dependency_string = dependency_strings.join(' with ') - dependency_string.prepend('(').concat(')') if dependency_strings.length > 1 - puts dependency_string + dependency_name = "rubygem(#{dependency.name})" + requirements = Helpers::requirement_versions_to_rpm(dependency.requirement) + + puts Helpers::compose_dependency_string(dependency_name, requirements) end end diff --git a/upgrade_lib_rexml.patch b/upgrade_lib_rexml.patch deleted file mode 100644 index 1a43ba0..0000000 --- a/upgrade_lib_rexml.patch +++ /dev/null @@ -1,548 +0,0 @@ -diff -Nur ruby-2.5.8/lib/rexml/doctype.rb ruby-2.5.9/lib/rexml/doctype.rb ---- ruby-2.5.8/lib/rexml/doctype.rb 2020-03-31 12:15:56.000000000 +0000 -+++ ruby-2.5.9/lib/rexml/doctype.rb 2021-04-05 11:46:35.000000000 +0000 -@@ -7,6 +7,39 @@ - require 'rexml/xmltokens' - - module REXML -+ class ReferenceWriter -+ def initialize(id_type, -+ public_id_literal, -+ system_literal) -+ @id_type = id_type -+ @public_id_literal = public_id_literal -+ @system_literal = system_literal -+ @default_quote = "\"" -+ end -+ -+ def write(output) -+ output << " #{@id_type}" -+ if @public_id_literal -+ if @public_id_literal.include?("'") -+ quote = "\"" -+ else -+ quote = @default_quote -+ end -+ output << " #{quote}#{@public_id_literal}#{quote}" -+ end -+ if @system_literal -+ if @system_literal.include?("'") -+ quote = "\"" -+ elsif @system_literal.include?("\"") -+ quote = "'" -+ else -+ quote = @default_quote -+ end -+ output << " #{quote}#{@system_literal}#{quote}" -+ end -+ end -+ end -+ - # Represents an XML DOCTYPE declaration; that is, the contents of . DOCTYPES can be used to declare the DTD of a document, as well as - # being used to declare entities used in the document. -@@ -50,6 +83,8 @@ - super( parent ) - @name = first.name - @external_id = first.external_id -+ @long_name = first.instance_variable_get(:@long_name) -+ @uri = first.instance_variable_get(:@uri) - elsif first.kind_of? Array - super( parent ) - @name = first[0] -@@ -112,9 +147,12 @@ - output << START - output << ' ' - output << @name -- output << " #@external_id" if @external_id -- output << " #{@long_name.inspect}" if @long_name -- output << " #{@uri.inspect}" if @uri -+ if @external_id -+ reference_writer = ReferenceWriter.new(@external_id, -+ @long_name, -+ @uri) -+ reference_writer.write(output) -+ end - unless @children.empty? - output << ' [' - @children.each { |child| -@@ -249,9 +287,9 @@ - end - - def to_s -- notation = "" - notation - end -diff -Nur ruby-2.5.8/lib/rexml/parsers/baseparser.rb ruby-2.5.9/lib/rexml/parsers/baseparser.rb ---- ruby-2.5.8/lib/rexml/parsers/baseparser.rb 2020-03-31 12:15:56.000000000 +0000 -+++ ruby-2.5.9/lib/rexml/parsers/baseparser.rb 2021-04-05 11:46:35.000000000 +0000 -@@ -1,4 +1,7 @@ - # frozen_string_literal: false -+ -+require "strscan" -+ - require 'rexml/parseexception' - require 'rexml/undefinednamespaceexception' - require 'rexml/source' -@@ -32,8 +35,12 @@ - COMBININGCHAR = '' # TODO - EXTENDER = '' # TODO - -- NCNAME_STR= "[#{LETTER}_:][-[:alnum:]._:#{COMBININGCHAR}#{EXTENDER}]*" -- NAME_STR= "(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})" -+ NCNAME_STR= "[#{LETTER}_][-[:alnum:]._#{COMBININGCHAR}#{EXTENDER}]*" -+ QNAME_STR= "(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})" -+ QNAME = /(#{QNAME_STR})/ -+ -+ # Just for backward compatibility. For example, kramdown uses this. -+ # It's not used in REXML. - UNAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}" - - NAMECHAR = '[\-\w\.:]' -@@ -45,8 +52,7 @@ - - DOCTYPE_START = /\A\s*/um -- DOCTYPE_PATTERN = /\s*)/um -- ATTRIBUTE_PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\4/um -+ ATTRIBUTE_PATTERN = /\s*(#{QNAME_STR})\s*=\s*(["'])(.*?)\4/um - COMMENT_START = /\A/um - CDATA_START = /\A/um - INSTRUCTION_START = /\A<\?/u - INSTRUCTION_PATTERN = /<\?(.*?)(\s+.*?)?\?>/um -- TAG_MATCH = /^<((?>#{NAME_STR}))\s*((?>\s+#{UNAME_STR}\s*=\s*(["']).*?\5)*)\s*(\/)?>/um -- CLOSE_MATCH = /^\s*<\/(#{NAME_STR})\s*>/um -+ TAG_MATCH = /\A<((?>#{QNAME_STR}))/um -+ CLOSE_MATCH = /\A\s*<\/(#{QNAME_STR})\s*>/um - - VERSION = /\bversion\s*=\s*["'](.*?)['"]/um - ENCODING = /\bencoding\s*=\s*["'](.*?)['"]/um - STANDALONE = /\bstandalone\s*=\s*["'](.*?)['"]/um - - ENTITY_START = /\A\s*/um - SYSTEMENTITY = /\A\s*(%.*?;)\s*$/um -@@ -78,9 +83,6 @@ - ATTDEF_RE = /#{ATTDEF}/ - ATTLISTDECL_START = /\A\s*/um -- NOTATIONDECL_START = /\A\s*/um -- SYSTEM = /\A\s*/um - - TEXT_PATTERN = /\A([^<]*)/um - -@@ -98,6 +100,11 @@ - GEDECL = "" - ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um - -+ NOTATIONDECL_START = /\A\s* 0 - #STDERR.puts @source.encoding -- @source.read if @source.buffer.size<2 - #STDERR.puts "BUFFER = #{@source.buffer.inspect}" - if @document_status == nil -- #@source.consume( /^\s*/um ) -- word = @source.match( /^((?:\s+)|(?:<[^>]*>))/um ) -+ word = @source.match( /\A((?:\s+)|(?:<[^>]*>))/um ) - word = word[1] unless word.nil? - #STDERR.puts "WORD = #{word.inspect}" - case word -@@ -226,38 +231,49 @@ - when INSTRUCTION_START - return [ :processing_instruction, *@source.match(INSTRUCTION_PATTERN, true)[1,2] ] - when DOCTYPE_START -- md = @source.match( DOCTYPE_PATTERN, true ) -+ base_error_message = "Malformed DOCTYPE" -+ @source.match(DOCTYPE_START, true) - @nsstack.unshift(curr_ns=Set.new) -- identity = md[1] -- close = md[2] -- identity =~ IDENTITY -- name = $1 -- raise REXML::ParseException.new("DOCTYPE is missing a name") if name.nil? -- pub_sys = $2.nil? ? nil : $2.strip -- long_name = $4.nil? ? nil : $4.strip -- uri = $6.nil? ? nil : $6.strip -- args = [ :start_doctype, name, pub_sys, long_name, uri ] -- if close == ">" -+ name = parse_name(base_error_message) -+ if @source.match(/\A\s*\[/um, true) -+ id = [nil, nil, nil] -+ @document_status = :in_doctype -+ elsif @source.match(/\A\s*>/um, true) -+ id = [nil, nil, nil] - @document_status = :after_doctype -- @source.read if @source.buffer.size<2 -- md = @source.match(/^\s*/um, true) -- @stack << [ :end_doctype ] - else -- @document_status = :in_doctype -+ id = parse_id(base_error_message, -+ accept_external_id: true, -+ accept_public_id: false) -+ if id[0] == "SYSTEM" -+ # For backward compatibility -+ id[1], id[2] = id[2], nil -+ end -+ if @source.match(/\A\s*\[/um, true) -+ @document_status = :in_doctype -+ elsif @source.match(/\A\s*>/um, true) -+ @document_status = :after_doctype -+ else -+ message = "#{base_error_message}: garbage after external ID" -+ raise REXML::ParseException.new(message, @source) -+ end -+ end -+ args = [:start_doctype, name, *id] -+ if @document_status == :after_doctype -+ @source.match(/\A\s*/um, true) -+ @stack << [ :end_doctype ] - end - return args -- when /^\s+/ -+ when /\A\s+/ - else - @document_status = :after_doctype -- @source.read if @source.buffer.size<2 -- md = @source.match(/\s*/um, true) - if @source.encoding == "UTF-8" - @source.buffer.force_encoding(::Encoding::UTF_8) - end - end - end - if @document_status == :in_doctype -- md = @source.match(/\s*(.*?>)/um) -+ md = @source.match(/\A\s*(.*?>)/um) - case md[1] - when SYSTEMENTITY - match = @source.match( SYSTEMENTITY, true )[1] -@@ -314,33 +330,50 @@ - end - return [ :attlistdecl, element, pairs, contents ] - when NOTATIONDECL_START -- md = nil -- if @source.match( PUBLIC ) -- md = @source.match( PUBLIC, true ) -- vals = [md[1],md[2],md[4],md[6]] -- elsif @source.match( SYSTEM ) -- md = @source.match( SYSTEM, true ) -- vals = [md[1],md[2],nil,md[4]] -- else -- raise REXML::ParseException.new( "error parsing notation: no matching pattern", @source ) -+ base_error_message = "Malformed notation declaration" -+ unless @source.match(/\A\s*/um) -+ message = "#{base_error_message}: name is missing" -+ else -+ message = "#{base_error_message}: invalid declaration name" -+ end -+ raise REXML::ParseException.new(message, @source) -+ end -+ name = parse_name(base_error_message) -+ id = parse_id(base_error_message, -+ accept_external_id: true, -+ accept_public_id: true) -+ unless @source.match(/\A\s*>/um, true) -+ message = "#{base_error_message}: garbage before end >" -+ raise REXML::ParseException.new(message, @source) - end -- return [ :notationdecl, *vals ] -+ return [:notationdecl, name, *id] - when DOCTYPE_END - @document_status = :after_doctype - @source.match( DOCTYPE_END, true ) - return [ :end_doctype ] - end - end -+ if @document_status == :after_doctype -+ @source.match(/\A\s*/um, true) -+ end - begin -+ @source.read if @source.buffer.size<2 - if @source.buffer[0] == ?< - if @source.buffer[1] == ?/ - @nsstack.shift - last_tag = @tags.pop - #md = @source.match_to_consume( '>', CLOSE_MATCH) - md = @source.match( CLOSE_MATCH, true ) -- raise REXML::ParseException.new( "Missing end tag for "+ -- "'#{last_tag}' (got \"#{md[1]}\")", -- @source) unless last_tag == md[1] -+ if md and !last_tag -+ message = "Unexpected top-level end tag (got '#{md[1]}')" -+ raise REXML::ParseException.new(message, @source) -+ end -+ if md.nil? or last_tag != md[1] -+ message = "Missing end tag for '#{last_tag}'" -+ message << " (got '#{md[1]}')" if md -+ raise REXML::ParseException.new(message, @source) -+ end - return [ :end_element, last_tag ] - elsif @source.buffer[1] == ?! - md = @source.match(/\A(\s*[^>]*>)/um) -@@ -374,40 +407,11 @@ - raise REXML::ParseException.new("missing attribute quote", @source) if @source.match(MISSING_ATTRIBUTE_QUOTES ) - raise REXML::ParseException.new("malformed XML: missing tag start", @source) - end -- attributes = {} -+ @document_status = :in_element - prefixes = Set.new - prefixes << md[2] if md[2] - @nsstack.unshift(curr_ns=Set.new) -- if md[4].size > 0 -- attrs = md[4].scan( ATTRIBUTE_PATTERN ) -- raise REXML::ParseException.new( "error parsing attributes: [#{attrs.join ', '}], excess = \"#$'\"", @source) if $' and $'.strip.size > 0 -- attrs.each do |attr_name, prefix, local_part, quote, value| -- if prefix == "xmlns" -- if local_part == "xml" -- if value != "http://www.w3.org/XML/1998/namespace" -- msg = "The 'xml' prefix must not be bound to any other namespace "+ -- "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" -- raise REXML::ParseException.new( msg, @source, self ) -- end -- elsif local_part == "xmlns" -- msg = "The 'xmlns' prefix must not be declared "+ -- "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" -- raise REXML::ParseException.new( msg, @source, self) -- end -- curr_ns << local_part -- elsif prefix -- prefixes << prefix unless prefix == "xml" -- end -- -- if attributes.has_key?(attr_name) -- msg = "Duplicate attribute #{attr_name.inspect}" -- raise REXML::ParseException.new(msg, @source, self) -- end -- -- attributes[attr_name] = value -- end -- end -- -+ attributes, closed = parse_attributes(prefixes, curr_ns) - # Verify that all of the prefixes have been defined - for prefix in prefixes - unless @nsstack.find{|k| k.member?(prefix)} -@@ -415,7 +419,7 @@ - end - end - -- if md[6] -+ if closed - @closed = md[1] - @nsstack.shift - else -@@ -508,6 +512,169 @@ - return false if /\AUTF-16\z/i =~ xml_declaration_encoding - true - end -+ -+ def parse_name(base_error_message) -+ md = @source.match(/\A\s*#{NAME}/um, true) -+ unless md -+ if @source.match(/\A\s*\S/um) -+ message = "#{base_error_message}: invalid name" -+ else -+ message = "#{base_error_message}: name is missing" -+ end -+ raise REXML::ParseException.new(message, @source) -+ end -+ md[1] -+ end -+ -+ def parse_id(base_error_message, -+ accept_external_id:, -+ accept_public_id:) -+ if accept_external_id and (md = @source.match(EXTERNAL_ID_PUBLIC, true)) -+ pubid = system = nil -+ pubid_literal = md[1] -+ pubid = pubid_literal[1..-2] if pubid_literal # Remove quote -+ system_literal = md[2] -+ system = system_literal[1..-2] if system_literal # Remove quote -+ ["PUBLIC", pubid, system] -+ elsif accept_public_id and (md = @source.match(PUBLIC_ID, true)) -+ pubid = system = nil -+ pubid_literal = md[1] -+ pubid = pubid_literal[1..-2] if pubid_literal # Remove quote -+ ["PUBLIC", pubid, nil] -+ elsif accept_external_id and (md = @source.match(EXTERNAL_ID_SYSTEM, true)) -+ system = nil -+ system_literal = md[1] -+ system = system_literal[1..-2] if system_literal # Remove quote -+ ["SYSTEM", nil, system] -+ else -+ details = parse_id_invalid_details(accept_external_id: accept_external_id, -+ accept_public_id: accept_public_id) -+ message = "#{base_error_message}: #{details}" -+ raise REXML::ParseException.new(message, @source) -+ end -+ end -+ -+ def parse_id_invalid_details(accept_external_id:, -+ accept_public_id:) -+ public = /\A\s*PUBLIC/um -+ system = /\A\s*SYSTEM/um -+ if (accept_external_id or accept_public_id) and @source.match(/#{public}/um) -+ if @source.match(/#{public}(?:\s+[^'"]|\s*[\[>])/um) -+ return "public ID literal is missing" -+ end -+ unless @source.match(/#{public}\s+#{PUBIDLITERAL}/um) -+ return "invalid public ID literal" -+ end -+ if accept_public_id -+ if @source.match(/#{public}\s+#{PUBIDLITERAL}\s+[^'"]/um) -+ return "system ID literal is missing" -+ end -+ unless @source.match(/#{public}\s+#{PUBIDLITERAL}\s+#{SYSTEMLITERAL}/um) -+ return "invalid system literal" -+ end -+ "garbage after system literal" -+ else -+ "garbage after public ID literal" -+ end -+ elsif accept_external_id and @source.match(/#{system}/um) -+ if @source.match(/#{system}(?:\s+[^'"]|\s*[\[>])/um) -+ return "system literal is missing" -+ end -+ unless @source.match(/#{system}\s+#{SYSTEMLITERAL}/um) -+ return "invalid system literal" -+ end -+ "garbage after system literal" -+ else -+ unless @source.match(/\A\s*(?:PUBLIC|SYSTEM)\s/um) -+ return "invalid ID type" -+ end -+ "ID type is missing" -+ end -+ end -+ -+ def parse_attributes(prefixes, curr_ns) -+ attributes = {} -+ closed = false -+ match_data = @source.match(/^(.*?)(\/)?>/um, true) -+ if match_data.nil? -+ message = "Start tag isn't ended" -+ raise REXML::ParseException.new(message, @source) -+ end -+ -+ raw_attributes = match_data[1] -+ closed = !match_data[2].nil? -+ return attributes, closed if raw_attributes.nil? -+ return attributes, closed if raw_attributes.empty? -+ -+ scanner = StringScanner.new(raw_attributes) -+ until scanner.eos? -+ if scanner.scan(/\s+/) -+ break if scanner.eos? -+ end -+ -+ pos = scanner.pos -+ loop do -+ break if scanner.scan(ATTRIBUTE_PATTERN) -+ unless scanner.scan(QNAME) -+ message = "Invalid attribute name: <#{scanner.rest}>" -+ raise REXML::ParseException.new(message, @source) -+ end -+ name = scanner[0] -+ unless scanner.scan(/\s*=\s*/um) -+ message = "Missing attribute equal: <#{name}>" -+ raise REXML::ParseException.new(message, @source) -+ end -+ quote = scanner.scan(/['"]/) -+ unless quote -+ message = "Missing attribute value start quote: <#{name}>" -+ raise REXML::ParseException.new(message, @source) -+ end -+ unless scanner.scan(/.*#{Regexp.escape(quote)}/um) -+ match_data = @source.match(/^(.*?)(\/)?>/um, true) -+ if match_data -+ scanner << "/" if closed -+ scanner << ">" -+ scanner << match_data[1] -+ scanner.pos = pos -+ closed = !match_data[2].nil? -+ next -+ end -+ message = -+ "Missing attribute value end quote: <#{name}>: <#{quote}>" -+ raise REXML::ParseException.new(message, @source) -+ end -+ end -+ name = scanner[1] -+ prefix = scanner[2] -+ local_part = scanner[3] -+ # quote = scanner[4] -+ value = scanner[5] -+ if prefix == "xmlns" -+ if local_part == "xml" -+ if value != "http://www.w3.org/XML/1998/namespace" -+ msg = "The 'xml' prefix must not be bound to any other namespace "+ -+ "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" -+ raise REXML::ParseException.new( msg, @source, self ) -+ end -+ elsif local_part == "xmlns" -+ msg = "The 'xmlns' prefix must not be declared "+ -+ "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" -+ raise REXML::ParseException.new( msg, @source, self) -+ end -+ curr_ns << local_part -+ elsif prefix -+ prefixes << prefix unless prefix == "xml" -+ end -+ -+ if attributes.has_key?(name) -+ msg = "Duplicate attribute #{name.inspect}" -+ raise REXML::ParseException.new(msg, @source, self) -+ end -+ -+ attributes[name] = value -+ end -+ return attributes, closed -+ end - end - end - end -diff -Nur ruby-2.5.8/lib/rexml/rexml.rb ruby-2.5.9/lib/rexml/rexml.rb ---- ruby-2.5.8/lib/rexml/rexml.rb 2020-03-31 12:15:56.000000000 +0000 -+++ ruby-2.5.9/lib/rexml/rexml.rb 2021-04-05 11:46:35.000000000 +0000 -@@ -24,8 +24,8 @@ - module REXML - COPYRIGHT = "Copyright © 2001-2008 Sean Russell " - DATE = "2008/019" -- VERSION = "3.1.7.3" -- REVISION = %w$Revision: 53141 $[1] || '' -+ VERSION = "3.1.7.4" -+ REVISION = %w$Revision: 67937 $[1] || '' - - Copyright = COPYRIGHT - Version = VERSION diff --git a/upgrade_lib_rexml_test.patch b/upgrade_lib_rexml_test.patch deleted file mode 100644 index f50cd14..0000000 --- a/upgrade_lib_rexml_test.patch +++ /dev/null @@ -1,775 +0,0 @@ -diff -Nur ruby-2.5.8/test/rexml/parse/test_document_type_declaration.rb ruby-2.5.9/test/rexml/parse/test_document_type_declaration.rb ---- ruby-2.5.8/test/rexml/parse/test_document_type_declaration.rb 2020-03-31 12:15:56.000000000 +0000 -+++ ruby-2.5.9/test/rexml/parse/test_document_type_declaration.rb 2021-04-05 11:46:35.000000000 +0000 -@@ -5,17 +5,187 @@ - module REXMLTests - class TestParseDocumentTypeDeclaration < Test::Unit::TestCase - private -- def xml(internal_subset) -- <<-XML -- -+ def parse(doctype) -+ REXML::Document.new(<<-XML).doctype -+#{doctype} - - XML - end - -- def parse(internal_subset) -- REXML::Document.new(xml(internal_subset)).doctype -+ class TestName < self -+ def test_valid -+ doctype = parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ assert_equal("r", doctype.name) -+ end -+ -+ def test_garbage_plus_before_name_at_line_start -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed DOCTYPE: invalid name -+Line: 5 -+Position: 51 -+Last 80 unconsumed characters: -++ r SYSTEM "urn:x-rexml:test" [ ]> -+ DETAIL -+ end -+ end -+ -+ class TestExternalID < self -+ class TestSystem < self -+ def test_left_bracket_in_system_literal -+ doctype = parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ assert_equal([ -+ "r", -+ "SYSTEM", -+ nil, -+ "urn:x-rexml:[test", -+ ], -+ [ -+ doctype.name, -+ doctype.external_id, -+ doctype.public, -+ doctype.system, -+ ]) -+ end -+ -+ def test_greater_than_in_system_literal -+ doctype = parse(<<-DOCTYPE) -+test" [ -+]> -+ DOCTYPE -+ assert_equal([ -+ "r", -+ "SYSTEM", -+ nil, -+ "urn:x-rexml:>test", -+ ], -+ [ -+ doctype.name, -+ doctype.external_id, -+ doctype.public, -+ doctype.system, -+ ]) -+ end -+ -+ def test_no_literal -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed DOCTYPE: system literal is missing -+Line: 3 -+Position: 26 -+Last 80 unconsumed characters: -+ SYSTEM> -+ DETAIL -+ end -+ -+ def test_garbage_after_literal -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed DOCTYPE: garbage after external ID -+Line: 3 -+Position: 36 -+Last 80 unconsumed characters: -+x'> -+ DETAIL -+ end -+ -+ def test_single_quote -+ doctype = parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ assert_equal("r\".dtd", doctype.system) -+ end -+ -+ def test_double_quote -+ doctype = parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ assert_equal("r'.dtd", doctype.system) -+ end -+ end -+ -+ class TestPublic < self -+ class TestPublicIDLiteral < self -+ def test_content_double_quote -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed DOCTYPE: invalid public ID literal -+Line: 3 -+Position: 62 -+Last 80 unconsumed characters: -+ PUBLIC 'double quote " is invalid' "r.dtd"> -+ DETAIL -+ end -+ -+ def test_single_quote -+ doctype = parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ assert_equal("public-id-literal", doctype.public) -+ end -+ -+ def test_double_quote -+ doctype = parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ assert_equal("public'-id-literal", doctype.public) -+ end -+ end -+ -+ class TestSystemLiteral < self -+ def test_garbage_after_literal -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed DOCTYPE: garbage after external ID -+Line: 3 -+Position: 65 -+Last 80 unconsumed characters: -+x'> -+ DETAIL -+ end -+ -+ def test_single_quote -+ doctype = parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ assert_equal("system\"-literal", doctype.system) -+ end -+ -+ def test_double_quote -+ doctype = parse(<<-DOCTYPE) -+ -+ DOCTYPE -+ assert_equal("system'-literal", doctype.system) -+ end -+ end -+ end - end - - class TestMixed < self -@@ -45,6 +215,15 @@ - assert_equal([REXML::NotationDecl, REXML::AttlistDecl], - doctype.children.collect(&:class)) - end -+ -+ private -+ def parse(internal_subset) -+ super(<<-DOCTYPE) -+ -+ DOCTYPE -+ end - end - end - end -diff -Nur ruby-2.5.8/test/rexml/parse/test_element.rb ruby-2.5.9/test/rexml/parse/test_element.rb ---- ruby-2.5.8/test/rexml/parse/test_element.rb 1970-01-01 00:00:00.000000000 +0000 -+++ ruby-2.5.9/test/rexml/parse/test_element.rb 2021-04-05 11:46:35.000000000 +0000 -@@ -0,0 +1,77 @@ -+require "test/unit" -+require "rexml/document" -+ -+module REXMLTests -+ class TestParseElement < Test::Unit::TestCase -+ def parse(xml) -+ REXML::Document.new(xml) -+ end -+ -+ class TestInvalid < self -+ def test_top_level_end_tag -+ exception = assert_raise(REXML::ParseException) do -+ parse("") -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Unexpected top-level end tag (got 'a') -+Line: 1 -+Position: 4 -+Last 80 unconsumed characters: -+ -+ DETAIL -+ end -+ -+ def test_no_end_tag -+ exception = assert_raise(REXML::ParseException) do -+ parse("") -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Invalid attribute name: <:a=""> -+Line: 1 -+Position: 13 -+Last 80 unconsumed characters: -+ -+ DETAIL -+ end -+ -+ def test_garbage_less_than_before_root_element_at_line_start -+ exception = assert_raise(REXML::ParseException) do -+ parse("<\n") -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+malformed XML: missing tag start -+Line: 2 -+Position: 6 -+Last 80 unconsumed characters: -+< -+ DETAIL -+ end -+ -+ def test_garbage_less_than_slash_before_end_tag_at_line_start -+ exception = assert_raise(REXML::ParseException) do -+ parse("") -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Missing end tag for 'x' -+Line: 2 -+Position: 10 -+Last 80 unconsumed characters: -+ -+ DETAIL -+ end -+ end -+ end -+end -diff -Nur ruby-2.5.8/test/rexml/parse/test_notation_declaration.rb ruby-2.5.9/test/rexml/parse/test_notation_declaration.rb ---- ruby-2.5.8/test/rexml/parse/test_notation_declaration.rb 2020-03-31 12:15:56.000000000 +0000 -+++ ruby-2.5.9/test/rexml/parse/test_notation_declaration.rb 2021-04-05 11:46:35.000000000 +0000 -@@ -23,10 +23,100 @@ - doctype = parse("") - assert_equal("name", doctype.notation("name").name) - end -+ -+ def test_no_name -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed notation declaration: name is missing -+Line: 5 -+Position: 72 -+Last 80 unconsumed characters: -+ ]> -+ DETAIL -+ end -+ -+ def test_invalid_name -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed notation declaration: invalid name -+Line: 5 -+Position: 74 -+Last 80 unconsumed characters: -+'> ]> -+ DETAIL -+ end -+ -+ def test_no_id_type -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed notation declaration: invalid ID type -+Line: 5 -+Position: 77 -+Last 80 unconsumed characters: -+> ]> -+ DETAIL -+ end -+ -+ def test_invalid_id_type -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed notation declaration: invalid ID type -+Line: 5 -+Position: 85 -+Last 80 unconsumed characters: -+ INVALID> ]> -+ DETAIL -+ end - end - - class TestExternalID < self - class TestSystem < self -+ def test_no_literal -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed notation declaration: system literal is missing -+Line: 5 -+Position: 84 -+Last 80 unconsumed characters: -+ SYSTEM> ]> -+ DETAIL -+ end -+ -+ def test_garbage_after_literal -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed notation declaration: garbage before end > -+Line: 5 -+Position: 103 -+Last 80 unconsumed characters: -+x'> ]> -+ DETAIL -+ end -+ - def test_single_quote - doctype = parse(<<-INTERNAL_SUBSET) - -@@ -44,6 +134,21 @@ - - class TestPublic < self - class TestPublicIDLiteral < self -+ def test_content_double_quote -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed notation declaration: invalid public ID literal -+Line: 5 -+Position: 129 -+Last 80 unconsumed characters: -+ PUBLIC 'double quote " is invalid' "system-literal"> ]> -+ DETAIL -+ end -+ - def test_single_quote - doctype = parse(<<-INTERNAL_SUBSET) - -@@ -60,6 +165,21 @@ - end - - class TestSystemLiteral < self -+ def test_garbage_after_literal -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed notation declaration: garbage before end > -+Line: 5 -+Position: 123 -+Last 80 unconsumed characters: -+x'> ]> -+ DETAIL -+ end -+ - def test_single_quote - doctype = parse(<<-INTERNAL_SUBSET) - -@@ -96,5 +216,66 @@ - end - end - end -+ -+ class TestPublicID < self -+ def test_no_literal -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed notation declaration: public ID literal is missing -+Line: 5 -+Position: 84 -+Last 80 unconsumed characters: -+ PUBLIC> ]> -+ DETAIL -+ end -+ -+ def test_literal_content_double_quote -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed notation declaration: invalid public ID literal -+Line: 5 -+Position: 128 -+Last 80 unconsumed characters: -+ PUBLIC 'double quote \" is invalid in PubidLiteral'> ]> -+ DETAIL -+ end -+ -+ def test_garbage_after_literal -+ exception = assert_raise(REXML::ParseException) do -+ parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ end -+ assert_equal(<<-DETAIL.chomp, exception.to_s) -+Malformed notation declaration: garbage before end > -+Line: 5 -+Position: 106 -+Last 80 unconsumed characters: -+x'> ]> -+ DETAIL -+ end -+ -+ def test_literal_single_quote -+ doctype = parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ assert_equal("public-id-literal", doctype.notation("name").public) -+ end -+ -+ def test_literal_double_quote -+ doctype = parse(<<-INTERNAL_SUBSET) -+ -+ INTERNAL_SUBSET -+ assert_equal("public-id-literal", doctype.notation("name").public) -+ end -+ end - end - end -diff -Nur ruby-2.5.8/test/rexml/parser/test_tree.rb ruby-2.5.9/test/rexml/parser/test_tree.rb ---- ruby-2.5.8/test/rexml/parser/test_tree.rb 2020-03-31 12:15:56.000000000 +0000 -+++ ruby-2.5.9/test/rexml/parser/test_tree.rb 2021-04-05 11:46:35.000000000 +0000 -@@ -12,7 +12,7 @@ - parse(xml) - end - assert_equal(<<-MESSAGE, exception.to_s) --Missing end tag for 'root' (got "not-root") -+Missing end tag for 'root' (got 'not-root') - Line: 1 - Position: #{xml.bytesize} - Last 80 unconsumed characters: -diff -Nur ruby-2.5.8/test/rexml/parser/test_ultra_light.rb ruby-2.5.9/test/rexml/parser/test_ultra_light.rb ---- ruby-2.5.8/test/rexml/parser/test_ultra_light.rb 2020-03-31 12:15:56.000000000 +0000 -+++ ruby-2.5.9/test/rexml/parser/test_ultra_light.rb 2021-04-05 11:46:35.000000000 +0000 -@@ -16,7 +16,6 @@ - nil, - [:entitydecl, "name", "value"] - ], -- [:text, "\n"], - [:start_element, :parent, "root", {}], - [:text, "\n"], - ], -diff -Nur ruby-2.5.8/test/rexml/test_core.rb ruby-2.5.9/test/rexml/test_core.rb ---- ruby-2.5.8/test/rexml/test_core.rb 2020-03-31 12:15:56.000000000 +0000 -+++ ruby-2.5.9/test/rexml/test_core.rb 2021-04-05 11:46:35.000000000 +0000 -@@ -1,4 +1,4 @@ --# coding: binary -+# coding: utf-8 - # frozen_string_literal: false - - require_relative "rexml_test_utils" -@@ -995,7 +995,7 @@ - document.write(s) - - ## XML Doctype -- str = '' -+ str = '' - source = REXML::Source.new(str) - doctype = REXML::DocType.new(source) - document.add(doctype) -@@ -1274,14 +1274,15 @@ - - def test_ticket_21 - src = "" -- assert_raise( ParseException, "invalid XML should be caught" ) { -+ exception = assert_raise(ParseException) do - Document.new(src) -- } -- begin -- Document.new(src) -- rescue -- assert_match( /missing attribute quote/, $!.message ) - end -+ assert_equal(<<-DETAIL, exception.to_s) -+Missing attribute value start quote: -+Line: 1 -+Position: 16 -+Last 80 unconsumed characters: -+ DETAIL - end - - def test_ticket_63 -diff -Nur ruby-2.5.8/test/rexml/test_doctype.rb ruby-2.5.9/test/rexml/test_doctype.rb ---- ruby-2.5.8/test/rexml/test_doctype.rb 2020-03-31 12:15:56.000000000 +0000 -+++ ruby-2.5.9/test/rexml/test_doctype.rb 2021-04-05 11:46:35.000000000 +0000 -@@ -4,65 +4,111 @@ - - module REXMLTests - class TestDocTypeAccessor < Test::Unit::TestCase -- - def setup - @sysid = "urn:x-test:sysid1" -- @notid1 = "urn:x-test:notation1" -- @notid2 = "urn:x-test:notation2" -- document_string1 = <<-"XMLEND" -- -- -+ @notation_id1 = "urn:x-test:notation1" -+ @notation_id2 = "urn:x-test:notation2" -+ xml_system = <<-XML -+ -+ - ]> -- -- XMLEND -- @doctype1 = REXML::Document.new(document_string1).doctype -+ -+ XML -+ @doc_type_system = REXML::Document.new(xml_system).doctype - - @pubid = "TEST_ID" -- document_string2 = <<-"XMLEND" -- -- -- XMLEND -- @doctype2 = REXML::Document.new(document_string2).doctype -- -- document_string3 = <<-"XMLEND" -- -- -- XMLEND -- @doctype3 = REXML::Document.new(document_string3).doctype -- -+ xml_public_system = <<-XML -+ -+ -+ XML -+ @doc_type_public_system = REXML::Document.new(xml_public_system).doctype - end - - def test_public -- assert_equal(nil, @doctype1.public) -- assert_equal(@pubid, @doctype2.public) -- assert_equal(@pubid, @doctype3.public) -+ assert_equal([ -+ nil, -+ @pubid, -+ ], -+ [ -+ @doc_type_system.public, -+ @doc_type_public_system.public, -+ ]) -+ end -+ -+ def test_to_s -+ assert_equal("", -+ @doc_type_public_system.to_s) - end - - def test_system -- assert_equal(@sysid, @doctype1.system) -- assert_equal(nil, @doctype2.system) -- assert_equal(@sysid, @doctype3.system) -+ assert_equal([ -+ @sysid, -+ @sysid, -+ ], -+ [ -+ @doc_type_system.system, -+ @doc_type_public_system.system, -+ ]) - end - - def test_notation -- assert_equal(@notid1, @doctype1.notation("n1").system) -- assert_equal(@notid2, @doctype1.notation("n2").system) -+ assert_equal([ -+ @notation_id1, -+ @notation_id2, -+ ], -+ [ -+ @doc_type_system.notation("n1").system, -+ @doc_type_system.notation("n2").system, -+ ]) - end - - def test_notations -- notations = @doctype1.notations -- assert_equal(2, notations.length) -- assert_equal(@notid1, find_notation(notations, "n1").system) -- assert_equal(@notid2, find_notation(notations, "n2").system) -+ notations = @doc_type_system.notations -+ assert_equal([ -+ @notation_id1, -+ @notation_id2, -+ ], -+ notations.collect(&:system)) - end -+ end - -- def find_notation(notations, name) -- notations.find { |notation| -- name == notation.name -- } -+ class TestDocType < Test::Unit::TestCase -+ class TestExternalID < self -+ class TestSystem < self -+ class TestSystemLiteral < self -+ def test_to_s -+ doctype = REXML::DocType.new(["root", "SYSTEM", nil, "root.dtd"]) -+ assert_equal("", -+ doctype.to_s) -+ end -+ end -+ end -+ -+ class TestPublic < self -+ class TestPublicIDLiteral < self -+ def test_to_s -+ doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root.dtd"]) -+ assert_equal("", -+ doctype.to_s) -+ end -+ end -+ -+ class TestSystemLiteral < self -+ def test_to_s -+ doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root.dtd"]) -+ assert_equal("", -+ doctype.to_s) -+ end -+ -+ def test_to_s_double_quote -+ doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root\".dtd"]) -+ assert_equal("", -+ doctype.to_s) -+ end -+ end -+ end - end -- - end - - class TestNotationDeclPublic < Test::Unit::TestCase -@@ -77,11 +123,26 @@ - decl(@id, nil).to_s) - end - -+ def test_to_s_pubid_literal_include_apostrophe -+ assert_equal("", -+ decl("#{@id}'", nil).to_s) -+ end -+ - def test_to_s_with_uri - assert_equal("", - decl(@id, @uri).to_s) - end - -+ def test_to_s_system_literal_include_apostrophe -+ assert_equal("", -+ decl(@id, "system'literal").to_s) -+ end -+ -+ def test_to_s_system_literal_include_double_quote -+ assert_equal("", -+ decl(@id, "system\"literal").to_s) -+ end -+ - private - def decl(id, uri) - REXML::NotationDecl.new(@name, "PUBLIC", id, uri) -@@ -99,9 +160,19 @@ - decl(@id).to_s) - end - -+ def test_to_s_include_apostrophe -+ assert_equal("", -+ decl("#{@id}'").to_s) -+ end -+ -+ def test_to_s_include_double_quote -+ assert_equal("", -+ decl("#{@id}\"").to_s) -+ end -+ - private - def decl(id) -- REXML::NotationDecl.new(@name, "SYSTEM", id, nil) -+ REXML::NotationDecl.new(@name, "SYSTEM", nil, id) - end - end - end