From 22aeb6373e13929e80da1676b1dc79cbfffc38a4 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi 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 b047485785..8a342f15b6 100644 --- a/ext/openssl/lib/openssl.rb +++ b/ext/openssl/lib/openssl.rb @@ -15,7 +15,6 @@ require 'openssl.so' 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 46e1711d28..0000000000 --- a/ext/openssl/lib/openssl/config.rb +++ /dev/null @@ -1,411 +0,0 @@ -# frozen_string_literal: true -=begin -= Ruby-space definitions that completes C-space funcs for Config - -= Info - Copyright (C) 2010 Hiroshi Nakamura - -= 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') - # #=> # - # 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('nil not allowed') - end - section = 'default' if section.empty? - get_key_string(section, key) - end - - ## - # Get a specific _section_ from the current configuration - # - # Given the following configurating file being loaded: - # - # config = OpenSSL::Config.load('foo.cnf') - # #=> # - # puts config.to_s - # #=> [ default ] - # # foo=bar - # - # You can get a hash of the specific section like so: - # - # config['default'] - # #=> {"foo"=>"bar"} - # - def [](section) - @data[section] || {} - end - - def set_section(section, pairs) # :nodoc: - hash = @data[section] ||= {} - pairs.each do |key, value| - hash[key] = value - end - end - - ## - # Get the names of all sections in the current configuration - def sections - @data.keys - end - - ## - # Get the parsable form of the current configuration - # - # Given the following configuration being created: - # - # config = OpenSSL::Config.new - # #=> # - # config['default'] = {"foo"=>"bar","baz"=>"buz"} - # #=> {"foo"=>"bar", "baz"=>"buz"} - # puts config.to_s - # #=> [ default ] - # # foo=bar - # # baz=buz - # - # You can parse get the serialized configuration using #to_s and then parse - # it later: - # - # serialized_config = config.to_s - # # much later... - # new_config = OpenSSL::Config.parse(serialized_config) - # #=> # - # puts new_config - # #=> [ default ] - # foo=bar - # baz=buz - # - def to_s - ary = [] - @data.keys.sort.each do |section| - ary << "[ #{section} ]\n" - @data[section].keys.each do |key| - ary << "#{key}=#{@data[section][key]}\n" - end - ary << "\n" - end - ary.join - end - - ## - # For a block. - # - # Receive the section and its pairs for the current configuration. - # - # config.each do |section, key, value| - # # ... - # end - # - def each - @data.each do |section, hash| - hash.each do |key, value| - yield [section, key, value] - end - end - end - - ## - # String representation of this configuration object, including the class - # name and its sections. - def inspect - "#<#{self.class.name} sections=#{sections.inspect}>" - end - - protected - - def data # :nodoc: - @data - end - - private - - def initialize_copy(other) - @data = other.data.dup - end - - def get_key_string(section, key) - Config.get_key_string(@data, section, key) - end - end -end diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c index 28392e208c..52d96e1ed1 100644 --- a/ext/openssl/ossl_config.c +++ b/ext/openssl/ossl_config.c @@ -9,21 +9,46 @@ */ #include "ossl.h" +static VALUE cConfig, eConfigError; -/* - * Classes - */ -VALUE cConfig; -/* Document-class: OpenSSL::ConfigError - * - * General error for openssl library configuration files. Including formatting, - * parsing errors, etc. - */ -VALUE eConfigError; +static void +nconf_free(void *conf) +{ + NCONF_free(conf); +} -/* - * Public - */ +static const rb_data_type_t ossl_config_type = { + "OpenSSL/CONF", + { + 0, nconf_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + +static CONF * +GetConfig(VALUE obj) +{ + CONF *conf; + + TypedData_Get_Struct(obj, CONF, &ossl_config_type, conf); + if (!conf) + rb_raise(rb_eRuntimeError, "CONF is not initialized"); + return conf; +} + +static VALUE +config_s_alloc(VALUE klass) +{ + VALUE obj; + CONF *conf; + + obj = TypedData_Wrap_Struct(klass, &ossl_config_type, 0); + conf = NCONF_new(NULL); + if (!conf) + ossl_raise(eConfigError, "NCONF_new"); + RTYPEDDATA_DATA(obj) = conf; + return obj; +} /* * DupConfigPtr is a public C-level function for getting OpenSSL CONF struct @@ -60,30 +85,412 @@ DupConfigPtr(VALUE obj) return conf; } -/* Document-const: DEFAULT_CONFIG_FILE + +static void +config_load_bio(CONF *conf, BIO *bio) +{ + long eline = -1; + + if (!NCONF_load_bio(conf, bio, &eline)) { + BIO_free(bio); + if (eline <= 0) + ossl_raise(eConfigError, "wrong config format"); + else + ossl_raise(eConfigError, "error in line %d", eline); + } + BIO_free(bio); + + /* + * Clear the error queue even if it is parsed successfully. + * Particularly, when the .include directive refers to a non-existent file, + * it is only reported in the error queue. + */ + ossl_clear_error(); +} + +/* + * call-seq: + * Config.parse(string) -> OpenSSL::Config + * + * Parses a given _string_ as a blob that contains configuration for OpenSSL. + */ +static VALUE +config_s_parse(VALUE klass, VALUE str) +{ + VALUE obj = config_s_alloc(klass); + CONF *conf = GetConfig(obj); + BIO *bio; + + bio = ossl_obj2bio(&str); + config_load_bio(conf, bio); /* Consumes BIO */ + return obj; +} + +static VALUE config_get_sections(VALUE self); +static VALUE config_get_section(VALUE self, VALUE section); + +/* + * call-seq: + * Config.parse_config(io) -> hash + * + * Parses the configuration data read from _io_ and returns the whole content + * as a Hash. + */ +static VALUE +config_s_parse_config(VALUE klass, VALUE io) +{ + VALUE obj, sections, ret; + long i; + + obj = config_s_parse(klass, io); + sections = config_get_sections(obj); + ret = rb_hash_new(); + for (i = 0; i < RARRAY_LEN(sections); i++) { + VALUE section = rb_ary_entry(sections, i); + rb_hash_aset(ret, section, config_get_section(obj, section)); + } + return ret; +} + +/* + * call-seq: + * Config.new(filename) -> OpenSSL::Config + * + * Creates an instance of OpenSSL::Config from the content of the file + * specified by _filename_. + * + * This can be used in contexts like OpenSSL::X509::ExtensionFactory.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. + */ +static VALUE +config_initialize(int argc, VALUE *argv, VALUE self) +{ + CONF *conf = GetConfig(self); + VALUE filename; + + /* 0-arguments call has no use-case, but is kept for compatibility */ + rb_scan_args(argc, argv, "01", &filename); + rb_check_frozen(self); + if (!NIL_P(filename)) { + BIO *bio = BIO_new_file(StringValueCStr(filename), "rb"); + if (!bio) + ossl_raise(eConfigError, "BIO_new_file"); + config_load_bio(conf, bio); /* Consumes BIO */ + } + return self; +} + +static VALUE +config_initialize_copy(VALUE self, VALUE other) +{ + CONF *conf = GetConfig(self); + VALUE str; + BIO *bio; + + str = rb_funcall(other, rb_intern("to_s"), 0); + rb_check_frozen(self); + bio = ossl_obj2bio(&str); + config_load_bio(conf, bio); /* Consumes BIO */ + return self; +} + +/* + * call-seq: + * config.get_value(section, key) -> string + * + * Gets the value of _key_ from the given _section_. + * + * Given the following configurating file being loaded: + * + * config = OpenSSL::Config.load('foo.cnf') + * #=> # + * 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" + */ +static VALUE +config_get_value(VALUE self, VALUE section, VALUE key) +{ + CONF *conf = GetConfig(self); + const char *str, *sectionp; + + StringValueCStr(section); + StringValueCStr(key); + /* For compatibility; NULL means "default". */ + sectionp = RSTRING_LEN(section) ? RSTRING_PTR(section) : NULL; + str = NCONF_get_string(conf, sectionp, RSTRING_PTR(key)); + if (!str) { + ossl_clear_error(); + return Qnil; + } + return rb_str_new_cstr(str); +} + +/* + * call-seq: + * config[section] -> hash + * + * Gets all key-value pairs in a specific _section_ from the current + * configuration. + * + * Given the following configurating file being loaded: + * + * config = OpenSSL::Config.load('foo.cnf') + * #=> # + * puts config.to_s + * #=> [ default ] + * # foo=bar + * + * You can get a hash of the specific section like so: + * + * config['default'] + * #=> {"foo"=>"bar"} * - * The default system configuration file for openssl */ +static VALUE +config_get_section(VALUE self, VALUE section) +{ + CONF *conf = GetConfig(self); + STACK_OF(CONF_VALUE) *sk; + int i, entries; + VALUE hash; + + hash = rb_hash_new(); + StringValueCStr(section); + if (!(sk = NCONF_get_section(conf, RSTRING_PTR(section)))) { + ossl_clear_error(); + return hash; + } + entries = sk_CONF_VALUE_num(sk); + for (i = 0; i < entries; i++) { + CONF_VALUE *entry = sk_CONF_VALUE_value(sk, i); + rb_hash_aset(hash, rb_str_new_cstr(entry->name), + rb_str_new_cstr(entry->value)); + } + return hash; +} + +static void +get_conf_section_doall_arg(CONF_VALUE *cv, VALUE *aryp) +{ + if (cv->name) + return; + rb_ary_push(*aryp, rb_str_new_cstr(cv->section)); +} + +/* IMPLEMENT_LHASH_DOALL_ARG_CONST() requires >= OpenSSL 1.1.0 */ +static IMPLEMENT_LHASH_DOALL_ARG_FN(get_conf_section, CONF_VALUE, VALUE) /* - * INIT + * call-seq: + * config.sections -> array of string + * + * Get the names of all sections in the current configuration. */ +static VALUE +config_get_sections(VALUE self) +{ + CONF *conf = GetConfig(self); + VALUE ary; + + ary = rb_ary_new(); + lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(get_conf_section), + &ary); + return ary; +} + +static void +dump_conf_value_doall_arg(CONF_VALUE *cv, VALUE *strp) +{ + VALUE str = *strp; + STACK_OF(CONF_VALUE) *sk; + int i, num; + + if (cv->name) + return; + sk = (STACK_OF(CONF_VALUE) *)cv->value; + num = sk_CONF_VALUE_num(sk); + rb_str_cat_cstr(str, "[ "); + rb_str_cat_cstr(str, cv->section); + rb_str_cat_cstr(str, " ]\n"); + for (i = 0; i < num; i++){ + CONF_VALUE *v = sk_CONF_VALUE_value(sk, i); + rb_str_cat_cstr(str, v->name ? v->name : "None"); + rb_str_cat_cstr(str, "="); + rb_str_cat_cstr(str, v->value ? v->value : "None"); + rb_str_cat_cstr(str, "\n"); + } + rb_str_cat_cstr(str, "\n"); +} + +static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_conf_value, CONF_VALUE, VALUE) + +/* + * call-seq: + * config.to_s -> string + * + * + * Gets the parsable form of the current configuration. + * + * Given the following configuration being created: + * + * config = OpenSSL::Config.new + * #=> # + * config['default'] = {"foo"=>"bar","baz"=>"buz"} + * #=> {"foo"=>"bar", "baz"=>"buz"} + * puts config.to_s + * #=> [ default ] + * # foo=bar + * # baz=buz + * + * You can parse get the serialized configuration using #to_s and then parse + * it later: + * + * serialized_config = config.to_s + * # much later... + * new_config = OpenSSL::Config.parse(serialized_config) + * #=> # + * puts new_config + * #=> [ default ] + * foo=bar + * baz=buz + */ +static VALUE +config_to_s(VALUE self) +{ + CONF *conf = GetConfig(self); + VALUE str; + + str = rb_str_new(NULL, 0); + lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(dump_conf_value), + &str); + return str; +} + +static void +each_conf_value_doall_arg(CONF_VALUE *cv, void *unused) +{ + STACK_OF(CONF_VALUE) *sk; + VALUE section; + int i, num; + + if (cv->name) + return; + sk = (STACK_OF(CONF_VALUE) *)cv->value; + num = sk_CONF_VALUE_num(sk); + section = rb_str_new_cstr(cv->section); + for (i = 0; i < num; i++){ + CONF_VALUE *v = sk_CONF_VALUE_value(sk, i); + VALUE name = v->name ? rb_str_new_cstr(v->name) : Qnil; + VALUE value = v->value ? rb_str_new_cstr(v->value) : Qnil; + rb_yield(rb_ary_new3(3, section, name, value)); + } +} + +static IMPLEMENT_LHASH_DOALL_ARG_FN(each_conf_value, CONF_VALUE, void) + +/* + * call-seq: + * config.each { |section, key, value| } + * + * Retrieves the section and its pairs for the current configuration. + * + * config.each do |section, key, value| + * # ... + * end + */ +static VALUE +config_each(VALUE self) +{ + CONF *conf = GetConfig(self); + + RETURN_ENUMERATOR(self, 0, 0); + + lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(each_conf_value), + NULL); + return self; +} + +/* + * call-seq: + * config.inspect -> string + * + * String representation of this configuration object, including the class + * name and its sections. + */ +static VALUE +config_inspect(VALUE self) +{ + VALUE str, ary = config_get_sections(self); + const char *cname = rb_class2name(rb_obj_class(self)); + + str = rb_str_new_cstr("#<"); + rb_str_cat_cstr(str, cname); + rb_str_cat_cstr(str, " sections="); + rb_str_append(str, rb_inspect(ary)); + rb_str_cat_cstr(str, ">"); + + return str; +} + void Init_ossl_config(void) { - char *default_config_file; + char *path; + VALUE path_str; #if 0 mOSSL = rb_define_module("OpenSSL"); eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); #endif - eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError); + /* Document-class: 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 + */ cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject); - default_config_file = CONF_get1_default_config_file(); - rb_define_const(cConfig, "DEFAULT_CONFIG_FILE", - rb_str_new2(default_config_file)); - OPENSSL_free(default_config_file); - /* methods are defined by openssl/config.rb */ + /* Document-class: OpenSSL::ConfigError + * + * General error for openssl library configuration files. Including formatting, + * parsing errors, etc. + */ + eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError); + + rb_include_module(cConfig, rb_mEnumerable); + rb_define_singleton_method(cConfig, "parse", config_s_parse, 1); + rb_define_singleton_method(cConfig, "parse_config", config_s_parse_config, 1); + rb_define_alias(CLASS_OF(cConfig), "load", "new"); + rb_define_alloc_func(cConfig, config_s_alloc); + rb_define_method(cConfig, "initialize", config_initialize, -1); + rb_define_method(cConfig, "initialize_copy", config_initialize_copy, 1); + rb_define_method(cConfig, "get_value", config_get_value, 2); + rb_define_method(cConfig, "[]", config_get_section, 1); + rb_define_method(cConfig, "sections", config_get_sections, 0); + rb_define_method(cConfig, "to_s", config_to_s, 0); + rb_define_method(cConfig, "each", config_each, 0); + rb_define_method(cConfig, "inspect", config_inspect, 0); + + /* Document-const: DEFAULT_CONFIG_FILE + * + * The default system configuration file for OpenSSL. + */ + path = CONF_get1_default_config_file(); + path_str = ossl_buf2str(path, rb_long2int(strlen(path))); + rb_define_const(cConfig, "DEFAULT_CONFIG_FILE", path_str); } diff --git a/ext/openssl/ossl_config.h b/ext/openssl/ossl_config.h index 627d297ba3..c96a00f70b 100644 --- a/ext/openssl/ossl_config.h +++ b/ext/openssl/ossl_config.h @@ -7,13 +7,10 @@ * This program is licensed under the same licence as Ruby. * (See the file 'LICENCE'.) */ -#if !defined(_OSSL_CONFIG_H_) -#define _OSSL_CONFIG_H_ +#ifndef OSSL_CONFIG_H +#define OSSL_CONFIG_H -extern VALUE cConfig; -extern VALUE eConfigError; - -CONF* DupConfigPtr(VALUE obj); +CONF *DupConfigPtr(VALUE obj); void Init_ossl_config(void); -#endif /* _OSSL_CONFIG_H_ */ +#endif /* OSSL_CONFIG_H */ diff --git a/test/openssl/test_config.rb b/test/openssl/test_config.rb index 01be28164a..3af9923d2a 100644 --- a/test/openssl/test_config.rb +++ b/test/openssl/test_config.rb @@ -150,6 +150,10 @@ __EOC__ # Include a file by relative path c1 = OpenSSL::Config.parse(include_file) + if c1["sec-main"][".include"] + # OpenSSL < 1.1.1 parses '.include =' as a normal assignment + pend ".include directive is not supported" + end assert_equal(["default", "sec-a", "sec-b", "sec-main"], c1.sections.sort) assert_equal(["file-a", "file-b", "file-main"], c1["default"].keys.sort) assert_equal({"a" => "123"}, c1["sec-a"]) @@ -157,9 +161,9 @@ __EOC__ 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 + # Inclusion fails, but the error is ignored silently + c2 = Dir.chdir("child") { OpenSSL::Config.parse(include_file) } + assert_equal(["default", "sec-main"], c2.sections.sort) end end -- cgit v1.2.3