jruby-openssl 0.7.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,19 @@
1
+ == 0.7.2
2
+
3
+ - JRUBY-5126: Ignore Cipher#reset and Cipher#iv= when it's a stream
4
+ cipher (Net::SSH compatibility)
5
+ - JRUBY-5125: let Cipher#name for 'rc4' to be 'RC4' (Net::SSH
6
+ compatibility)
7
+ - JRUBY-5096: Fixed inconsistent Certificate verification behavior
8
+ - JRUBY-5060: Avoid NPE from to_pem for empty X509 Objects
9
+ - JRUBY-5059: SSLSocket ignores Timeout (Fixed)
10
+ - JRUBY-4965: implemented OpenSSL::Config
11
+ - JRUBY-5023: make Certificate#signature_algorithm return correct algo
12
+ name; "sha1WithRSAEncryption" instead of "SHA1"
13
+ - JRUBY-5024: let HMAC.new accept a String as a digest name
14
+ - JRUBY-5018: SSLSocket holds selectors, keys, preventing quick
15
+ cleanup of resources when dereferenced
16
+
1
17
  == 0.7.1
2
18
 
3
19
  - NOTE: Now BouncyCastle jars has moved out to its own gem
@@ -12,6 +12,7 @@ lib/jopenssl/version.rb
12
12
  lib/openssl/bn.rb
13
13
  lib/openssl/buffering.rb
14
14
  lib/openssl/cipher.rb
15
+ lib/openssl/config.rb
15
16
  lib/openssl/digest.rb
16
17
  lib/openssl/dummy.rb
17
18
  lib/openssl/dummyssl.rb
@@ -86,6 +87,7 @@ test/java/test_java_smime.rb
86
87
  test/openssl/ssl_server.rb
87
88
  test/openssl/test_asn1.rb
88
89
  test/openssl/test_cipher.rb
90
+ test/openssl/test_config.rb
89
91
  test/openssl/test_digest.rb
90
92
  test/openssl/test_ec.rb
91
93
  test/openssl/test_hmac.rb
data/Rakefile CHANGED
@@ -53,6 +53,7 @@ require File.dirname(__FILE__) + "/lib/jopenssl/version"
53
53
  begin
54
54
  require 'hoe'
55
55
  Hoe.plugin :gemcutter
56
+ Hoe.add_include_dirs('build_lib')
56
57
  hoe = Hoe.spec("jruby-openssl") do |p|
57
58
  p.version = Jopenssl::Version::VERSION
58
59
  p.rubyforge_name = "jruby-extras"
Binary file
@@ -1,5 +1,5 @@
1
1
  module Jopenssl
2
2
  module Version
3
- VERSION = "0.7.1"
3
+ VERSION = "0.7.2"
4
4
  end
5
5
  end
@@ -68,6 +68,7 @@ require 'jopenssl'
68
68
 
69
69
  require 'openssl/bn'
70
70
  require 'openssl/cipher'
71
+ require 'openssl/config'
71
72
  require 'openssl/digest'
72
73
  require 'openssl/pkcs7'
73
74
  require 'openssl/ssl'
