aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2020-07-11 16:10:41 +0900
committernagachika <nagachika@ruby-lang.org>2020-07-11 16:10:41 +0900
commitb4c893a62c71ac28795f8fcefb375131833afd0c (patch)
treeb8b7bcc53638ee75f8123fbec4c57e1e11cdc1cf
parenta0bb4eb04512b3f8ca50ec5fa72e3d4a8278ca46 (diff)
downloadruby-b4c893a62c71ac28795f8fcefb375131833afd0c.tar.gz
OpenSSL 1.1.1 introduces a new '.include' directive. Update our config
parser to support that. As mentioned in the referenced GitHub issue, we should use the OpenSSL API instead of implementing the parsing logic ourselves, but it will need backwards-incompatible changes which we can't backport to stable versions. So continue to use the Ruby implementation for now. References: https://github.com/ruby/openssl/issues/208 https://github.com/ruby/openssl/pull/216 The original patch was written by Kazuki Yamaguchi <k@rhe.jp> and the patch for ruby_2_7 branch was prepared by Vít Ondruch.
-rw-r--r--ext/openssl/lib/openssl/config.rb54
-rw-r--r--test/openssl/test_config.rb54
-rw-r--r--version.h4
3 files changed, 92 insertions, 20 deletions
diff --git a/ext/openssl/lib/openssl/config.rb b/ext/openssl/lib/openssl/config.rb
index 48d8be0069..78a2da9eb9 100644
--- a/ext/openssl/lib/openssl/config.rb
+++ b/ext/openssl/lib/openssl/config.rb
@@ -77,29 +77,44 @@ module OpenSSL
def parse_config_lines(io)
section = 'default'
data = {section => {}}
- while definition = get_definition(io)
+ io_stack = [io]
+ while definition = get_definition(io_stack)
definition = clear_comments(definition)
next if definition.empty?
- if definition[0] == ?[
+ case definition
+ when /\A\[/
if /\[([^\]]*)\]/ =~ definition
section = $1.strip
data[section] ||= {}
else
raise ConfigError, "missing close square bracket"
end
- else
- if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
- if $2
- section = $1
- key = $2
- else
- key = $1
+ when /\A\.include (\s*=\s*)?(.+)\z/
+ path = $2
+ if File.directory?(path)
+ files = Dir.glob(File.join(path, "*.{cnf,conf}"), File::FNM_EXTGLOB)
+ else
+ files = [path]
+ end
+
+ files.each do |filename|
+ begin
+ io_stack << StringIO.new(File.read(filename))
+ rescue
+ raise ConfigError, "could not include file '%s'" % filename
end
- value = unescape_value(data, section, $3)
- (data[section] ||= {})[key] = value.strip
+ end
+ when /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/
+ if $2
+ section = $1
+ key = $2
else
- raise ConfigError, "missing equal sign"
+ key = $1
end
+ value = unescape_value(data, section, $3)
+ (data[section] ||= {})[key] = value.strip
+ else
+ raise ConfigError, "missing equal sign"
end
end
data
@@ -212,10 +227,10 @@ module OpenSSL
scanned.join
end
- def get_definition(io)
- if line = get_line(io)
+ def get_definition(io_stack)
+ if line = get_line(io_stack)
while /[^\\]\\\z/ =~ line
- if extra = get_line(io)
+ if extra = get_line(io_stack)
line += extra
else
break
@@ -225,9 +240,12 @@ module OpenSSL
end
end
- def get_line(io)
- if line = io.gets
- line.gsub(/[\r\n]*/, '')
+ def get_line(io_stack)
+ while io = io_stack.last
+ if line = io.gets
+ return line.gsub(/[\r\n]*/, '')
+ end
+ io_stack.pop
end
end
end
diff --git a/test/openssl/test_config.rb b/test/openssl/test_config.rb
index 3606c67d65..c1a01d4dbe 100644
--- a/test/openssl/test_config.rb
+++ b/test/openssl/test_config.rb
@@ -120,6 +120,49 @@ __EOC__
assert_equal("error in line 7: missing close square bracket", excn.message)
end
+ def test_s_parse_include
+ in_tmpdir("ossl-config-include-test") do |dir|
+ Dir.mkdir("child")
+ File.write("child/a.conf", <<~__EOC__)
+ [default]
+ file-a = a.conf
+ [sec-a]
+ a = 123
+ __EOC__
+ File.write("child/b.cnf", <<~__EOC__)
+ [default]
+ file-b = b.cnf
+ [sec-b]
+ b = 123
+ __EOC__
+ File.write("include-child.conf", <<~__EOC__)
+ key_outside_section = value_a
+ .include child
+ __EOC__
+
+ include_file = <<~__EOC__
+ [default]
+ file-main = unnamed
+ [sec-main]
+ main = 123
+ .include = include-child.conf
+ __EOC__
+
+ # Include a file by relative path
+ c1 = OpenSSL::Config.parse(include_file)
+ assert_equal(["default", "sec-a", "sec-b", "sec-main"], c1.sections.sort)
+ assert_equal(["file-main", "file-a", "file-b"], c1["default"].keys)
+ assert_equal({"a" => "123"}, c1["sec-a"])
+ assert_equal({"b" => "123"}, c1["sec-b"])
+ assert_equal({"main" => "123", "key_outside_section" => "value_a"}, c1["sec-main"])
+
+ # Relative paths are from the working directory
+ assert_raise(OpenSSL::ConfigError) do
+ Dir.chdir("child") { OpenSSL::Config.parse(include_file) }
+ end
+ end
+ end
+
def test_s_load
# alias of new
c = OpenSSL::Config.load
@@ -299,6 +342,17 @@ __EOC__
@it['newsection'] = {'a' => 'b'}
assert_not_equal(@it.sections.sort, c.sections.sort)
end
+
+ private
+
+ def in_tmpdir(*args)
+ Dir.mktmpdir(*args) do |dir|
+ dir = File.realpath(dir)
+ Dir.chdir(dir) do
+ yield dir
+ end
+ end
+ end
end
end
diff --git a/version.h b/version.h
index 870e9bed1b..01ec32bb13 100644
--- a/version.h
+++ b/version.h
@@ -2,11 +2,11 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 1
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
-#define RUBY_PATCHLEVEL 91
+#define RUBY_PATCHLEVEL 92
#define RUBY_RELEASE_YEAR 2020
#define RUBY_RELEASE_MONTH 7
-#define RUBY_RELEASE_DAY 10
+#define RUBY_RELEASE_DAY 11
#include "ruby/version.h"