ruby-changes:65552
From: Kazuki <ko1@a...>
Date: Tue, 16 Mar 2021 20:38:37 +0900 (JST)
Subject: [ruby-changes:65552] 22aeb6373e (master): [ruby/openssl] config: revert to C implementation of OpenSSL::Config
https://git.ruby-lang.org/ruby.git/commit/?id=22aeb6373e From 22aeb6373e13929e80da1676b1dc79cbfffc38a4 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi <k@r...> Date: Wed, 19 Feb 2020 05:06:09 +0000 Subject: [ruby/openssl] config: revert to C implementation of OpenSSL::Config Revert OpenSSL::Config to using the OpenSSL API and remove our own parser implementation for the config file syntax. OpenSSL::Config now wraps a CONF object. Accessor methods deal with the object directly rather than Ruby-level internal state. This work is based on the old C code we used before 2010. https://github.com/ruby/openssl/commit/c891e0ea89 --- ext/openssl/lib/openssl.rb | 1 - ext/openssl/lib/openssl/config.rb | 411 ---------------------------------- ext/openssl/ossl_config.c | 453 ++++++++++++++++++++++++++++++++++++-- ext/openssl/ossl_config.h | 11 +- test/openssl/test_config.rb | 10 +- 5 files changed, 441 insertions(+), 445 deletions(-) delete mode 100644 ext/openssl/lib/openssl/config.rb diff --git a/ext/openssl/lib/openssl.rb b/ext/openssl/lib/openssl.rb index b047485..8a342f1 100644 --- a/ext/openssl/lib/openssl.rb +++ b/ext/openssl/lib/openssl.rb @@ -15,7 +15,6 @@ require 'openssl.so' https://github.com/ruby/ruby/blob/trunk/ext/openssl/lib/openssl.rb#L15 require_relative 'openssl/bn' require_relative 'openssl/pkey' require_relative 'openssl/cipher' -require_relative 'openssl/config' require_relative 'openssl/digest' require_relative 'openssl/hmac' require_relative 'openssl/x509' diff --git a/ext/openssl/lib/openssl/config.rb b/ext/openssl/lib/openssl/config.rb deleted file mode 100644 index 46e1711..0000000 --- a/ext/openssl/lib/openssl/config.rb +++ /dev/null @@ -1,411 +0,0 @@ https://github.com/ruby/ruby/blob/trunk/ext/openssl/lib/openssl.rb#L0 -# frozen_string_literal: true -=begin -= Ruby-space definitions that completes C-space funcs for Config - -= Info - Copyright (C) 2010 Hiroshi Nakamura <nahi@r...> - -= Licence - This program is licensed under the same licence as Ruby. - (See the file 'LICENCE'.) - -=end - -require 'stringio' - -module OpenSSL - ## - # = OpenSSL::Config - # - # Configuration for the openssl library. - # - # Many system's installation of openssl library will depend on your system - # configuration. See the value of OpenSSL::Config::DEFAULT_CONFIG_FILE for - # the location of the file for your host. - # - # See also http://www.openssl.org/docs/apps/config.html - class Config - include Enumerable - - class << self - - ## - # Parses a given _string_ as a blob that contains configuration for - # OpenSSL. - # - # If the source of the IO is a file, then consider using #parse_config. - def parse(string) - c = new() - parse_config(StringIO.new(string)).each do |section, hash| - c.set_section(section, hash) - end - c - end - - ## - # load is an alias to ::new - alias load new - - ## - # Parses the configuration data read from _io_, see also #parse. - # - # Raises a ConfigError on invalid configuration data. - def parse_config(io) - begin - parse_config_lines(io) - rescue => error - raise ConfigError, "error in line #{io.lineno}: " + error.message - end - end - - def get_key_string(data, section, key) # :nodoc: - if v = data[section] && data[section][key] - return v - elsif section == 'ENV' - if v = ENV[key] - return v - end - end - if v = data['default'] && data['default'][key] - return v - end - end - - private - - def parse_config_lines(io) - section = 'default' - data = {section => {}} - io_stack = [io] - while definition = get_definition(io_stack) - definition = clear_comments(definition) - next if definition.empty? - case definition - when /\A\[/ - if /\[([^\]]*)\]/ =~ definition - section = $1.strip - data[section] ||= {} - else - raise ConfigError, "missing close square bracket" - end - 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 - end - when /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ - if $2 - section = $1 - key = $2 - else - key = $1 - end - value = unescape_value(data, section, $3) - (data[section] ||= {})[key] = value.strip - else - raise ConfigError, "missing equal sign" - end - end - data - end - - # escape with backslash - QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/ - # escape with backslash and doubled dq - QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/ - # escaped char map - ESCAPE_MAP = { - "r" => "\r", - "n" => "\n", - "b" => "\b", - "t" => "\t", - } - - def unescape_value(data, section, value) - scanned = [] - while m = value.match(/['"\\$]/) - scanned << m.pre_match - c = m[0] - value = m.post_match - case c - when "'" - if m = value.match(QUOTE_REGEXP_SQ) - scanned << m[1].gsub(/\\(.)/, '\\1') - value = m.post_match - else - break - end - when '"' - if m = value.match(QUOTE_REGEXP_DQ) - scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1') - value = m.post_match - else - break - end - when "\\" - c = value.slice!(0, 1) - scanned << (ESCAPE_MAP[c] || c) - when "$" - ref, value = extract_reference(value) - refsec = section - if ref.index('::') - refsec, ref = ref.split('::', 2) - end - if v = get_key_string(data, refsec, ref) - scanned << v - else - raise ConfigError, "variable has no value" - end - else - raise 'must not reaced' - end - end - scanned << value - scanned.join - end - - def extract_reference(value) - rest = '' - if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/) - value = m[1] || m[2] - rest = m.post_match - elsif [?(, ?{].include?(value[0]) - raise ConfigError, "no close brace" - end - if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/) - return m[0], m.post_match + rest - else - raise - end - end - - def clear_comments(line) - # FCOMMENT - if m = line.match(/\A([\t\n\f ]*);.*\z/) - return m[1] - end - # COMMENT - scanned = [] - while m = line.match(/[#'"\\]/) - scanned << m.pre_match - c = m[0] - line = m.post_match - case c - when '#' - line = nil - break - when "'", '"' - regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ - scanned << c - if m = line.match(regexp) - scanned << m[0] - line = m.post_match - else - scanned << line - line = nil - break - end - when "\\" - scanned << c - scanned << line.slice!(0, 1) - else - raise 'must not reaced' - end - end - scanned << line - scanned.join - end - - def get_definition(io_stack) - if line = get_line(io_stack) - while /[^\\]\\\z/ =~ line - if extra = get_line(io_stack) - line += extra - else - break - end - end - return line.strip - end - end - - 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 - - ## - # Creates an instance of OpenSSL's configuration class. - # - # This can be used in contexts like OpenSSL::X509::ExtensionFactory.config= - # - # If the optional _filename_ parameter is provided, then it is read in and - # parsed via #parse_config. - # - # This can raise IO exceptions based on the access, or availability of the - # file. A ConfigError exception may be raised depending on the validity of - # the data being configured. - # - def initialize(filename = nil) - @data = {} - if filename - File.open(filename.to_s) do |file| - Config.parse_config(file).each do |section, hash| - set_section(section, hash) - end - end - end - end - - ## - # Gets the value of _key_ from the given _section_ - # - # Given the following configurating file being loaded: - # - # config = OpenSSL::Config.load('foo.cnf') - # #=> #<OpenSSL::Config sections=["default"]> - # puts config.to_s - # #=> [ default ] - # # foo=bar - # - # You can get a specific value from the config if you know the _section_ - # and _key_ like so: - # - # config.get_value('default','foo') - # #=> "bar" - # - def get_value(section, key) - if section.nil? - raise TypeError.new( (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/