@@ -0,0 +1,316 @@
1
+ =begin
2
+ = Ruby-space definitions that completes C-space funcs for Config
3
+
4
+ = Info
5
+ Copyright (C) 2010 Hiroshi Nakamura <nahi@ruby-lang.org>
6
+
7
+ = Licence
8
+ This program is licenced under the same licence as Ruby.
9
+ (See the file 'LICENCE'.)
10
+
11
+ =end
12
+
13
+ ##
14
+ # Should we care what if somebody require this file directly?
15
+ #require 'openssl'
16
+ require 'stringio'
17
+
18
+ module OpenSSL
19
+ class Config
20
+ include Enumerable
21
+
22
+ class << self
23
+ def parse(str)
24
+ c = new()
25
+ parse_config(StringIO.new(str)).each do |section, hash|
26
+ c[section] = hash
27
+ end
28
+ c
29
+ end
30
+
31
+ alias load new
32
+
33
+ def parse_config(io)
34
+ begin
35
+ parse_config_lines(io)
36
+ rescue ConfigError => e
37
+ e.message.replace("error in line #{io.lineno}: " + e.message)
38
+ raise
39
+ end
40
+ end
41
+
42
+ def get_key_string(data, section, key) # :nodoc:
43
+ if v = data[section] && data[section][key]
44
+ return v
45
+ elsif section == 'ENV'
46
+ if v = ENV[key]
47
+ return v
48
+ end
49
+ end
50
+ if v = data['default'] && data['default'][key]
51
+ return v
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def parse_config_lines(io)
58
+ section = 'default'
59
+ data = {section => {}}
60
+ while definition = get_definition(io)
61
+ definition = clear_comments(definition)
62
+ next if definition.empty?
63
+ if definition[0] == ?[
64
+ if /\[([^\]]*)\]/ =~ definition
65
+ section = $1.strip
66
+ data[section] ||= {}
67
+ else
68
+ raise ConfigError, "missing close square bracket"
69
+ end
70
+ else
71
+ if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
72
+ if $2
73
+ section = $1
74
+ key = $2
75
+ else
76
+ key = $1
77
+ end
78
+ value = unescape_value(data, section, $3)
79
+ (data[section] ||= {})[key] = value.strip
80
+ else
81
+ raise ConfigError, "missing equal sign"
82
+ end
83
+ end
84
+ end
85
+ data
86
+ end
87
+
88
+ # escape with backslash
89
+ QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/
90
+ # escape with backslash and doubled dq
91
+ QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/
92
+ # escaped char map
93
+ ESCAPE_MAP = {
94
+ "r" => "\r",
95
+ "n" => "\n",
96
+ "b" => "\b",
97
+ "t" => "\t",
98
+ }
99
+
100
+ def unescape_value(data, section, value)
101
+ scanned = []
102
+ while m = value.match(/['"\\$]/)
103
+ scanned << m.pre_match
104
+ c = m[0]
105
+ value = m.post_match
106
+ case c
107
+ when "'"
108
+ if m = value.match(QUOTE_REGEXP_SQ)
109
+ scanned << m[1].gsub(/\\(.)/, '\\1')
110
+ value = m.post_match
111
+ else
112
+ break
113
+ end
114
+ when '"'
115
+ if m = value.match(QUOTE_REGEXP_DQ)
116
+ scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1')
117
+ value = m.post_match
118
+ else
119
+ break
120
+ end
121
+ when "\\"
122
+ c = value.slice!(0, 1)
123
+ scanned << (ESCAPE_MAP[c] || c)
124
+ when "$"
125
+ ref, value = extract_reference(value)
126
+ refsec = section
127
+ if ref.index('::')
128
+ refsec, ref = ref.split('::', 2)
129
+ end
130
+ if v = get_key_string(data, refsec, ref)
131
+ scanned << v
132
+ else
133
+ raise ConfigError, "variable has no value"
134
+ end
135
+ else
136
+ raise 'must not reaced'
137
+ end
138
+ end
139
+ scanned << value
140
+ scanned.join
141
+ end
142
+
143
+ def extract_reference(value)
144
+ rest = ''
145
+ if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/)
146
+ value = m[1] || m[2]
147
+ rest = m.post_match
148
+ elsif [?(, ?{].include?(value[0])
149
+ raise ConfigError, "no close brace"
150
+ end
151
+ if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/)
152
+ return m[0], m.post_match + rest
153
+ else
154
+ raise
155
+ end
156
+ end
157
+
158
+ def clear_comments(line)
159
+ # FCOMMENT
160
+ if m = line.match(/\A([\t\n\f ]*);.*\z/)
161
+ return m[1]
162
+ end
163
+ # COMMENT
164
+ scanned = []
165
+ while m = line.match(/[#'"\\]/)
166
+ scanned << m.pre_match
167
+ c = m[0]
168
+ line = m.post_match
169
+ case c
170
+ when '#'
171
+ line = nil
172
+ break
173
+ when "'", '"'
174
+ regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ
175
+ scanned << c
176
+ if m = line.match(regexp)
177
+ scanned << m[0]
178
+ line = m.post_match
179
+ else
180
+ scanned << line
181
+ line = nil
182
+ break
183
+ end
184
+ when "\\"
185
+ scanned << c
186
+ scanned << line.slice!(0, 1)
187
+ else
188
+ raise 'must not reaced'
189
+ end
190
+ end
191
+ scanned << line
192
+ scanned.join
193
+ end
194
+
195
+ def get_definition(io)
196
+ if line = get_line(io)
197
+ while /[^\\]\\\z/ =~ line
198
+ if extra = get_line(io)
199
+ line += extra
200
+ else
201
+ break
202
+ end
203
+ end
204
+ return line.strip
205
+ end
206
+ end
207
+
208
+ def get_line(io)
209
+ if line = io.gets
210
+ line.gsub(/[\r\n]*/, '')
211
+ end
212
+ end
213
+ end
214
+
215
+ def initialize(filename = nil)
216
+ @data = {}
217
+ if filename
218
+ File.open(filename.to_s) do |file|
219
+ Config.parse_config(file).each do |section, hash|
220
+ self[section] = hash
221
+ end
222
+ end
223
+ end
224
+ end
225
+
226
+ def get_value(section, key)
227
+ if section.nil?
228
+ raise TypeError.new('nil not allowed')
229
+ end
230
+ section = 'default' if section.empty?
231
+ get_key_string(section, key)
232
+ end
233
+
234
+ def value(arg1, arg2 = nil)
235
+ warn('Config#value is deprecated; use Config#get_value')
236
+ if arg2.nil?
237
+ section, key = 'default', arg1
238
+ else
239
+ section, key = arg1, arg2
240
+ end
241
+ section ||= 'default'
242
+ section = 'default' if section.empty?
243
+ get_key_string(section, key)
244
+ end
245
+
246
+ def add_value(section, key, value)
247
+ check_modify
248
+ (@data[section] ||= {})[key] = value
249
+ end
250
+
251
+ def [](section)
252
+ @data[section] || {}
253
+ end
254
+
255
+ def section(name)
256
+ warn('Config#section is deprecated; use Config#[]')
257
+ @data[name] || {}
258
+ end
259
+
260
+ def []=(section, pairs)
261
+ check_modify
262
+ @data[section] ||= {}
263
+ pairs.each do |key, value|
264
+ self.add_value(section, key, value)
265
+ end
266
+ end
267
+
268
+ def sections
269
+ @data.keys
270
+ end
271
+
272
+ def to_s
273
+ ary = []
274
+ @data.keys.sort.each do |section|
275
+ ary << "[ #{section} ]\n"
276
+ @data[section].keys.each do |key|
277
+ ary << "#{key}=#{@data[section][key]}\n"
278
+ end
279
+ ary << "\n"
280
+ end
281
+ ary.join
282
+ end
283
+
284
+ def each
285
+ @data.each do |section, hash|
286
+ hash.each do |key, value|
287
+ yield [section, key, value]
288
+ end
289
+ end
290
+ end
291
+
292
+ def inspect
293
+ "#<#{self.class.name} sections=#{sections.inspect}>"
294
+ end
295
+
296
+ protected
297
+
298
+ def data
299
+ @data
300
+ end
301
+
302
+ private
303
+
304
+ def initialize_copy(other)
305
+ @data = other.data.dup
306
+ end
307
+
308
+ def check_modify
309
+ raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen?
310
+ end
311
+
312
+ def get_key_string(section, key)
313
+ Config.get_key_string(@data, section, key)
314
+ end
315
+ end
316
+ end
@@ -101,13 +101,13 @@ class OpenSSL::TestCipher < Test::Unit::TestCase
101
101
  assert_equal(@data, decrypted_data[0...@data.size])
102
102
  end
103
103
 
104
- if PLATFORM =~ /java/
104
+ if RUBY_PLATFORM =~ /java/
105
105
  # JRuby extension - using Java padding types
106
-
106
+
107
107
  def test_disable_padding_javastyle
108
108
  test_disable_padding('NoPadding')
109
109
  end
110
-
110
+
111
111
  def test_iso10126_padding
112
112
  @c1.encrypt
113
113
  @c1.key = @key
@@ -176,7 +176,7 @@ class OpenSSL::TestCipher < Test::Unit::TestCase
176
176
  c1.key = key
177
177
  e = c1.update data
178
178
  e << c1.final
179
-
179
+
180
180
  c2 = OpenSSL::Cipher::Cipher.new("DES-CBC")
181
181
  c2.padding = 0
182
182
  c2.iv = "0" * 8
@@ -0,0 +1,290 @@
1
+ require 'openssl'
2
+ require "test/unit"
3
+ require 'tempfile'
4
+ require File.join(File.dirname(__FILE__), "utils.rb")
5
+
6
+ class OpenSSL::TestConfig < Test::Unit::TestCase
7
+ def setup
8
+ file = Tempfile.open("openssl.cnf")
9
+ file << <<__EOD__
10
+ HOME = .
11
+ [ ca ]
12
+ default_ca = CA_default
13
+ [ CA_default ]
14
+ dir = ./demoCA
15
+ certs = ./certs
16
+ __EOD__
17
+ file.close
18
+ @it = OpenSSL::Config.new(file.path)
19
+ end
20
+
21
+ def TODO_test_constants
22
+ assert(defined?(OpenSSL::Config::DEFAULT_CONFIG_FILE))
23
+ assert_nothing_raised do
24
+ OpenSSL::Config.load(OpenSSL::Config::DEFAULT_CONFIG_FILE)
25
+ end
26
+ end
27
+
28
+ def test_s_parse
29
+ c = OpenSSL::Config.parse('')
30
+ assert_equal("[ default ]\n\n", c.to_s)
31
+ c = OpenSSL::Config.parse(@it.to_s)
32
+ assert_equal(['CA_default', 'ca', 'default'], c.sections.sort)
33
+ end
34
+
35
+ def test_s_parse_format
36
+ c = OpenSSL::Config.parse(<<__EOC__)
37
+ baz =qx\t # "baz = qx"
38
+
39
+ foo::bar = baz # shortcut section::key format
40
+ default::bar = baz # ditto
41
+ a=\t \t # "a = ": trailing spaces are ignored
42
+ =b # " = b": empty key
43
+ =c # " = c": empty key (override the above line)
44
+ d= # "c = ": trailing comment is ignored
45
+
46
+ sq = 'foo''b\\'ar'
47
+ dq ="foo""''\\""
48
+ dq2 = foo""bar
49
+ esc=a\\r\\n\\b\\tb
50
+ foo\\bar = foo\\b\\\\ar
51
+ foo\\bar::foo\\bar = baz
52
+ [default1 default2]\t\t # space is allowed in section name
53
+ fo =b ar # space allowed in value
54
+ [emptysection]
55
+ [doller ]
56
+ foo=bar
57
+ bar = $(foo)
58
+ baz = 123$(default::bar)456${foo}798
59
+ qux = ${baz}
60
+ quxx = $qux.$qux
61
+ __EOC__
62
+ assert_equal(['default', 'default1 default2', 'doller', 'emptysection', 'foo', 'foo\\bar'], c.sections.sort)
63
+ assert_equal(['', 'a', 'bar', 'baz', 'd', 'dq', 'dq2', 'esc', 'foo\\bar', 'sq'], c['default'].keys.sort)
64
+ assert_equal('c', c['default'][''])
65
+ assert_equal('', c['default']['a'])
66
+ assert_equal('qx', c['default']['baz'])
67
+ assert_equal('', c['default']['d'])
68
+ assert_equal('baz', c['default']['bar'])
69
+ assert_equal("foob'ar", c['default']['sq'])
70
+ assert_equal("foo''\"", c['default']['dq'])
71
+ assert_equal("foobar", c['default']['dq2'])
72
+ assert_equal("a\r\n\b\tb", c['default']['esc'])
73
+ assert_equal("foo\b\\ar", c['default']['foo\\bar'])
74
+ assert_equal('baz', c['foo']['bar'])
75
+ assert_equal('baz', c['foo\\bar']['foo\\bar'])
76
+ assert_equal('b ar', c['default1 default2']['fo'])
77
+
78
+ # dolloer
79
+ assert_equal('bar', c['doller']['foo'])
80
+ assert_equal('bar', c['doller']['bar'])
81
+ assert_equal('123baz456bar798', c['doller']['baz'])
82
+ assert_equal('123baz456bar798', c['doller']['qux'])
83
+ assert_equal('123baz456bar798.123baz456bar798', c['doller']['quxx'])
84
+
85
+ excn = assert_raise(OpenSSL::ConfigError) do
86
+ OpenSSL::Config.parse("foo = $bar")
87
+ end
88
+ assert_equal("error in line 1: variable has no value", excn.message)
89
+
90
+ excn = assert_raise(OpenSSL::ConfigError) do
91
+ OpenSSL::Config.parse("foo = $(bar")
92
+ end
93
+ assert_equal("error in line 1: no close brace", excn.message)
94
+
95
+ excn = assert_raise(OpenSSL::ConfigError) do
96
+ OpenSSL::Config.parse("f o =b ar # no space in key")
97
+ end
98
+ assert_equal("error in line 1: missing equal sign", excn.message)
99
+
100
+ excn = assert_raise(OpenSSL::ConfigError) do
101
+ OpenSSL::Config.parse(<<__EOC__)
102
+ # comment 1 # comments
103
+
104
+ #
105
+ # comment 2
106
+ \t#comment 3
107
+ [second ]\t
108
+ [third # section not terminated
109
+ __EOC__
110
+ end
111
+ assert_equal("error in line 7: missing close square bracket", excn.message)
112
+ end
113
+
114
+ def test_s_load
115
+ # alias of new
116
+ c = OpenSSL::Config.load
117
+ assert_equal("", c.to_s)
118
+ assert_equal([], c.sections)
119
+ #
120
+ file = Tempfile.open("openssl.cnf")
121
+ file.close
122
+ c = OpenSSL::Config.load(file.path)
123
+ assert_equal("[ default ]\n\n", c.to_s)
124
+ assert_equal(['default'], c.sections)
125
+ end
126
+
127
+ def test_initialize
128
+ c = OpenSSL::Config.new
129
+ assert_equal("", c.to_s)
130
+ assert_equal([], c.sections)
131
+ end
132
+
133
+ def test_initialize_with_empty_file
134
+ file = Tempfile.open("openssl.cnf")
135
+ file.close
136
+ c = OpenSSL::Config.new(file.path)
137
+ assert_equal("[ default ]\n\n", c.to_s)
138
+ assert_equal(['default'], c.sections)
139
+ end
140
+
141
+ def test_initialize_with_example_file
142
+ assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort)
143
+ end
144
+
145
+ def test_get_value
146
+ assert_equal('CA_default', @it.get_value('ca', 'default_ca'))
147
+ assert_equal(nil, @it.get_value('ca', 'no such key'))
148
+ assert_equal(nil, @it.get_value('no such section', 'no such key'))
149
+ assert_equal('.', @it.get_value('', 'HOME'))
150
+ assert_raise(TypeError) do
151
+ @it.get_value(nil, 'HOME') # not allowed unlike Config#value
152
+ end
153
+ # fallback to 'default' ugly...
154
+ assert_equal('.', @it.get_value('unknown', 'HOME'))
155
+ end
156
+
157
+ def test_get_value_ENV
158
+ key = ENV.keys.first
159
+ assert_not_nil(key) # make sure we have at least one ENV var.
160
+ assert_equal(ENV[key], @it.get_value('ENV', key))
161
+ end
162
+
163
+ def test_value
164
+ # supress deprecation warnings
165
+ OpenSSL::TestUtils.silent do
166
+ assert_equal('CA_default', @it.value('ca', 'default_ca'))
167
+ assert_equal(nil, @it.value('ca', 'no such key'))
168
+ assert_equal(nil, @it.value('no such section', 'no such key'))
169
+ assert_equal('.', @it.value('', 'HOME'))
170
+ assert_equal('.', @it.value(nil, 'HOME'))
171
+ assert_equal('.', @it.value('HOME'))
172
+ # fallback to 'default' ugly...
173
+ assert_equal('.', @it.value('unknown', 'HOME'))
174
+ end
175
+ end
176
+
177
+ def test_value_ENV
178
+ OpenSSL::TestUtils.silent do
179
+ key = ENV.keys.first
180
+ assert_not_nil(key) # make sure we have at least one ENV var.
181
+ assert_equal(ENV[key], @it.value('ENV', key))
182
+ end
183
+ end
184
+
185
+ def test_aref
186
+ assert_equal({'HOME' => '.'}, @it['default'])
187
+ assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it['CA_default'])
188
+ assert_equal({}, @it['no_such_section'])
189
+ assert_equal({}, @it[''])
190
+ end
191
+
192
+ def test_section
193
+ OpenSSL::TestUtils.silent do
194
+ assert_equal({'HOME' => '.'}, @it.section('default'))
195
+ assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it.section('CA_default'))
196
+ assert_equal({}, @it.section('no_such_section'))
197
+ assert_equal({}, @it.section(''))
198
+ end
199
+ end
200
+
201
+ def test_sections
202
+ assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort)
203
+ @it['new_section'] = {'foo' => 'bar'}
204
+ assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort)
205
+ @it['new_section'] = {}
206
+ assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort)
207
+ end
208
+
209
+ def test_add_value
210
+ c = OpenSSL::Config.new
211
+ assert_equal("", c.to_s)
212
+ # add key
213
+ c.add_value('default', 'foo', 'bar')
214
+ assert_equal("[ default ]\nfoo=bar\n\n", c.to_s)
215
+ # add another key
216
+ c.add_value('default', 'baz', 'qux')
217
+ assert_equal('bar', c['default']['foo'])
218
+ assert_equal('qux', c['default']['baz'])
219
+ # update the value
220
+ c.add_value('default', 'baz', 'quxxx')
221
+ assert_equal('bar', c['default']['foo'])
222
+ assert_equal('quxxx', c['default']['baz'])
223
+ # add section and key
224
+ c.add_value('section', 'foo', 'bar')
225
+ assert_equal('bar', c['default']['foo'])
226
+ assert_equal('quxxx', c['default']['baz'])
227
+ assert_equal('bar', c['section']['foo'])
228
+ end
229
+
230
+ def test_aset
231
+ @it['foo'] = {'bar' => 'baz'}
232
+ assert_equal({'bar' => 'baz'}, @it['foo'])
233
+ @it['foo'] = {'bar' => 'qux', 'baz' => 'quxx'}
234
+ assert_equal({'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
235
+
236
+ # OpenSSL::Config is add only for now.
237
+ @it['foo'] = {'foo' => 'foo'}
238
+ assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
239
+ # you cannot override or remove any section and key.
240
+ @it['foo'] = {}
241
+ assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
242
+ end
243
+
244
+ def test_each
245
+ # each returns [section, key, value] array.
246
+ ary = @it.map { |e| e }.sort { |a, b| a[0] <=> b[0] }
247
+ assert_equal(4, ary.size)
248
+ assert_equal('CA_default', ary[0][0])
249
+ assert_equal('CA_default', ary[1][0])
250
+ assert_equal(["ca", "default_ca", "CA_default"], ary[2])
251
+ assert_equal(["default", "HOME", "."], ary[3])
252
+ end
253
+
254
+ def test_to_s
255
+ c = OpenSSL::Config.parse("[empty]\n")
256
+ assert_equal("[ default ]\n\n[ empty ]\n\n", c.to_s)
257
+ end
258
+
259
+ def test_inspect
260
+ assert_match(/#<OpenSSL::Config sections=\[.*\]>/, @it.inspect)
261
+ end
262
+
263
+ def test_freeze
264
+ c = OpenSSL::Config.new
265
+ c['foo'] = [['key', 'value']]
266
+ c.freeze
267
+
268
+ # [ruby-core:18377]
269
+ # RuntimeError for 1.9, TypeError for 1.8
270
+ assert_raise(TypeError, /frozen/) do
271
+ c['foo'] = [['key', 'wrong']]
272
+ end
273
+ end
274
+
275
+ def test_dup
276
+ assert(!@it.sections.empty?)
277
+ c = @it.dup
278
+ assert_equal(@it.sections.sort, c.sections.sort)
279
+ @it['newsection'] = {'a' => 'b'}
280
+ assert_not_equal(@it.sections.sort, c.sections.sort)
281
+ end
282
+
283
+ def test_clone
284
+ assert(!@it.sections.empty?)
285
+ c = @it.clone
286
+ assert_equal(@it.sections.sort, c.sections.sort)
287
+ @it['newsection'] = {'a' => 'b'}
288
+ assert_not_equal(@it.sections.sort, c.sections.sort)
289
+ end
290
+ end