rubysl-openssl 0.0.1 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +0 -1
- data/.travis.yml +7 -0
- data/README.md +2 -2
- data/Rakefile +0 -1
- data/ext/rubysl/openssl/extconf.h +50 -0
- data/ext/rubysl/openssl/extconf.rb +144 -0
- data/ext/rubysl/openssl/openssl_missing.c +343 -0
- data/ext/rubysl/openssl/openssl_missing.h +191 -0
- data/ext/rubysl/openssl/ossl.c +552 -0
- data/ext/rubysl/openssl/ossl.h +233 -0
- data/ext/rubysl/openssl/ossl_asn1.c +1160 -0
- data/ext/rubysl/openssl/ossl_asn1.h +59 -0
- data/ext/rubysl/openssl/ossl_bio.c +86 -0
- data/ext/rubysl/openssl/ossl_bio.h +21 -0
- data/ext/rubysl/openssl/ossl_bn.c +852 -0
- data/ext/rubysl/openssl/ossl_bn.h +25 -0
- data/ext/rubysl/openssl/ossl_cipher.c +569 -0
- data/ext/rubysl/openssl/ossl_cipher.h +22 -0
- data/ext/rubysl/openssl/ossl_config.c +75 -0
- data/ext/rubysl/openssl/ossl_config.h +22 -0
- data/ext/rubysl/openssl/ossl_digest.c +259 -0
- data/ext/rubysl/openssl/ossl_digest.h +22 -0
- data/ext/rubysl/openssl/ossl_engine.c +411 -0
- data/ext/rubysl/openssl/ossl_engine.h +20 -0
- data/ext/rubysl/openssl/ossl_hmac.c +268 -0
- data/ext/rubysl/openssl/ossl_hmac.h +19 -0
- data/ext/rubysl/openssl/ossl_ns_spki.c +257 -0
- data/ext/rubysl/openssl/ossl_ns_spki.h +21 -0
- data/ext/rubysl/openssl/ossl_ocsp.c +769 -0
- data/ext/rubysl/openssl/ossl_ocsp.h +24 -0
- data/ext/rubysl/openssl/ossl_pkcs12.c +210 -0
- data/ext/rubysl/openssl/ossl_pkcs12.h +15 -0
- data/ext/rubysl/openssl/ossl_pkcs5.c +99 -0
- data/ext/rubysl/openssl/ossl_pkcs5.h +6 -0
- data/ext/rubysl/openssl/ossl_pkcs7.c +1039 -0
- data/ext/rubysl/openssl/ossl_pkcs7.h +22 -0
- data/ext/rubysl/openssl/ossl_pkey.c +240 -0
- data/ext/rubysl/openssl/ossl_pkey.h +141 -0
- data/ext/rubysl/openssl/ossl_pkey_dh.c +532 -0
- data/ext/rubysl/openssl/ossl_pkey_dsa.c +484 -0
- data/ext/rubysl/openssl/ossl_pkey_ec.c +1593 -0
- data/ext/rubysl/openssl/ossl_pkey_rsa.c +593 -0
- data/ext/rubysl/openssl/ossl_rand.c +202 -0
- data/ext/rubysl/openssl/ossl_rand.h +20 -0
- data/ext/rubysl/openssl/ossl_ssl.c +1484 -0
- data/ext/rubysl/openssl/ossl_ssl.h +36 -0
- data/ext/rubysl/openssl/ossl_ssl_session.c +307 -0
- data/ext/rubysl/openssl/ossl_version.h +16 -0
- data/ext/rubysl/openssl/ossl_x509.c +104 -0
- data/ext/rubysl/openssl/ossl_x509.h +114 -0
- data/ext/rubysl/openssl/ossl_x509attr.c +274 -0
- data/ext/rubysl/openssl/ossl_x509cert.c +764 -0
- data/ext/rubysl/openssl/ossl_x509crl.c +535 -0
- data/ext/rubysl/openssl/ossl_x509ext.c +458 -0
- data/ext/rubysl/openssl/ossl_x509name.c +399 -0
- data/ext/rubysl/openssl/ossl_x509req.c +466 -0
- data/ext/rubysl/openssl/ossl_x509revoked.c +229 -0
- data/ext/rubysl/openssl/ossl_x509store.c +625 -0
- data/ext/rubysl/openssl/ruby_missing.h +41 -0
- data/lib/openssl.rb +1 -0
- data/lib/openssl/bn.rb +35 -0
- data/lib/openssl/buffering.rb +241 -0
- data/lib/openssl/cipher.rb +65 -0
- data/lib/openssl/config.rb +316 -0
- data/lib/openssl/digest.rb +61 -0
- data/lib/openssl/net/ftptls.rb +53 -0
- data/lib/openssl/net/telnets.rb +251 -0
- data/lib/openssl/pkcs7.rb +25 -0
- data/lib/openssl/ssl-internal.rb +187 -0
- data/lib/openssl/ssl.rb +1 -0
- data/lib/openssl/x509-internal.rb +153 -0
- data/lib/openssl/x509.rb +1 -0
- data/lib/rubysl/openssl.rb +28 -0
- data/lib/rubysl/openssl/version.rb +5 -0
- data/rubysl-openssl.gemspec +19 -18
- data/spec/cipher_spec.rb +16 -0
- data/spec/config/freeze_spec.rb +17 -0
- data/spec/hmac/digest_spec.rb +15 -0
- data/spec/hmac/hexdigest_spec.rb +15 -0
- data/spec/random/pseudo_bytes_spec.rb +5 -0
- data/spec/random/random_bytes_spec.rb +5 -0
- data/spec/random/shared/random_bytes.rb +28 -0
- data/spec/shared/constants.rb +11 -0
- data/spec/x509/name/parse_spec.rb +47 -0
- metadata +153 -89
- data/lib/rubysl-openssl.rb +0 -7
- data/lib/rubysl-openssl/version.rb +0 -5
@@ -0,0 +1,61 @@
|
|
1
|
+
=begin
|
2
|
+
= $RCSfile$ -- Ruby-space predefined Digest subclasses
|
3
|
+
|
4
|
+
= Info
|
5
|
+
'OpenSSL for Ruby 2' project
|
6
|
+
Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
|
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: digest.rb 28004 2010-05-24 23:58:49Z shyouhei $
|
15
|
+
=end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Should we care what if somebody require this file directly?
|
19
|
+
#require 'openssl'
|
20
|
+
|
21
|
+
module OpenSSL
|
22
|
+
class Digest
|
23
|
+
|
24
|
+
alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1)
|
25
|
+
if OPENSSL_VERSION_NUMBER > 0x00908000
|
26
|
+
alg += %w(SHA224 SHA256 SHA384 SHA512)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.digest(name, data)
|
30
|
+
super(data, name)
|
31
|
+
end
|
32
|
+
|
33
|
+
alg.each{|name|
|
34
|
+
klass = Class.new(Digest){
|
35
|
+
define_method(:initialize){|*data|
|
36
|
+
if data.length > 1
|
37
|
+
raise ArgumentError,
|
38
|
+
"wrong number of arguments (#{data.length} for 1)"
|
39
|
+
end
|
40
|
+
super(name, data.first)
|
41
|
+
}
|
42
|
+
}
|
43
|
+
singleton = (class << klass; self; end)
|
44
|
+
singleton.class_eval{
|
45
|
+
define_method(:digest){|data| Digest.digest(name, data) }
|
46
|
+
define_method(:hexdigest){|data| Digest.hexdigest(name, data) }
|
47
|
+
}
|
48
|
+
const_set(name, klass)
|
49
|
+
}
|
50
|
+
|
51
|
+
# This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future.
|
52
|
+
class Digest < Digest
|
53
|
+
def initialize(*args)
|
54
|
+
# add warning
|
55
|
+
super(*args)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end # Digest
|
60
|
+
end # OpenSSL
|
61
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
=begin
|
2
|
+
= $RCSfile$ -- SSL/TLS enhancement for Net::HTTP.
|
3
|
+
|
4
|
+
= Info
|
5
|
+
'OpenSSL for Ruby 2' project
|
6
|
+
Copyright (C) 2003 Blaz Grilc <farmer@gmx.co.uk>
|
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
|
+
= Requirements
|
14
|
+
|
15
|
+
= Version
|
16
|
+
$Id: ftptls.rb 13657 2007-10-08 11:16:54Z gotoyuzo $
|
17
|
+
|
18
|
+
= Notes
|
19
|
+
Tested on FreeBSD 5-CURRENT and 4-STABLE
|
20
|
+
- ruby 1.6.8 (2003-01-17) [i386-freebsd5]
|
21
|
+
- OpenSSL 0.9.7a Feb 19 2003
|
22
|
+
- ruby-openssl-0.2.0.p0
|
23
|
+
tested on ftp server: glftpd 1.30
|
24
|
+
=end
|
25
|
+
|
26
|
+
require 'socket'
|
27
|
+
require 'openssl'
|
28
|
+
require 'net/ftp'
|
29
|
+
|
30
|
+
module Net
|
31
|
+
class FTPTLS < FTP
|
32
|
+
def connect(host, port=FTP_PORT)
|
33
|
+
@hostname = host
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
def login(user = "anonymous", passwd = nil, acct = nil)
|
38
|
+
store = OpenSSL::X509::Store.new
|
39
|
+
store.set_default_paths
|
40
|
+
ctx = OpenSSL::SSL::SSLContext.new('SSLv23')
|
41
|
+
ctx.cert_store = store
|
42
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
43
|
+
ctx.key = nil
|
44
|
+
ctx.cert = nil
|
45
|
+
voidcmd("AUTH TLS")
|
46
|
+
@sock = OpenSSL::SSL::SSLSocket.new(@sock, ctx)
|
47
|
+
@sock.connect
|
48
|
+
@sock.post_connection_check(@hostname)
|
49
|
+
super(user, passwd, acct)
|
50
|
+
voidcmd("PBSZ 0")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
=begin
|
2
|
+
= $RCSfile$ -- SSL/TLS enhancement for Net::Telnet.
|
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: telnets.rb 13657 2007-10-08 11:16:54Z gotoyuzo $
|
15
|
+
|
16
|
+
2001/11/06: Contiributed to Ruby/OpenSSL project.
|
17
|
+
|
18
|
+
== class Net::Telnet
|
19
|
+
|
20
|
+
This class will initiate SSL/TLS session automaticaly if the server
|
21
|
+
sent OPT_STARTTLS. Some options are added for SSL/TLS.
|
22
|
+
|
23
|
+
host = Net::Telnet::new({
|
24
|
+
"Host" => "localhost",
|
25
|
+
"Port" => "telnets",
|
26
|
+
## follows are new options.
|
27
|
+
'CertFile' => "user.crt",
|
28
|
+
'KeyFile' => "user.key",
|
29
|
+
'CAFile' => "/some/where/certs/casert.pem",
|
30
|
+
'CAPath' => "/some/where/caserts",
|
31
|
+
'VerifyMode' => SSL::VERIFY_PEER,
|
32
|
+
'VerifyCallback' => verify_proc
|
33
|
+
})
|
34
|
+
|
35
|
+
Or, the new options ('Cert', 'Key' and 'CACert') are available from
|
36
|
+
Michal Rokos's OpenSSL module.
|
37
|
+
|
38
|
+
cert_data = File.open("user.crt"){|io| io.read }
|
39
|
+
pkey_data = File.open("user.key"){|io| io.read }
|
40
|
+
cacert_data = File.open("your_ca.pem"){|io| io.read }
|
41
|
+
host = Net::Telnet::new({
|
42
|
+
"Host" => "localhost",
|
43
|
+
"Port" => "telnets",
|
44
|
+
'Cert' => OpenSSL::X509::Certificate.new(cert_data)
|
45
|
+
'Key' => OpenSSL::PKey::RSA.new(pkey_data)
|
46
|
+
'CACert' => OpenSSL::X509::Certificate.new(cacert_data)
|
47
|
+
'CAFile' => "/some/where/certs/casert.pem",
|
48
|
+
'CAPath' => "/some/where/caserts",
|
49
|
+
'VerifyMode' => SSL::VERIFY_PEER,
|
50
|
+
'VerifyCallback' => verify_proc
|
51
|
+
})
|
52
|
+
|
53
|
+
This class is expected to be a superset of usual Net::Telnet.
|
54
|
+
=end
|
55
|
+
|
56
|
+
require "net/telnet"
|
57
|
+
require "openssl"
|
58
|
+
|
59
|
+
module Net
|
60
|
+
class Telnet
|
61
|
+
attr_reader :ssl
|
62
|
+
|
63
|
+
OPT_STARTTLS = 46.chr # "\056" # "\x2e" # Start TLS
|
64
|
+
TLS_FOLLOWS = 1.chr # "\001" # "\x01" # FOLLOWS (for STARTTLS)
|
65
|
+
|
66
|
+
alias preprocess_orig preprocess
|
67
|
+
|
68
|
+
def ssl?; @ssl; end
|
69
|
+
|
70
|
+
def preprocess(string)
|
71
|
+
# combine CR+NULL into CR
|
72
|
+
string = string.gsub(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"]
|
73
|
+
|
74
|
+
# combine EOL into "\n"
|
75
|
+
string = string.gsub(/#{EOL}/no, "\n") unless @options["Binmode"]
|
76
|
+
|
77
|
+
string.gsub(/#{IAC}(
|
78
|
+
[#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]|
|
79
|
+
[#{DO}#{DONT}#{WILL}#{WONT}][#{OPT_BINARY}-#{OPT_EXOPL}]|
|
80
|
+
#{SB}[#{OPT_BINARY}-#{OPT_EXOPL}]
|
81
|
+
(#{IAC}#{IAC}|[^#{IAC}])+#{IAC}#{SE}
|
82
|
+
)/xno) do
|
83
|
+
if IAC == $1 # handle escaped IAC characters
|
84
|
+
IAC
|
85
|
+
elsif AYT == $1 # respond to "IAC AYT" (are you there)
|
86
|
+
self.write("nobody here but us pigeons" + EOL)
|
87
|
+
''
|
88
|
+
elsif DO[0] == $1[0] # respond to "IAC DO x"
|
89
|
+
if OPT_BINARY[0] == $1[1]
|
90
|
+
@telnet_option["BINARY"] = true
|
91
|
+
self.write(IAC + WILL + OPT_BINARY)
|
92
|
+
elsif OPT_STARTTLS[0] == $1[1]
|
93
|
+
self.write(IAC + WILL + OPT_STARTTLS)
|
94
|
+
self.write(IAC + SB + OPT_STARTTLS + TLS_FOLLOWS + IAC + SE)
|
95
|
+
else
|
96
|
+
self.write(IAC + WONT + $1[1..1])
|
97
|
+
end
|
98
|
+
''
|
99
|
+
elsif DONT[0] == $1[0] # respond to "IAC DON'T x" with "IAC WON'T x"
|
100
|
+
self.write(IAC + WONT + $1[1..1])
|
101
|
+
''
|
102
|
+
elsif WILL[0] == $1[0] # respond to "IAC WILL x"
|
103
|
+
if OPT_BINARY[0] == $1[1]
|
104
|
+
self.write(IAC + DO + OPT_BINARY)
|
105
|
+
elsif OPT_ECHO[0] == $1[1]
|
106
|
+
self.write(IAC + DO + OPT_ECHO)
|
107
|
+
elsif OPT_SGA[0] == $1[1]
|
108
|
+
@telnet_option["SGA"] = true
|
109
|
+
self.write(IAC + DO + OPT_SGA)
|
110
|
+
else
|
111
|
+
self.write(IAC + DONT + $1[1..1])
|
112
|
+
end
|
113
|
+
''
|
114
|
+
elsif WONT[0] == $1[0] # respond to "IAC WON'T x"
|
115
|
+
if OPT_ECHO[0] == $1[1]
|
116
|
+
self.write(IAC + DONT + OPT_ECHO)
|
117
|
+
elsif OPT_SGA[0] == $1[1]
|
118
|
+
@telnet_option["SGA"] = false
|
119
|
+
self.write(IAC + DONT + OPT_SGA)
|
120
|
+
else
|
121
|
+
self.write(IAC + DONT + $1[1..1])
|
122
|
+
end
|
123
|
+
''
|
124
|
+
elsif SB[0] == $1[0] # respond to "IAC SB xxx IAC SE"
|
125
|
+
if OPT_STARTTLS[0] == $1[1] && TLS_FOLLOWS[0] == $2[0]
|
126
|
+
@sock = OpenSSL::SSL::SSLSocket.new(@sock)
|
127
|
+
@sock.cert = @options['Cert'] unless @sock.cert
|
128
|
+
@sock.key = @options['Key'] unless @sock.key
|
129
|
+
@sock.ca_cert = @options['CACert']
|
130
|
+
@sock.ca_file = @options['CAFile']
|
131
|
+
@sock.ca_path = @options['CAPath']
|
132
|
+
@sock.timeout = @options['Timeout']
|
133
|
+
@sock.verify_mode = @options['VerifyMode']
|
134
|
+
@sock.verify_callback = @options['VerifyCallback']
|
135
|
+
@sock.verify_depth = @options['VerifyDepth']
|
136
|
+
@sock.connect
|
137
|
+
if @options['VerifyMode'] != OpenSSL::SSL::VERIFY_NONE
|
138
|
+
@sock.post_connection_check(@options['Host'])
|
139
|
+
end
|
140
|
+
@ssl = true
|
141
|
+
end
|
142
|
+
''
|
143
|
+
else
|
144
|
+
''
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end # preprocess
|
148
|
+
|
149
|
+
alias waitfor_org waitfor
|
150
|
+
|
151
|
+
def waitfor(options)
|
152
|
+
time_out = @options["Timeout"]
|
153
|
+
waittime = @options["Waittime"]
|
154
|
+
|
155
|
+
if options.kind_of?(Hash)
|
156
|
+
prompt = if options.has_key?("Match")
|
157
|
+
options["Match"]
|
158
|
+
elsif options.has_key?("Prompt")
|
159
|
+
options["Prompt"]
|
160
|
+
elsif options.has_key?("String")
|
161
|
+
Regexp.new( Regexp.quote(options["String"]) )
|
162
|
+
end
|
163
|
+
time_out = options["Timeout"] if options.has_key?("Timeout")
|
164
|
+
waittime = options["Waittime"] if options.has_key?("Waittime")
|
165
|
+
else
|
166
|
+
prompt = options
|
167
|
+
end
|
168
|
+
|
169
|
+
if time_out == false
|
170
|
+
time_out = nil
|
171
|
+
end
|
172
|
+
|
173
|
+
line = ''
|
174
|
+
buf = ''
|
175
|
+
@rest = '' unless @rest
|
176
|
+
|
177
|
+
until(prompt === line and not IO::select([@sock], nil, nil, waittime))
|
178
|
+
unless IO::select([@sock], nil, nil, time_out)
|
179
|
+
raise TimeoutError, "timed-out; wait for the next data"
|
180
|
+
end
|
181
|
+
begin
|
182
|
+
c = @rest + @sock.sysread(1024 * 1024)
|
183
|
+
@dumplog.log_dump('<', c) if @options.has_key?("Dump_log")
|
184
|
+
if @options["Telnetmode"]
|
185
|
+
pos = 0
|
186
|
+
catch(:next){
|
187
|
+
while true
|
188
|
+
case c[pos]
|
189
|
+
when IAC[0]
|
190
|
+
case c[pos+1]
|
191
|
+
when DO[0], DONT[0], WILL[0], WONT[0]
|
192
|
+
throw :next unless c[pos+2]
|
193
|
+
pos += 3
|
194
|
+
when SB[0]
|
195
|
+
ret = detect_sub_negotiation(c, pos)
|
196
|
+
throw :next unless ret
|
197
|
+
pos = ret
|
198
|
+
when nil
|
199
|
+
throw :next
|
200
|
+
else
|
201
|
+
pos += 2
|
202
|
+
end
|
203
|
+
when nil
|
204
|
+
throw :next
|
205
|
+
else
|
206
|
+
pos += 1
|
207
|
+
end
|
208
|
+
end
|
209
|
+
}
|
210
|
+
|
211
|
+
buf = preprocess(c[0...pos])
|
212
|
+
@rest = c[pos..-1]
|
213
|
+
end
|
214
|
+
@log.print(buf) if @options.has_key?("Output_log")
|
215
|
+
line.concat(buf)
|
216
|
+
yield buf if block_given?
|
217
|
+
rescue EOFError # End of file reached
|
218
|
+
if line == ''
|
219
|
+
line = nil
|
220
|
+
yield nil if block_given?
|
221
|
+
end
|
222
|
+
break
|
223
|
+
end
|
224
|
+
end
|
225
|
+
line
|
226
|
+
end
|
227
|
+
|
228
|
+
private
|
229
|
+
|
230
|
+
def detect_sub_negotiation(data, pos)
|
231
|
+
return nil if data.length < pos+6 # IAC SB x param IAC SE
|
232
|
+
pos += 3
|
233
|
+
while true
|
234
|
+
case data[pos]
|
235
|
+
when IAC[0]
|
236
|
+
if data[pos+1] == SE[0]
|
237
|
+
pos += 2
|
238
|
+
return pos
|
239
|
+
else
|
240
|
+
pos += 2
|
241
|
+
end
|
242
|
+
when nil
|
243
|
+
return nil
|
244
|
+
else
|
245
|
+
pos += 1
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
=begin
|
2
|
+
= $RCSfile$ -- PKCS7
|
3
|
+
|
4
|
+
= Licence
|
5
|
+
This program is licenced under the same licence as Ruby.
|
6
|
+
(See the file 'LICENCE'.)
|
7
|
+
|
8
|
+
= Version
|
9
|
+
$Id: digest.rb 12148 2007-04-05 05:59:22Z technorama $
|
10
|
+
=end
|
11
|
+
|
12
|
+
module OpenSSL
|
13
|
+
class PKCS7
|
14
|
+
# This class is only provided for backwards compatibility. Use OpenSSL::PKCS7 in the future.
|
15
|
+
class PKCS7 < PKCS7
|
16
|
+
def initialize(*args)
|
17
|
+
super(*args)
|
18
|
+
|
19
|
+
warn("Warning: OpenSSL::PKCS7::PKCS7 is deprecated after Ruby 1.9; use OpenSSL::PKCS7 instead")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end # PKCS7
|
24
|
+
end # OpenSSL
|
25
|
+
|
@@ -0,0 +1,187 @@
|
|
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"
|
19
|
+
|
20
|
+
module OpenSSL
|
21
|
+
module SSL
|
22
|
+
class SSLContext
|
23
|
+
DEFAULT_PARAMS = {
|
24
|
+
:ssl_version => "SSLv23",
|
25
|
+
:verify_mode => OpenSSL::SSL::VERIFY_PEER,
|
26
|
+
:ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW",
|
27
|
+
:options => OpenSSL::SSL::OP_ALL,
|
28
|
+
}
|
29
|
+
|
30
|
+
DEFAULT_CERT_STORE = OpenSSL::X509::Store.new
|
31
|
+
DEFAULT_CERT_STORE.set_default_paths
|
32
|
+
if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL)
|
33
|
+
DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_params(params={})
|
37
|
+
params = DEFAULT_PARAMS.merge(params)
|
38
|
+
# ssl_version need to be set at first.
|
39
|
+
self.ssl_version = params.delete(:ssl_version)
|
40
|
+
params.each{|name, value| self.__send__("#{name}=", value) }
|
41
|
+
if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
42
|
+
unless self.ca_file or self.ca_path or self.cert_store
|
43
|
+
self.cert_store = DEFAULT_CERT_STORE
|
44
|
+
end
|
45
|
+
end
|
46
|
+
return params
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module SocketForwarder
|
51
|
+
def addr
|
52
|
+
to_io.addr
|
53
|
+
end
|
54
|
+
|
55
|
+
def peeraddr
|
56
|
+
to_io.peeraddr
|
57
|
+
end
|
58
|
+
|
59
|
+
def setsockopt(level, optname, optval)
|
60
|
+
to_io.setsockopt(level, optname, optval)
|
61
|
+
end
|
62
|
+
|
63
|
+
def getsockopt(level, optname)
|
64
|
+
to_io.getsockopt(level, optname)
|
65
|
+
end
|
66
|
+
|
67
|
+
def fcntl(*args)
|
68
|
+
to_io.fcntl(*args)
|
69
|
+
end
|
70
|
+
|
71
|
+
def closed?
|
72
|
+
to_io.closed?
|
73
|
+
end
|
74
|
+
|
75
|
+
def do_not_reverse_lookup=(flag)
|
76
|
+
to_io.do_not_reverse_lookup = flag
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
module Nonblock
|
81
|
+
def initialize(*args)
|
82
|
+
flag = File::NONBLOCK
|
83
|
+
flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL)
|
84
|
+
@io.fcntl(Fcntl::F_SETFL, flag)
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def verify_certificate_identity(cert, hostname)
|
90
|
+
should_verify_common_name = true
|
91
|
+
cert.extensions.each{|ext|
|
92
|
+
next if ext.oid != "subjectAltName"
|
93
|
+
ostr = OpenSSL::ASN1.decode(ext.to_der).value.last
|
94
|
+
sequence = OpenSSL::ASN1.decode(ostr.value)
|
95
|
+
sequence.value.each{|san|
|
96
|
+
case san.tag
|
97
|
+
when 2 # dNSName in GeneralName (RFC5280)
|
98
|
+
should_verify_common_name = false
|
99
|
+
reg = Regexp.escape(san.value).gsub(/\\\*/, "[^.]+")
|
100
|
+
return true if /\A#{reg}\z/i =~ hostname
|
101
|
+
when 7 # iPAddress in GeneralName (RFC5280)
|
102
|
+
should_verify_common_name = false
|
103
|
+
# follows GENERAL_NAME_print() in x509v3/v3_alt.c
|
104
|
+
if san.value.size == 4
|
105
|
+
return true if san.value.unpack('C*').join('.') == hostname
|
106
|
+
elsif san.value.size == 16
|
107
|
+
return true if san.value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname
|
108
|
+
end
|
109
|
+
end
|
110
|
+
}
|
111
|
+
}
|
112
|
+
if should_verify_common_name
|
113
|
+
cert.subject.to_a.each{|oid, value|
|
114
|
+
if oid == "CN"
|
115
|
+
reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+")
|
116
|
+
return true if /\A#{reg}\z/i =~ hostname
|
117
|
+
end
|
118
|
+
}
|
119
|
+
end
|
120
|
+
return false
|
121
|
+
end
|
122
|
+
module_function :verify_certificate_identity
|
123
|
+
|
124
|
+
class SSLSocket
|
125
|
+
include Buffering
|
126
|
+
include SocketForwarder
|
127
|
+
include Nonblock
|
128
|
+
|
129
|
+
def post_connection_check(hostname)
|
130
|
+
unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
|
131
|
+
raise SSLError, "hostname was not match with the server certificate"
|
132
|
+
end
|
133
|
+
return true
|
134
|
+
end
|
135
|
+
|
136
|
+
def session
|
137
|
+
SSL::Session.new(self)
|
138
|
+
rescue SSL::Session::SessionError
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class SSLServer
|
144
|
+
include SocketForwarder
|
145
|
+
attr_accessor :start_immediately
|
146
|
+
|
147
|
+
def initialize(svr, ctx)
|
148
|
+
@svr = svr
|
149
|
+
@ctx = ctx
|
150
|
+
unless ctx.session_id_context
|
151
|
+
session_id = OpenSSL::Digest::MD5.hexdigest($0)
|
152
|
+
@ctx.session_id_context = session_id
|
153
|
+
end
|
154
|
+
@start_immediately = true
|
155
|
+
end
|
156
|
+
|
157
|
+
def to_io
|
158
|
+
@svr
|
159
|
+
end
|
160
|
+
|
161
|
+
def listen(backlog=5)
|
162
|
+
@svr.listen(backlog)
|
163
|
+
end
|
164
|
+
|
165
|
+
def shutdown(how=Socket::SHUT_RDWR)
|
166
|
+
@svr.shutdown(how)
|
167
|
+
end
|
168
|
+
|
169
|
+
def accept
|
170
|
+
sock = @svr.accept
|
171
|
+
begin
|
172
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
|
173
|
+
ssl.sync_close = true
|
174
|
+
ssl.accept if @start_immediately
|
175
|
+
ssl
|
176
|
+
rescue SSLError => ex
|
177
|
+
sock.close
|
178
|
+
raise ex
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def close
|
183
|
+
@svr.close
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|