jruby-openssl 0.9.7-java → 0.9.8-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ #--
2
+ #
3
+ # $RCSfile$
4
+ #
5
+ # = Ruby-space predefined Cipher subclasses
6
+ #
7
+ # = Info
8
+ # 'OpenSSL for Ruby 2' project
9
+ # Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
10
+ # All rights reserved.
11
+ #
12
+ # = Licence
13
+ # This program is licenced under the same licence as Ruby.
14
+ # (See the file 'LICENCE'.)
15
+ #
16
+ # = Version
17
+ # $Id$
18
+ #
19
+ #++
20
+
21
+ module OpenSSL
22
+ class Cipher
23
+ # This class is only provided for backwards compatibility. Use OpenSSL::Cipher in the future.
24
+ class Cipher < Cipher
25
+ # add warning
26
+ end
27
+ end # Cipher
28
+ end # OpenSSL
@@ -0,0 +1,313 @@
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
+ require 'stringio'
14
+
15
+ module OpenSSL
16
+ class Config
17
+ include Enumerable
18
+
19
+ class << self
20
+ def parse(str)
21
+ c = new()
22
+ parse_config(StringIO.new(str)).each do |section, hash|
23
+ c[section] = hash
24
+ end
25
+ c
26
+ end
27
+
28
+ alias load new
29
+
30
+ def parse_config(io)
31
+ begin
32
+ parse_config_lines(io)
33
+ rescue ConfigError => e
34
+ e.message.replace("error in line #{io.lineno}: " + e.message)
35
+ raise
36
+ end
37
+ end
38
+
39
+ def get_key_string(data, section, key) # :nodoc:
40
+ if v = data[section] && data[section][key]
41
+ return v
42
+ elsif section == 'ENV'
43
+ if v = ENV[key]
44
+ return v
45
+ end
46
+ end
47
+ if v = data['default'] && data['default'][key]
48
+ return v
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def parse_config_lines(io)
55
+ section = 'default'
56
+ data = {section => {}}
57
+ while definition = get_definition(io)
58
+ definition = clear_comments(definition)
59
+ next if definition.empty?
60
+ if definition[0] == ?[
61
+ if /\[([^\]]*)\]/ =~ definition
62
+ section = $1.strip
63
+ data[section] ||= {}
64
+ else
65
+ raise ConfigError, "missing close square bracket"
66
+ end
67
+ else
68
+ if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
69
+ if $2
70
+ section = $1
71
+ key = $2
72
+ else
73
+ key = $1
74
+ end
75
+ value = unescape_value(data, section, $3)
76
+ (data[section] ||= {})[key] = value.strip
77
+ else
78
+ raise ConfigError, "missing equal sign"
79
+ end
80
+ end
81
+ end
82
+ data
83
+ end
84
+
85
+ # escape with backslash
86
+ QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/
87
+ # escape with backslash and doubled dq
88
+ QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/
89
+ # escaped char map
90
+ ESCAPE_MAP = {
91
+ "r" => "\r",
92
+ "n" => "\n",
93
+ "b" => "\b",
94
+ "t" => "\t",
95
+ }
96
+
97
+ def unescape_value(data, section, value)
98
+ scanned = []
99
+ while m = value.match(/['"\\$]/)
100
+ scanned << m.pre_match
101
+ c = m[0]
102
+ value = m.post_match
103
+ case c
104
+ when "'"
105
+ if m = value.match(QUOTE_REGEXP_SQ)
106
+ scanned << m[1].gsub(/\\(.)/, '\\1')
107
+ value = m.post_match
108
+ else
109
+ break
110
+ end
111
+ when '"'
112
+ if m = value.match(QUOTE_REGEXP_DQ)
113
+ scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1')
114
+ value = m.post_match
115
+ else
116
+ break
117
+ end
118
+ when "\\"
119
+ c = value.slice!(0, 1)
120
+ scanned << (ESCAPE_MAP[c] || c)
121
+ when "$"
122
+ ref, value = extract_reference(value)
123
+ refsec = section
124
+ if ref.index('::')
125
+ refsec, ref = ref.split('::', 2)
126
+ end
127
+ if v = get_key_string(data, refsec, ref)
128
+ scanned << v
129
+ else
130
+ raise ConfigError, "variable has no value"
131
+ end
132
+ else
133
+ raise 'must not reaced'
134
+ end
135
+ end
136
+ scanned << value
137
+ scanned.join
138
+ end
139
+
140
+ def extract_reference(value)
141
+ rest = ''
142
+ if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/)
143
+ value = m[1] || m[2]
144
+ rest = m.post_match
145
+ elsif [?(, ?{].include?(value[0])
146
+ raise ConfigError, "no close brace"
147
+ end
148
+ if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/)
149
+ return m[0], m.post_match + rest
150
+ else
151
+ raise
152
+ end
153
+ end
154
+
155
+ def clear_comments(line)
156
+ # FCOMMENT
157
+ if m = line.match(/\A([\t\n\f ]*);.*\z/)
158
+ return m[1]
159
+ end
160
+ # COMMENT
161
+ scanned = []
162
+ while m = line.match(/[#'"\\]/)
163
+ scanned << m.pre_match
164
+ c = m[0]
165
+ line = m.post_match
166
+ case c
167
+ when '#'
168
+ line = nil
169
+ break
170
+ when "'", '"'
171
+ regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ
172
+ scanned << c
173
+ if m = line.match(regexp)
174
+ scanned << m[0]
175
+ line = m.post_match
176
+ else
177
+ scanned << line
178
+ line = nil
179
+ break
180
+ end
181
+ when "\\"
182
+ scanned << c
183
+ scanned << line.slice!(0, 1)
184
+ else
185
+ raise 'must not reaced'
186
+ end
187
+ end
188
+ scanned << line
189
+ scanned.join
190
+ end
191
+
192
+ def get_definition(io)
193
+ if line = get_line(io)
194
+ while /[^\\]\\\z/ =~ line
195
+ if extra = get_line(io)
196
+ line += extra
197
+ else
198
+ break
199
+ end
200
+ end
201
+ return line.strip
202
+ end
203
+ end
204
+
205
+ def get_line(io)
206
+ if line = io.gets
207
+ line.gsub(/[\r\n]*/, '')
208
+ end
209
+ end
210
+ end
211
+
212
+ def initialize(filename = nil)
213
+ @data = {}
214
+ if filename
215
+ File.open(filename.to_s) do |file|
216
+ Config.parse_config(file).each do |section, hash|
217
+ self[section] = hash
218
+ end
219
+ end
220
+ end
221
+ end
222
+
223
+ def get_value(section, key)
224
+ if section.nil?
225
+ raise TypeError.new('nil not allowed')
226
+ end
227
+ section = 'default' if section.empty?
228
+ get_key_string(section, key)
229
+ end
230
+
231
+ def value(arg1, arg2 = nil)
232
+ warn('Config#value is deprecated; use Config#get_value')
233
+ if arg2.nil?
234
+ section, key = 'default', arg1
235
+ else
236
+ section, key = arg1, arg2
237
+ end
238
+ section ||= 'default'
239
+ section = 'default' if section.empty?
240
+ get_key_string(section, key)
241
+ end
242
+
243
+ def add_value(section, key, value)
244
+ check_modify
245
+ (@data[section] ||= {})[key] = value
246
+ end
247
+
248
+ def [](section)
249
+ @data[section] || {}
250
+ end
251
+
252
+ def section(name)
253
+ warn('Config#section is deprecated; use Config#[]')
254
+ @data[name] || {}
255
+ end
256
+
257
+ def []=(section, pairs)
258
+ check_modify
259
+ @data[section] ||= {}
260
+ pairs.each do |key, value|
261
+ self.add_value(section, key, value)
262
+ end
263
+ end
264
+
265
+ def sections
266
+ @data.keys
267
+ end
268
+
269
+ def to_s
270
+ ary = []
271
+ @data.keys.sort.each do |section|
272
+ ary << "[ #{section} ]\n"
273
+ @data[section].keys.each do |key|
274
+ ary << "#{key}=#{@data[section][key]}\n"
275
+ end
276
+ ary << "\n"
277
+ end
278
+ ary.join
279
+ end
280
+
281
+ def each
282
+ @data.each do |section, hash|
283
+ hash.each do |key, value|
284
+ yield [section, key, value]
285
+ end
286
+ end
287
+ end
288
+
289
+ def inspect
290
+ "#<#{self.class.name} sections=#{sections.inspect}>"
291
+ end
292
+
293
+ protected
294
+
295
+ def data
296
+ @data
297
+ end
298
+
299
+ private
300
+
301
+ def initialize_copy(other)
302
+ @data = other.data.dup
303
+ end
304
+
305
+ def check_modify
306
+ raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen?
307
+ end
308
+
309
+ def get_key_string(section, key)
310
+ Config.get_key_string(@data, section, key)
311
+ end
312
+ end
313
+ end
@@ -0,0 +1,54 @@
1
+ #--
2
+ #
3
+ # $RCSfile$
4
+ #
5
+ # = Ruby-space predefined Digest subclasses
6
+ #
7
+ # = Info
8
+ # 'OpenSSL for Ruby 2' project
9
+ # Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
10
+ # All rights reserved.
11
+ #
12
+ # = Licence
13
+ # This program is licenced under the same licence as Ruby.
14
+ # (See the file 'LICENCE'.)
15
+ #
16
+ # = Version
17
+ # $Id$
18
+ #
19
+ #++
20
+
21
+ module OpenSSL
22
+ class Digest
23
+ # Deprecated.
24
+ #
25
+ # This class is only provided for backwards compatibility.
26
+ class Digest < Digest # :nodoc:
27
+ # Deprecated.
28
+ #
29
+ # See OpenSSL::Digest.new
30
+ def initialize(*args)
31
+ warn('Digest::Digest is deprecated; use Digest')
32
+ super(*args)
33
+ end
34
+ end
35
+
36
+ end # Digest
37
+
38
+ # Returns a Digest subclass by +name+.
39
+ #
40
+ # require 'openssl'
41
+ #
42
+ # OpenSSL::Digest("MD5")
43
+ # # => OpenSSL::Digest::MD5
44
+ #
45
+ # Digest("Foo")
46
+ # # => NameError: wrong constant name Foo
47
+
48
+ def Digest(name)
49
+ OpenSSL::Digest.const_get(name)
50
+ end
51
+
52
+ module_function :Digest
53
+
54
+ end # OpenSSL
@@ -0,0 +1,193 @@
1
+ =begin
2
+ = $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL
3
+
4
+ = Info
5
+ 'OpenSSL for Ruby 2' project
6
+ Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
7
+ All rights reserved.
8
+
9
+ = Licence
10
+ This program is licenced under the same licence as Ruby.
11
+ (See the file 'LICENCE'.)
12
+
13
+ = Version
14
+ $Id$
15
+ =end
16
+
17
+ require "openssl/buffering"
18
+ require 'fcntl' # used by OpenSSL::SSL::Nonblock (if loaded)
19
+
20
+ module OpenSSL
21
+ module SSL
22
+
23
+ # FIXME: Using the old non-ASN1 logic here because our ASN1 appears to
24
+ # return the wrong types for some decoded objects.
25
+ # @see https://github.com/jruby/jruby/issues/1102
26
+ # @private
27
+ def verify_certificate_identity(cert, hostname)
28
+ should_verify_common_name = true
29
+ cert.extensions.each { |ext|
30
+ next if ext.oid != "subjectAltName"
31
+ ext.value.split(/,\s+/).each { |general_name|
32
+ # MRI 1.9.3 (since we parse ASN.1 differently)
33
+ # when 2 # dNSName in GeneralName (RFC5280)
34
+ if /\ADNS:(.*)/ =~ general_name
35
+ should_verify_common_name = false
36
+ return true if verify_hostname(hostname, $1)
37
+ # MRI 1.9.3 (since we parse ASN.1 differently)
38
+ # when 7 # iPAddress in GeneralName (RFC5280)
39
+ elsif /\AIP(?: Address)?:(.*)/ =~ general_name
40
+ should_verify_common_name = false
41
+ return true if $1 == hostname
42
+ # NOTE: bellow logic makes little sense as we read exts differently
43
+ #value = $1 # follows GENERAL_NAME_print() in x509v3/v3_alt.c
44
+ #if value.size == 4
45
+ # return true if value.unpack('C*').join('.') == hostname
46
+ #elsif value.size == 16
47
+ # return true if value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname
48
+ #end
49
+ end
50
+ }
51
+ }
52
+ if should_verify_common_name
53
+ cert.subject.to_a.each { |oid, value|
54
+ if oid == "CN"
55
+ return true if verify_hostname(hostname, value)
56
+ end
57
+ }
58
+ end
59
+ return false
60
+ end
61
+ module_function :verify_certificate_identity
62
+
63
+ def verify_hostname(hostname, san) # :nodoc:
64
+ # RFC 5280, IA5String is limited to the set of ASCII characters
65
+ return false unless san.ascii_only?
66
+ return false unless hostname.ascii_only?
67
+
68
+ # See RFC 6125, section 6.4.1
69
+ # Matching is case-insensitive.
70
+ san_parts = san.downcase.split(".")
71
+
72
+ # TODO: this behavior should probably be more strict
73
+ return san == hostname if san_parts.size < 2
74
+
75
+ # Matching is case-insensitive.
76
+ host_parts = hostname.downcase.split(".")
77
+
78
+ # RFC 6125, section 6.4.3, subitem 2.
79
+ # If the wildcard character is the only character of the left-most
80
+ # label in the presented identifier, the client SHOULD NOT compare
81
+ # against anything but the left-most label of the reference
82
+ # identifier (e.g., *.example.com would match foo.example.com but
83
+ # not bar.foo.example.com or example.com).
84
+ return false unless san_parts.size == host_parts.size
85
+
86
+ # RFC 6125, section 6.4.3, subitem 1.
87
+ # The client SHOULD NOT attempt to match a presented identifier in
88
+ # which the wildcard character comprises a label other than the
89
+ # left-most label (e.g., do not match bar.*.example.net).
90
+ return false unless verify_wildcard(host_parts.shift, san_parts.shift)
91
+
92
+ san_parts.join(".") == host_parts.join(".")
93
+ end
94
+ module_function :verify_hostname
95
+
96
+ def verify_wildcard(domain_component, san_component) # :nodoc:
97
+ parts = san_component.split("*", -1)
98
+
99
+ return false if parts.size > 2
100
+ return san_component == domain_component if parts.size == 1
101
+
102
+ # RFC 6125, section 6.4.3, subitem 3.
103
+ # The client SHOULD NOT attempt to match a presented identifier
104
+ # where the wildcard character is embedded within an A-label or
105
+ # U-label of an internationalized domain name.
106
+ return false if domain_component.start_with?("xn--") && san_component != "*"
107
+
108
+ parts[0].length + parts[1].length < domain_component.length &&
109
+ domain_component.start_with?(parts[0]) &&
110
+ domain_component.end_with?(parts[1])
111
+ end
112
+ module_function :verify_wildcard
113
+
114
+ class SSLSocket
115
+ include Buffering
116
+ include SocketForwarder
117
+ include Nonblock
118
+
119
+ ##
120
+ # Perform hostname verification after an SSL connection is established
121
+ #
122
+ # This method MUST be called after calling #connect to ensure that the
123
+ # hostname of a remote peer has been verified.
124
+ def post_connection_check(hostname)
125
+ unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
126
+ raise SSLError, "hostname \"#{hostname}\" does not match the server certificate"
127
+ end
128
+ return true
129
+ end
130
+
131
+ end
132
+
133
+ ##
134
+ # SSLServer represents a TCP/IP server socket with Secure Sockets Layer.
135
+ class SSLServer
136
+ include SocketForwarder
137
+ # When true then #accept works exactly the same as TCPServer#accept
138
+ attr_accessor :start_immediately
139
+
140
+ # Creates a new instance of SSLServer.
141
+ # * +srv+ is an instance of TCPServer.
142
+ # * +ctx+ is an instance of OpenSSL::SSL::SSLContext.
143
+ def initialize(svr, ctx)
144
+ @svr = svr
145
+ @ctx = ctx
146
+ unless ctx.session_id_context
147
+ # see #6137 - session id may not exceed 32 bytes
148
+ prng = ::Random.new($0.hash)
149
+ session_id = prng.bytes(16).unpack('H*')[0]
150
+ @ctx.session_id_context = session_id
151
+ end
152
+ @start_immediately = true
153
+ end
154
+
155
+ # Returns the TCPServer passed to the SSLServer when initialized.
156
+ def to_io
157
+ @svr
158
+ end
159
+
160
+ # See TCPServer#listen for details.
161
+ def listen(backlog=5)
162
+ @svr.listen(backlog)
163
+ end
164
+
165
+ # See BasicSocket#shutdown for details.
166
+ def shutdown(how=Socket::SHUT_RDWR)
167
+ @svr.shutdown(how)
168
+ end
169
+
170
+ # Works similar to TCPServer#accept.
171
+ def accept
172
+ # Socket#accept returns [socket, addrinfo].
173
+ # TCPServer#accept returns a socket.
174
+ # The following comma strips addrinfo.
175
+ sock, = @svr.accept
176
+ begin
177
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
178
+ ssl.sync_close = true
179
+ ssl.accept if @start_immediately
180
+ ssl
181
+ rescue SSLError => ex
182
+ sock.close
183
+ raise ex
184
+ end
185
+ end
186
+
187
+ # See IO#close for details.
188
+ def close
189
+ @svr.close
190
+ end
191
+ end
192
+ end
193
+ end