summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/openssl/lib/openssl.rb1
-rw-r--r--ext/openssl/lib/openssl/config.rb411
-rw-r--r--ext/openssl/ossl_config.c453
-rw-r--r--ext/openssl/ossl_config.h11
-rw-r--r--test/openssl/test_config.rb10
5 files changed, 441 insertions, 445 deletions
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 <nahi@ruby-lang.org>
-
-= 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('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')
- # #=> #<OpenSSL::Config sections=["default"]>
- # 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
- # #=> #<OpenSSL::Config sections=[]>
- # 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)
- # #=> #<OpenSSL::Config sections=["default"]>
- # 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')
+ * #=> #<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"
+ */
+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')
+ * #=> #<OpenSSL::Config sections=["default"]>
+ * 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
+ * #=> #<OpenSSL::Config sections=[]>
+ * 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)
+ * #=> #<OpenSSL::Config sections=["default"]>
+ * 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