sslshake 1.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/README.md +18 -0
- data/lib/sslshake.rb +73 -0
- data/lib/sslshake/ciphers.rb +360 -0
- data/lib/sslshake/common.rb +59 -0
- data/lib/sslshake/sslv2.rb +98 -0
- data/lib/sslshake/tls.rb +140 -0
- data/lib/sslshake/version.rb +7 -0
- data/sslshake.gemspec +18 -0
- metadata +58 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 73fea6614c1a8dac99abcc7e97607e4e33a2f4e1
|
4
|
+
data.tar.gz: 8ffbb4598f29d65b3b03c574641404f76f9ed85c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c6ee7096edd757778e9b13a8a4090ce4f3982762373132213cc8b605bf7129032a63c44351ccebcaf11a2f5f9f32766269e7c2713703f8fcc0164a77f3be9ca7
|
7
|
+
data.tar.gz: 278ea0a3d288c0d636fe4bb12c34f36bf5be30859e09636932bc45ded810cf8aefd38b8c04a5a3d62b5aad46184a739f3fbaf480aed3c57f227c79ec8f7405ea
|
data/.gitignore
ADDED
data/README.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# sslshake
|
2
|
+
|
3
|
+
Tiny Ruby library to simulate SSL and TLS handshakes. Independent of OpenSSL. Supports SSLv2, SSLv3, TLS 1.0 - 1.2.
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
* Ruby v1.9.3+
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require 'sslshake'
|
13
|
+
SSLShake.hello('my.host', port: 4443, protocol: 'tls1.2')
|
14
|
+
```
|
15
|
+
|
16
|
+
## License
|
17
|
+
|
18
|
+
MPLv2, see [https://www.mozilla.org/en-US/MPL/2.0/](https://www.mozilla.org/en-US/MPL/2.0/)
|
data/lib/sslshake.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# copyright: 2016, Dominik Richter
|
3
|
+
# license: MPLv2
|
4
|
+
|
5
|
+
require 'socket'
|
6
|
+
require 'securerandom'
|
7
|
+
require 'io/wait'
|
8
|
+
require 'sslshake/version'
|
9
|
+
require 'sslshake/ciphers'
|
10
|
+
require 'sslshake/sslv2'
|
11
|
+
require 'sslshake/tls'
|
12
|
+
|
13
|
+
module SSLShake
|
14
|
+
def self.socket(host, opts = {})
|
15
|
+
return [opts[:socket], nil] unless opts[:socket].nil?
|
16
|
+
|
17
|
+
port = opts[:port] || 443
|
18
|
+
timeout = opts[:timeout] || 2
|
19
|
+
|
20
|
+
addr = Socket.getaddrinfo(host, nil)[0] ||
|
21
|
+
fail("Cannot determine address for socket to #{host}:#{port}")
|
22
|
+
family = addr[4]
|
23
|
+
|
24
|
+
sockaddr = Socket.pack_sockaddr_in(port, addr[2])
|
25
|
+
socket = Socket.new(family, Socket::SOCK_STREAM, 0)
|
26
|
+
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
27
|
+
|
28
|
+
begin
|
29
|
+
socket.connect_nonblock(sockaddr)
|
30
|
+
rescue IO::WaitWritable
|
31
|
+
if IO.select(nil, [socket], nil, timeout)
|
32
|
+
begin
|
33
|
+
socket.connect_nonblock(sockaddr)
|
34
|
+
rescue Errno::EISCONN
|
35
|
+
true # done, it's connected
|
36
|
+
rescue => err
|
37
|
+
socket.close
|
38
|
+
return [nil, "Connection error #{err.class}, can't connect to #{host}:#{port}."]
|
39
|
+
end
|
40
|
+
else
|
41
|
+
socket.close
|
42
|
+
return [nil, "Connection timeout after #{timeout}, can't connect to #{host}:#{port}."]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
[socket, nil]
|
47
|
+
rescue SystemCallError, Alert => _
|
48
|
+
return [nil, "Connection refused, can't connect to #{host}:#{port}."]
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.hello(host, opts = {})
|
52
|
+
cur_socket = opts[:socket]
|
53
|
+
if cur_socket.nil?
|
54
|
+
cur_socket, error = socket(host, opts)
|
55
|
+
return { 'error' => error } unless error.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
protocol = opts[:protocol] || 'tls1.2'
|
59
|
+
if protocol == 'ssl2'
|
60
|
+
ssl = SSLShake::SSLv2.new
|
61
|
+
cur_socket.send(ssl.hello(opts[:ciphers]), 0)
|
62
|
+
else
|
63
|
+
ssl = SSLShake::TLS.new
|
64
|
+
cur_socket.send(ssl.hello(protocol, opts[:ciphers]), 0)
|
65
|
+
end
|
66
|
+
|
67
|
+
res = ssl.parse_hello(cur_socket, opts)
|
68
|
+
cur_socket.close if opts[:socket].nil?
|
69
|
+
res
|
70
|
+
rescue SystemCallError => _
|
71
|
+
return { 'error' => 'Failed to send hello. Socket closed.' }
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,360 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# copyright: 2015, Dominik Richter
|
3
|
+
# license: MPLv2
|
4
|
+
|
5
|
+
module SSLShake # rubocop:disable Metrics/ModuleLength
|
6
|
+
CIPHERS = {
|
7
|
+
'010080' => 'SSL_CK_RC4_128_WITH_MD5',
|
8
|
+
'020080' => 'SSL_CK_RC4_128_EXPORT40_WITH_MD5',
|
9
|
+
'030080' => 'SSL_CK_RC2_128_CBC_WITH_MD5',
|
10
|
+
'040080' => 'SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5',
|
11
|
+
'050080' => 'SSL_CK_IDEA_128_CBC_WITH_MD5',
|
12
|
+
'060040' => 'SSL_CK_DES_64_CBC_WITH_MD5',
|
13
|
+
'0700C0' => 'SSL_CK_DES_192_EDE3_CBC_WITH_MD5',
|
14
|
+
'080080' => 'SSL_CK_RC4_64_WITH_MD5',
|
15
|
+
'0000' => 'TLS_NULL_WITH_NULL_NULL',
|
16
|
+
'0001' => 'TLS_RSA_WITH_NULL_MD5',
|
17
|
+
'0002' => 'TLS_RSA_WITH_NULL_SHA',
|
18
|
+
'0003' => 'TLS_RSA_EXPORT_WITH_RC4_40_MD5',
|
19
|
+
'0004' => 'TLS_RSA_WITH_RC4_128_MD5',
|
20
|
+
'0005' => 'TLS_RSA_WITH_RC4_128_SHA',
|
21
|
+
'0006' => 'TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5',
|
22
|
+
'0007' => 'TLS_RSA_WITH_IDEA_CBC_SHA',
|
23
|
+
'0008' => 'TLS_RSA_EXPORT_WITH_DES40_CBC_SHA',
|
24
|
+
'0009' => 'TLS_RSA_WITH_DES_CBC_SHA',
|
25
|
+
'000A' => 'TLS_RSA_WITH_3DES_EDE_CBC_SHA',
|
26
|
+
'000B' => 'TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA',
|
27
|
+
'000C' => 'TLS_DH_DSS_WITH_DES_CBC_SHA',
|
28
|
+
'000D' => 'TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA',
|
29
|
+
'000E' => 'TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA',
|
30
|
+
'000F' => 'TLS_DH_RSA_WITH_DES_CBC_SHA',
|
31
|
+
'0010' => 'TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA',
|
32
|
+
'0011' => 'TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA',
|
33
|
+
'0012' => 'TLS_DHE_DSS_WITH_DES_CBC_SHA',
|
34
|
+
'0013' => 'TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA',
|
35
|
+
'0014' => 'TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA',
|
36
|
+
'0015' => 'TLS_DHE_RSA_WITH_DES_CBC_SHA',
|
37
|
+
'0016' => 'TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA',
|
38
|
+
'0017' => 'TLS_DH_anon_EXPORT_WITH_RC4_40_MD5',
|
39
|
+
'0018' => 'TLS_DH_anon_WITH_RC4_128_MD5',
|
40
|
+
'0019' => 'TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA',
|
41
|
+
'001A' => 'TLS_DH_anon_WITH_DES_CBC_SHA',
|
42
|
+
'001B' => 'TLS_DH_anon_WITH_3DES_EDE_CBC_SHA',
|
43
|
+
'001E' => 'TLS_KRB5_WITH_DES_CBC_SHA',
|
44
|
+
'001F' => 'TLS_KRB5_WITH_3DES_EDE_CBC_SHA',
|
45
|
+
'0020' => 'TLS_KRB5_WITH_RC4_128_SHA',
|
46
|
+
'0021' => 'TLS_KRB5_WITH_IDEA_CBC_SHA',
|
47
|
+
'0022' => 'TLS_KRB5_WITH_DES_CBC_MD5',
|
48
|
+
'0023' => 'TLS_KRB5_WITH_3DES_EDE_CBC_MD5',
|
49
|
+
'0024' => 'TLS_KRB5_WITH_RC4_128_MD5',
|
50
|
+
'0025' => 'TLS_KRB5_WITH_IDEA_CBC_MD5',
|
51
|
+
'0026' => 'TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA',
|
52
|
+
'0027' => 'TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA',
|
53
|
+
'0028' => 'TLS_KRB5_EXPORT_WITH_RC4_40_SHA',
|
54
|
+
'0029' => 'TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5',
|
55
|
+
'002A' => 'TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5',
|
56
|
+
'002B' => 'TLS_KRB5_EXPORT_WITH_RC4_40_MD5',
|
57
|
+
'002C' => 'TLS_PSK_WITH_NULL_SHA',
|
58
|
+
'002D' => 'TLS_DHE_PSK_WITH_NULL_SHA',
|
59
|
+
'002E' => 'TLS_RSA_PSK_WITH_NULL_SHA',
|
60
|
+
'002F' => 'TLS_RSA_WITH_AES_128_CBC_SHA',
|
61
|
+
'0030' => 'TLS_DH_DSS_WITH_AES_128_CBC_SHA',
|
62
|
+
'0031' => 'TLS_DH_RSA_WITH_AES_128_CBC_SHA',
|
63
|
+
'0032' => 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA',
|
64
|
+
'0033' => 'TLS_DHE_RSA_WITH_AES_128_CBC_SHA',
|
65
|
+
'0034' => 'TLS_DH_anon_WITH_AES_128_CBC_SHA',
|
66
|
+
'0035' => 'TLS_RSA_WITH_AES_256_CBC_SHA',
|
67
|
+
'0036' => 'TLS_DH_DSS_WITH_AES_256_CBC_SHA',
|
68
|
+
'0037' => 'TLS_DH_RSA_WITH_AES_256_CBC_SHA',
|
69
|
+
'0038' => 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA',
|
70
|
+
'0039' => 'TLS_DHE_RSA_WITH_AES_256_CBC_SHA',
|
71
|
+
'003A' => 'TLS_DH_anon_WITH_AES_256_CBC_SHA',
|
72
|
+
'003B' => 'TLS_RSA_WITH_NULL_SHA256',
|
73
|
+
'003C' => 'TLS_RSA_WITH_AES_128_CBC_SHA256',
|
74
|
+
'003D' => 'TLS_RSA_WITH_AES_256_CBC_SHA256',
|
75
|
+
'003E' => 'TLS_DH_DSS_WITH_AES_128_CBC_SHA256',
|
76
|
+
'003F' => 'TLS_DH_RSA_WITH_AES_128_CBC_SHA256',
|
77
|
+
'0040' => 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA256',
|
78
|
+
'0041' => 'TLS_RSA_WITH_CAMELLIA_128_CBC_SHA',
|
79
|
+
'0042' => 'TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA',
|
80
|
+
'0043' => 'TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA',
|
81
|
+
'0044' => 'TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA',
|
82
|
+
'0045' => 'TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA',
|
83
|
+
'0046' => 'TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA',
|
84
|
+
'0060' => 'TLS_RSA_EXPORT1024_WITH_RC4_56_MD5',
|
85
|
+
'0061' => 'TLS_RSA_EXPORT1024_WITH_RC2_56_MD5',
|
86
|
+
'0062' => 'TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA',
|
87
|
+
'0063' => 'TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA',
|
88
|
+
'0064' => 'TLS_RSA_EXPORT1024_WITH_RC4_56_SHA',
|
89
|
+
'0065' => 'TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA',
|
90
|
+
'0066' => 'TLS_DHE_DSS_WITH_RC4_128_SHA',
|
91
|
+
'0067' => 'TLS_DHE_RSA_WITH_AES_128_CBC_SHA256',
|
92
|
+
'0068' => 'TLS_DH_DSS_WITH_AES_256_CBC_SHA256',
|
93
|
+
'0069' => 'TLS_DH_RSA_WITH_AES_256_CBC_SHA256',
|
94
|
+
'006A' => 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA256',
|
95
|
+
'006B' => 'TLS_DHE_RSA_WITH_AES_256_CBC_SHA256',
|
96
|
+
'006C' => 'TLS_DH_anon_WITH_AES_128_CBC_SHA256',
|
97
|
+
'006D' => 'TLS_DH_anon_WITH_AES_256_CBC_SHA256',
|
98
|
+
'0080' => 'TLS_GOSTR341094_WITH_28147_CNT_IMIT',
|
99
|
+
'0081' => 'TLS_GOSTR341001_WITH_28147_CNT_IMIT',
|
100
|
+
'0082' => 'TLS_GOSTR341094_WITH_NULL_GOSTR3411',
|
101
|
+
'0083' => 'TLS_GOSTR341001_WITH_NULL_GOSTR3411',
|
102
|
+
'0084' => 'TLS_RSA_WITH_CAMELLIA_256_CBC_SHA',
|
103
|
+
'0085' => 'TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA',
|
104
|
+
'0086' => 'TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA',
|
105
|
+
'0087' => 'TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA',
|
106
|
+
'0088' => 'TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA',
|
107
|
+
'0089' => 'TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA',
|
108
|
+
'008A' => 'TLS_PSK_WITH_RC4_128_SHA',
|
109
|
+
'008B' => 'TLS_PSK_WITH_3DES_EDE_CBC_SHA',
|
110
|
+
'008C' => 'TLS_PSK_WITH_AES_128_CBC_SHA',
|
111
|
+
'008D' => 'TLS_PSK_WITH_AES_256_CBC_SHA',
|
112
|
+
'008E' => 'TLS_DHE_PSK_WITH_RC4_128_SHA',
|
113
|
+
'008F' => 'TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA',
|
114
|
+
'0090' => 'TLS_DHE_PSK_WITH_AES_128_CBC_SHA',
|
115
|
+
'0091' => 'TLS_DHE_PSK_WITH_AES_256_CBC_SHA',
|
116
|
+
'0092' => 'TLS_RSA_PSK_WITH_RC4_128_SHA',
|
117
|
+
'0093' => 'TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA',
|
118
|
+
'0094' => 'TLS_RSA_PSK_WITH_AES_128_CBC_SHA',
|
119
|
+
'0095' => 'TLS_RSA_PSK_WITH_AES_256_CBC_SHA',
|
120
|
+
'0096' => 'TLS_RSA_WITH_SEED_CBC_SHA',
|
121
|
+
'0097' => 'TLS_DH_DSS_WITH_SEED_CBC_SHA',
|
122
|
+
'0098' => 'TLS_DH_RSA_WITH_SEED_CBC_SHA',
|
123
|
+
'0099' => 'TLS_DHE_DSS_WITH_SEED_CBC_SHA',
|
124
|
+
'009A' => 'TLS_DHE_RSA_WITH_SEED_CBC_SHA',
|
125
|
+
'009B' => 'TLS_DH_anon_WITH_SEED_CBC_SHA',
|
126
|
+
'009C' => 'TLS_RSA_WITH_AES_128_GCM_SHA256',
|
127
|
+
'009D' => 'TLS_RSA_WITH_AES_256_GCM_SHA384',
|
128
|
+
'009E' => 'TLS_DHE_RSA_WITH_AES_128_GCM_SHA256',
|
129
|
+
'009F' => 'TLS_DHE_RSA_WITH_AES_256_GCM_SHA384',
|
130
|
+
'00A0' => 'TLS_DH_RSA_WITH_AES_128_GCM_SHA256',
|
131
|
+
'00A1' => 'TLS_DH_RSA_WITH_AES_256_GCM_SHA384',
|
132
|
+
'00A2' => 'TLS_DHE_DSS_WITH_AES_128_GCM_SHA256',
|
133
|
+
'00A3' => 'TLS_DHE_DSS_WITH_AES_256_GCM_SHA384',
|
134
|
+
'00A4' => 'TLS_DH_DSS_WITH_AES_128_GCM_SHA256',
|
135
|
+
'00A5' => 'TLS_DH_DSS_WITH_AES_256_GCM_SHA384',
|
136
|
+
'00A6' => 'TLS_DH_anon_WITH_AES_128_GCM_SHA256',
|
137
|
+
'00A7' => 'TLS_DH_anon_WITH_AES_256_GCM_SHA384',
|
138
|
+
'00A8' => 'TLS_PSK_WITH_AES_128_GCM_SHA256',
|
139
|
+
'00A9' => 'TLS_PSK_WITH_AES_256_GCM_SHA384',
|
140
|
+
'00AA' => 'TLS_DHE_PSK_WITH_AES_128_GCM_SHA256',
|
141
|
+
'00AB' => 'TLS_DHE_PSK_WITH_AES_256_GCM_SHA384',
|
142
|
+
'00AC' => 'TLS_RSA_PSK_WITH_AES_128_GCM_SHA256',
|
143
|
+
'00AD' => 'TLS_RSA_PSK_WITH_AES_256_GCM_SHA384',
|
144
|
+
'00AE' => 'TLS_PSK_WITH_AES_128_CBC_SHA256',
|
145
|
+
'00AF' => 'TLS_PSK_WITH_AES_256_CBC_SHA384',
|
146
|
+
'00B0' => 'TLS_PSK_WITH_NULL_SHA256',
|
147
|
+
'00B1' => 'TLS_PSK_WITH_NULL_SHA384',
|
148
|
+
'00B2' => 'TLS_DHE_PSK_WITH_AES_128_CBC_SHA256',
|
149
|
+
'00B3' => 'TLS_DHE_PSK_WITH_AES_256_CBC_SHA384',
|
150
|
+
'00B4' => 'TLS_DHE_PSK_WITH_NULL_SHA256',
|
151
|
+
'00B5' => 'TLS_DHE_PSK_WITH_NULL_SHA384',
|
152
|
+
'00B6' => 'TLS_RSA_PSK_WITH_AES_128_CBC_SHA256',
|
153
|
+
'00B7' => 'TLS_RSA_PSK_WITH_AES_256_CBC_SHA384',
|
154
|
+
'00B8' => 'TLS_RSA_PSK_WITH_NULL_SHA256',
|
155
|
+
'00B9' => 'TLS_RSA_PSK_WITH_NULL_SHA384',
|
156
|
+
'00BA' => 'TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256',
|
157
|
+
'00BB' => 'TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256',
|
158
|
+
'00BC' => 'TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256',
|
159
|
+
'00BD' => 'TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256',
|
160
|
+
'00BE' => 'TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256',
|
161
|
+
'00BF' => 'TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256',
|
162
|
+
'00C0' => 'TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256',
|
163
|
+
'00C1' => 'TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256',
|
164
|
+
'00C2' => 'TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256',
|
165
|
+
'00C3' => 'TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256',
|
166
|
+
'00C4' => 'TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256',
|
167
|
+
'00C5' => 'TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256',
|
168
|
+
'00FF' => 'TLS_EMPTY_RENEGOTIATION_INFO_SCSV',
|
169
|
+
'5600' => 'TLS_FALLBACK_SCSV',
|
170
|
+
'C001' => 'TLS_ECDH_ECDSA_WITH_NULL_SHA',
|
171
|
+
'C002' => 'TLS_ECDH_ECDSA_WITH_RC4_128_SHA',
|
172
|
+
'C003' => 'TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA',
|
173
|
+
'C004' => 'TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA',
|
174
|
+
'C005' => 'TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA',
|
175
|
+
'C006' => 'TLS_ECDHE_ECDSA_WITH_NULL_SHA',
|
176
|
+
'C007' => 'TLS_ECDHE_ECDSA_WITH_RC4_128_SHA',
|
177
|
+
'C008' => 'TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA',
|
178
|
+
'C009' => 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA',
|
179
|
+
'C00A' => 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA',
|
180
|
+
'C00B' => 'TLS_ECDH_RSA_WITH_NULL_SHA',
|
181
|
+
'C00C' => 'TLS_ECDH_RSA_WITH_RC4_128_SHA',
|
182
|
+
'C00D' => 'TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA',
|
183
|
+
'C00E' => 'TLS_ECDH_RSA_WITH_AES_128_CBC_SHA',
|
184
|
+
'C00F' => 'TLS_ECDH_RSA_WITH_AES_256_CBC_SHA',
|
185
|
+
'C010' => 'TLS_ECDHE_RSA_WITH_NULL_SHA',
|
186
|
+
'C011' => 'TLS_ECDHE_RSA_WITH_RC4_128_SHA',
|
187
|
+
'C012' => 'TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA',
|
188
|
+
'C013' => 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA',
|
189
|
+
'C014' => 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA',
|
190
|
+
'C015' => 'TLS_ECDH_anon_WITH_NULL_SHA',
|
191
|
+
'C016' => 'TLS_ECDH_anon_WITH_RC4_128_SHA',
|
192
|
+
'C017' => 'TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA',
|
193
|
+
'C018' => 'TLS_ECDH_anon_WITH_AES_128_CBC_SHA',
|
194
|
+
'C019' => 'TLS_ECDH_anon_WITH_AES_256_CBC_SHA',
|
195
|
+
'C01A' => 'TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA',
|
196
|
+
'C01B' => 'TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA',
|
197
|
+
'C01C' => 'TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA',
|
198
|
+
'C01D' => 'TLS_SRP_SHA_WITH_AES_128_CBC_SHA',
|
199
|
+
'C01E' => 'TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA',
|
200
|
+
'C01F' => 'TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA',
|
201
|
+
'C020' => 'TLS_SRP_SHA_WITH_AES_256_CBC_SHA',
|
202
|
+
'C021' => 'TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA',
|
203
|
+
'C022' => 'TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA',
|
204
|
+
'C023' => 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256',
|
205
|
+
'C024' => 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384',
|
206
|
+
'C025' => 'TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256',
|
207
|
+
'C026' => 'TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384',
|
208
|
+
'C027' => 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256',
|
209
|
+
'C028' => 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384',
|
210
|
+
'C029' => 'TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256',
|
211
|
+
'C02A' => 'TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384',
|
212
|
+
'C02B' => 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',
|
213
|
+
'C02C' => 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384',
|
214
|
+
'C02D' => 'TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256',
|
215
|
+
'C02E' => 'TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384',
|
216
|
+
'C02F' => 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256',
|
217
|
+
'C030' => 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384',
|
218
|
+
'C031' => 'TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256',
|
219
|
+
'C032' => 'TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384',
|
220
|
+
'C033' => 'TLS_ECDHE_PSK_WITH_RC4_128_SHA',
|
221
|
+
'C034' => 'TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA',
|
222
|
+
'C035' => 'TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA',
|
223
|
+
'C036' => 'TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA',
|
224
|
+
'C037' => 'TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256',
|
225
|
+
'C038' => 'TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384',
|
226
|
+
'C039' => 'TLS_ECDHE_PSK_WITH_NULL_SHA',
|
227
|
+
'C03A' => 'TLS_ECDHE_PSK_WITH_NULL_SHA256',
|
228
|
+
'C03B' => 'TLS_ECDHE_PSK_WITH_NULL_SHA384',
|
229
|
+
'C03C' => 'TLS_RSA_WITH_ARIA_128_CBC_SHA256',
|
230
|
+
'C03D' => 'TLS_RSA_WITH_ARIA_256_CBC_SHA384',
|
231
|
+
'C03E' => 'TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256',
|
232
|
+
'C03F' => 'TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384',
|
233
|
+
'C040' => 'TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256',
|
234
|
+
'C041' => 'TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384',
|
235
|
+
'C042' => 'TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256',
|
236
|
+
'C043' => 'TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384',
|
237
|
+
'C044' => 'TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256',
|
238
|
+
'C045' => 'TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384',
|
239
|
+
'C046' => 'TLS_DH_anon_WITH_ARIA_128_CBC_SHA256',
|
240
|
+
'C047' => 'TLS_DH_anon_WITH_ARIA_256_CBC_SHA384',
|
241
|
+
'C048' => 'TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256',
|
242
|
+
'C049' => 'TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384',
|
243
|
+
'C04A' => 'TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256',
|
244
|
+
'C04B' => 'TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384',
|
245
|
+
'C04C' => 'TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256',
|
246
|
+
'C04D' => 'TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384',
|
247
|
+
'C04E' => 'TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256',
|
248
|
+
'C04F' => 'TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384',
|
249
|
+
'C050' => 'TLS_RSA_WITH_ARIA_128_GCM_SHA256',
|
250
|
+
'C051' => 'TLS_RSA_WITH_ARIA_256_GCM_SHA384',
|
251
|
+
'C052' => 'TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256',
|
252
|
+
'C053' => 'TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384',
|
253
|
+
'C054' => 'TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256',
|
254
|
+
'C055' => 'TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384',
|
255
|
+
'C056' => 'TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256',
|
256
|
+
'C057' => 'TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384',
|
257
|
+
'C058' => 'TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256',
|
258
|
+
'C059' => 'TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384',
|
259
|
+
'C05A' => 'TLS_DH_anon_WITH_ARIA_128_GCM_SHA256',
|
260
|
+
'C05B' => 'TLS_DH_anon_WITH_ARIA_256_GCM_SHA384',
|
261
|
+
'C05C' => 'TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256',
|
262
|
+
'C05D' => 'TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384',
|
263
|
+
'C05E' => 'TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256',
|
264
|
+
'C05F' => 'TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384',
|
265
|
+
'C060' => 'TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256',
|
266
|
+
'C061' => 'TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384',
|
267
|
+
'C062' => 'TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256',
|
268
|
+
'C063' => 'TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384',
|
269
|
+
'C064' => 'TLS_PSK_WITH_ARIA_128_CBC_SHA256',
|
270
|
+
'C065' => 'TLS_PSK_WITH_ARIA_256_CBC_SHA384',
|
271
|
+
'C066' => 'TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256',
|
272
|
+
'C067' => 'TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384',
|
273
|
+
'C068' => 'TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256',
|
274
|
+
'C069' => 'TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384',
|
275
|
+
'C06A' => 'TLS_PSK_WITH_ARIA_128_GCM_SHA256',
|
276
|
+
'C06B' => 'TLS_PSK_WITH_ARIA_256_GCM_SHA384',
|
277
|
+
'C06C' => 'TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256',
|
278
|
+
'C06D' => 'TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384',
|
279
|
+
'C06E' => 'TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256',
|
280
|
+
'C06F' => 'TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384',
|
281
|
+
'C070' => 'TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256',
|
282
|
+
'C071' => 'TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384',
|
283
|
+
'C072' => 'TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256',
|
284
|
+
'C073' => 'TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384',
|
285
|
+
'C074' => 'TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256',
|
286
|
+
'C075' => 'TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384',
|
287
|
+
'C076' => 'TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256',
|
288
|
+
'C077' => 'TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384',
|
289
|
+
'C078' => 'TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256',
|
290
|
+
'C079' => 'TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384',
|
291
|
+
'C07A' => 'TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256',
|
292
|
+
'C07B' => 'TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384',
|
293
|
+
'C07C' => 'TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256',
|
294
|
+
'C07D' => 'TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384',
|
295
|
+
'C07E' => 'TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256',
|
296
|
+
'C07F' => 'TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384',
|
297
|
+
'C080' => 'TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256',
|
298
|
+
'C081' => 'TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384',
|
299
|
+
'C082' => 'TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256',
|
300
|
+
'C083' => 'TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384',
|
301
|
+
'C084' => 'TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256',
|
302
|
+
'C085' => 'TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384',
|
303
|
+
'C086' => 'TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256',
|
304
|
+
'C087' => 'TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384',
|
305
|
+
'C088' => 'TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256',
|
306
|
+
'C089' => 'TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384',
|
307
|
+
'C08A' => 'TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256',
|
308
|
+
'C08B' => 'TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384',
|
309
|
+
'C08C' => 'TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256',
|
310
|
+
'C08D' => 'TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384',
|
311
|
+
'C08E' => 'TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256',
|
312
|
+
'C08F' => 'TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384',
|
313
|
+
'C090' => 'TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256',
|
314
|
+
'C091' => 'TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384',
|
315
|
+
'C092' => 'TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256',
|
316
|
+
'C093' => 'TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384',
|
317
|
+
'C094' => 'TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256',
|
318
|
+
'C095' => 'TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384',
|
319
|
+
'C096' => 'TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256',
|
320
|
+
'C097' => 'TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384',
|
321
|
+
'C098' => 'TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256',
|
322
|
+
'C099' => 'TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384',
|
323
|
+
'C09A' => 'TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256',
|
324
|
+
'C09B' => 'TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384',
|
325
|
+
'C09C' => 'TLS_RSA_WITH_AES_128_CCM',
|
326
|
+
'C09D' => 'TLS_RSA_WITH_AES_256_CCM',
|
327
|
+
'C09E' => 'TLS_DHE_RSA_WITH_AES_128_CCM',
|
328
|
+
'C09F' => 'TLS_DHE_RSA_WITH_AES_256_CCM',
|
329
|
+
'C0A0' => 'TLS_RSA_WITH_AES_128_CCM_8',
|
330
|
+
'C0A1' => 'TLS_RSA_WITH_AES_256_CCM_8',
|
331
|
+
'C0A2' => 'TLS_DHE_RSA_WITH_AES_128_CCM_8',
|
332
|
+
'C0A3' => 'TLS_DHE_RSA_WITH_AES_256_CCM_8',
|
333
|
+
'C0A4' => 'TLS_PSK_WITH_AES_128_CCM',
|
334
|
+
'C0A5' => 'TLS_PSK_WITH_AES_256_CCM',
|
335
|
+
'C0A6' => 'TLS_DHE_PSK_WITH_AES_128_CCM',
|
336
|
+
'C0A7' => 'TLS_DHE_PSK_WITH_AES_256_CCM',
|
337
|
+
'C0A8' => 'TLS_PSK_WITH_AES_128_CCM_8',
|
338
|
+
'C0A9' => 'TLS_PSK_WITH_AES_256_CCM_8',
|
339
|
+
'C0AA' => 'TLS_PSK_DHE_WITH_AES_128_CCM_8',
|
340
|
+
'C0AB' => 'TLS_PSK_DHE_WITH_AES_256_CCM_8',
|
341
|
+
'C0AC' => 'TLS_ECDHE_ECDSA_WITH_AES_128_CCM',
|
342
|
+
'C0AD' => 'TLS_ECDHE_ECDSA_WITH_AES_256_CCM',
|
343
|
+
'C0AE' => 'TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8',
|
344
|
+
'C0AF' => 'TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8',
|
345
|
+
'CCA8' => 'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305',
|
346
|
+
'CCA9' => 'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305',
|
347
|
+
'CCAA' => 'TLS_DHE_RSA_WITH_CHACHA20_POLY1305',
|
348
|
+
'CCAB' => 'TLS_PSK_WITH_CHACHA20_POLY1305',
|
349
|
+
'CCAC' => 'TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305',
|
350
|
+
'CCAD' => 'TLS_DHE_PSK_WITH_CHACHA20_POLY1305',
|
351
|
+
'CCAE' => 'TLS_RSA_PSK_WITH_CHACHA20_POLY1305',
|
352
|
+
'CC13' => 'OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256',
|
353
|
+
'CC14' => 'OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256',
|
354
|
+
'CC15' => 'OLD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256',
|
355
|
+
'FEFE' => 'SSL_RSA_FIPS_WITH_DES_CBC_SHA',
|
356
|
+
'FEFF' => 'SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA',
|
357
|
+
'FFE0' => 'SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA',
|
358
|
+
'FFE1' => 'SSL_RSA_FIPS_WITH_DES_CBC_SHA',
|
359
|
+
}.invert.freeze
|
360
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# copyright: 2016, Dominik Richter
|
3
|
+
# license: MPLv2
|
4
|
+
|
5
|
+
module SSLShake
|
6
|
+
class Alert < ::StandardError; end
|
7
|
+
class UserError < ::StandardError; end
|
8
|
+
class NotYetImplementedError < ::StandardError; end
|
9
|
+
|
10
|
+
module CommonHelpers
|
11
|
+
def int_bytes(i, len = 1)
|
12
|
+
format("%0#{len * 2}x", i)
|
13
|
+
end
|
14
|
+
|
15
|
+
def socket_read(socket, bytes, timeout, retries)
|
16
|
+
timeout ||= 1
|
17
|
+
retries ||= 2
|
18
|
+
if socket.closed?
|
19
|
+
fail Alert, 'No response, socket is closed.'
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
res = socket.read_nonblock(bytes)
|
24
|
+
rescue IO::WaitReadable
|
25
|
+
IO.select([socket], nil, nil, timeout)
|
26
|
+
retries -= 1
|
27
|
+
retry if retries >= 0
|
28
|
+
raise Alert, 'Timeout while reading data.'
|
29
|
+
rescue IO::WaitWritable
|
30
|
+
IO.select(nil, [socket], nil, timeout)
|
31
|
+
retries -= 1
|
32
|
+
retry if retries >= 0
|
33
|
+
raise Alert, 'Timeout while waiting for socket to be writable.'
|
34
|
+
rescue EOFError
|
35
|
+
raise Alert, 'Failed to read, EOF reached.'
|
36
|
+
end
|
37
|
+
|
38
|
+
fail Alert, 'No data received' if res.nil?
|
39
|
+
res
|
40
|
+
end
|
41
|
+
|
42
|
+
def cipher_string(ciphers, search)
|
43
|
+
case search
|
44
|
+
when Proc
|
45
|
+
ciphers.select(&search).values.join
|
46
|
+
when String
|
47
|
+
ciphers[search] || search
|
48
|
+
when Regexp
|
49
|
+
ciphers.select { |k, _| k =~ search }.values.join
|
50
|
+
when Array
|
51
|
+
search.map { |i| cipher_string(ciphers, i) }.join
|
52
|
+
when nil
|
53
|
+
ciphers.values.join
|
54
|
+
else
|
55
|
+
fail UserError, 'Please provide a search string, regex, or list for SSL ciphers.'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# copyright: 2016, Dominik Richter
|
3
|
+
# license: MPLv2
|
4
|
+
|
5
|
+
require 'sslshake/common'
|
6
|
+
require 'sslshake/ciphers'
|
7
|
+
|
8
|
+
module SSLShake
|
9
|
+
class SSLv2
|
10
|
+
# https://tools.ietf.org/html/draft-hickman-netscape-ssl-00
|
11
|
+
# http://www.homeport.org/~adam/ssl.html
|
12
|
+
include CommonHelpers
|
13
|
+
|
14
|
+
VERSIONS = {
|
15
|
+
'ssl2' => '0002',
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
CIPHERS = ::SSLShake::CIPHERS.select { |k, _| k.start_with? 'SSL_CK_' }
|
19
|
+
|
20
|
+
MESSAGE_TYPES = {
|
21
|
+
'ERROR' => '00',
|
22
|
+
'CLIENT_HELLO' => '01',
|
23
|
+
'CLIENT_MASTER_KEY' => '02',
|
24
|
+
'CLIENT_FINISHED' => '03',
|
25
|
+
'SERVER_HELLO' => '04',
|
26
|
+
'SERVER_VERIFY' => '05',
|
27
|
+
'SERVER_FINISHED' => '06',
|
28
|
+
'REQUEST_CERTIFICATE' => '07',
|
29
|
+
'CLIENT_CERTIFICATE' => '08',
|
30
|
+
}.freeze
|
31
|
+
|
32
|
+
def hello(cipher_search = nil)
|
33
|
+
ciphers = cipher_string(CIPHERS, cipher_search)
|
34
|
+
challenge = SecureRandom.hex(16)
|
35
|
+
content = MESSAGE_TYPES['CLIENT_HELLO'] +
|
36
|
+
VERSIONS['ssl2'] +
|
37
|
+
int_bytes(ciphers.length / 2, 2) +
|
38
|
+
'0000' + # session id length
|
39
|
+
int_bytes(challenge.length / 2, 2) +
|
40
|
+
ciphers +
|
41
|
+
challenge
|
42
|
+
length = int_bytes((content.length / 2) | 0x8000, 2)
|
43
|
+
res = length + content
|
44
|
+
[res].pack('H*')
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse_hello(socket, opts)
|
48
|
+
res = {}
|
49
|
+
head = socket_read(socket, 2, opts[:timeout], opts[:retries])
|
50
|
+
.unpack('H*')[0].upcase.to_i(16)
|
51
|
+
if (head & 0x8000) == 0
|
52
|
+
fail NotYetImplementedError, 'Cannot yet handle SSLv2 responses with first bit set to 0'
|
53
|
+
end
|
54
|
+
|
55
|
+
len = head & 0x7fff
|
56
|
+
res['raw'] = response = socket.read(len).unpack('H*')[0].upcase
|
57
|
+
raw = response.scan(/../)
|
58
|
+
|
59
|
+
res['message_type'] = MESSAGE_TYPES.key(raw.shift)
|
60
|
+
if res['message_type'] == 'ERROR'
|
61
|
+
fail Alert, 'SSL handshake responded with an error.'
|
62
|
+
end
|
63
|
+
|
64
|
+
res['session_id_hit'] = raw.shift
|
65
|
+
res['cert_type'] = raw.shift
|
66
|
+
version = raw.shift(2).join
|
67
|
+
res['version'] = VERSIONS.key(version)
|
68
|
+
if res['version'].nil?
|
69
|
+
fail Alert, 'This does not look like a valid SSLv2 response; version bits are empty, no response.'
|
70
|
+
end
|
71
|
+
|
72
|
+
cert_len = raw.shift(2).join.to_i(16)
|
73
|
+
ciphers_len = raw.shift(2).join.to_i(16)
|
74
|
+
connection_id_len = raw.shift(2).join.to_i(16)
|
75
|
+
|
76
|
+
while raw.length < cert_len
|
77
|
+
cur = socket.gets
|
78
|
+
sleep 0.1 && next if cur.nil?
|
79
|
+
raw += cur.unpack('H*')[0].upcase.scan(/../)
|
80
|
+
print '.'
|
81
|
+
print raw.length
|
82
|
+
end
|
83
|
+
|
84
|
+
res['certificate'] = raw.shift(cert_len).join
|
85
|
+
res['ciphers'] = raw.shift(ciphers_len).join.scan(/....../).map do |id|
|
86
|
+
CIPHERS.key(id)
|
87
|
+
end
|
88
|
+
res['connection_id'] = raw.shift(connection_id_len).join
|
89
|
+
res['success'] = true
|
90
|
+
|
91
|
+
res
|
92
|
+
rescue SystemCallError, Alert => _
|
93
|
+
return { 'error' => 'Failed to parse response. The connection was terminated.' }
|
94
|
+
rescue NotYetImplementedError => e
|
95
|
+
return { 'error' => 'Failed to parse response. ' + e.message }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/sslshake/tls.rb
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# copyright: 2016, Dominik Richter
|
3
|
+
# license: MPLv2
|
4
|
+
|
5
|
+
require 'sslshake/common'
|
6
|
+
require 'sslshake/ciphers'
|
7
|
+
|
8
|
+
module SSLShake
|
9
|
+
class TLS # rubocop:disable Metrics/ClassLength
|
10
|
+
include CommonHelpers
|
11
|
+
|
12
|
+
VERSIONS = {
|
13
|
+
'ssl3' => '0300',
|
14
|
+
'tls1.0' => '0301',
|
15
|
+
'tls1.1' => '0302',
|
16
|
+
'tls1.2' => '0303',
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
CONTENT_TYPES = {
|
20
|
+
'ChangeCipherSpec' => '14',
|
21
|
+
'Alert' => '15',
|
22
|
+
'Handshake' => '16',
|
23
|
+
'Application' => '17',
|
24
|
+
'Heartbeat' => '18',
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
HANDSHAKE_TYPES = {
|
28
|
+
'HelloRequest' => '00',
|
29
|
+
'ClientHello' => '01',
|
30
|
+
'ServerHello' => '02',
|
31
|
+
'NewSessionTicket' => '04',
|
32
|
+
'Certificate' => '11',
|
33
|
+
'ServerKeyExchange' => '12',
|
34
|
+
'CertificateRequest' => '13',
|
35
|
+
'ServerHelloDone' => '14',
|
36
|
+
'CertificateVerify' => '15',
|
37
|
+
'ClientKeyExchange' => '16',
|
38
|
+
'Finished' => '20',
|
39
|
+
}.freeze
|
40
|
+
|
41
|
+
# https://tools.ietf.org/html/rfc6101#appendix-A.6
|
42
|
+
SSL3_CIPHERS = ::SSLShake::CIPHERS.select { |_, v| v < '001F' && v.length == 4 }
|
43
|
+
TLS_CIPHERS = ::SSLShake::CIPHERS.select { |k, _| k.start_with? 'TLS_' }
|
44
|
+
TLS10_CIPHERS = TLS_CIPHERS.select { |_, v| v[0] == '0' && v[1] == '0' }
|
45
|
+
|
46
|
+
# Additional collection of ciphers used by different apps and versions
|
47
|
+
OPENSSL_1_0_2_TLS10_CIPHERS = 'c014c00ac022c021c02000390038003700360088008700860085c00fc00500350084c013c009c01fc01ec01d00330032008000810082008300310030009a0099009800970045004400430042c00ec004002f009600410007c011c0070066c00cc00200050004c012c008c01cc01bc01a001600130010000dc00dc003000a006300150012000f000c006200090065006400140011000e000b00080006000300ff'.freeze
|
48
|
+
OPENSSL_1_0_2_TLS11_CIPHERS = 'c014c00ac022c021c02000390038003700360088008700860085c00fc00500350084c013c009c01fc01ec01d00330032008000810082008300310030009a0099009800970045004400430042c00ec004002f009600410007c011c0070066c00cc00200050004c012c008c01cc01bc01a001600130010000dc00dc003000a006300150012000f000c006200090065006400140011000e000b00080006000300ff'.freeze
|
49
|
+
OPENSSL_1_0_2_TLS12_CIPHERS = 'cc14cc13cc15c030c02cc028c024c014c00a00a500a300a1009f006b006a006900680039003800370036c077c07300c400c300c200c1008800870086008500810080c032c02ec02ac026c00fc005c079c075009d003d003500c000840095c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030c076c07200be00bd00bc00bb009a0099009800970045004400430042c031c02dc029c025c00ec004c078c074009c003c002f00ba0096004100070094c011c0070066c00cc002000500040092c012c008001600130010000dc00dc003000a009300150012000f000c000900ff'.freeze
|
50
|
+
|
51
|
+
def ssl_record(content_type, content, version)
|
52
|
+
res = content_type + version + int_bytes(content.length / 2, 2) + content
|
53
|
+
[res].pack('H*')
|
54
|
+
end
|
55
|
+
|
56
|
+
def ssl_hello(content, version)
|
57
|
+
ssl_record(
|
58
|
+
CONTENT_TYPES['Handshake'],
|
59
|
+
HANDSHAKE_TYPES['ClientHello'] + int_bytes(content.length / 2, 3) + content,
|
60
|
+
version,
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def hello(version, cipher_search = nil, extensions = nil)
|
65
|
+
case version
|
66
|
+
when 'ssl3'
|
67
|
+
ciphers = cipher_string(SSL3_CIPHERS, cipher_search)
|
68
|
+
when 'tls1.0', 'tls1.1'
|
69
|
+
ciphers = cipher_string(TLS10_CIPHERS, cipher_search)
|
70
|
+
when 'tls1.2'
|
71
|
+
ciphers = cipher_string(TLS_CIPHERS, cipher_search)
|
72
|
+
else
|
73
|
+
fail UserError, "This version is not supported: #{version.inspect}"
|
74
|
+
end
|
75
|
+
hello_tls(version, ciphers, extensions || '')
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse_hello(socket, opts) # rubocop:disable Meterics/AbcSize
|
79
|
+
raw = socket_read(socket, 5, opts[:timeout], opts[:retries])
|
80
|
+
.unpack('H*')[0].upcase.scan(/../)
|
81
|
+
type = raw.shift
|
82
|
+
if type == CONTENT_TYPES['Alert']
|
83
|
+
return { 'error' => 'SSL Alert.' }
|
84
|
+
end
|
85
|
+
unless type == CONTENT_TYPES['Handshake']
|
86
|
+
return { 'error' => 'Failed to parse response. It is not an SSL handshake.' }
|
87
|
+
end
|
88
|
+
|
89
|
+
res = {}
|
90
|
+
res['version'] = VERSIONS.key(raw.shift(2).join(''))
|
91
|
+
len = raw.shift(2).join.to_i(16)
|
92
|
+
|
93
|
+
res['raw'] = response = socket.read(len).unpack('H*')[0].upcase
|
94
|
+
raw = response.scan(/../)
|
95
|
+
|
96
|
+
res['handshake_type'] = HANDSHAKE_TYPES.key(raw.shift)
|
97
|
+
_len = raw.shift(3)
|
98
|
+
|
99
|
+
res['handshake_tls_version'] = VERSIONS.key(raw.shift(2).join(''))
|
100
|
+
res['random'] = raw.shift(32).join('')
|
101
|
+
|
102
|
+
len = raw.shift.to_i(16)
|
103
|
+
res['session_id'] = raw.shift(len).join('')
|
104
|
+
ciphers =
|
105
|
+
case res['version']
|
106
|
+
when 'ssl3'
|
107
|
+
SSL3_CIPHERS
|
108
|
+
else
|
109
|
+
TLS_CIPHERS
|
110
|
+
end
|
111
|
+
res['cipher_suite'] = ciphers.key(raw.shift(2).join(''))
|
112
|
+
res['compression_method'] = raw.shift
|
113
|
+
res['success'] = true
|
114
|
+
res['success'] = (res['version'] == opts[:protocol]) unless opts[:protocol].nil?
|
115
|
+
|
116
|
+
res
|
117
|
+
rescue SystemCallError, Alert => _
|
118
|
+
return { 'error' => 'Failed to parse response. The connection was terminated.' }
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def hello_tls(version, ciphers, extensions)
|
124
|
+
random = SecureRandom.hex(32)
|
125
|
+
session_id = ''
|
126
|
+
compressions = '00'
|
127
|
+
c = VERSIONS[version] +
|
128
|
+
random +
|
129
|
+
int_bytes(session_id.length / 2, 1) +
|
130
|
+
session_id +
|
131
|
+
int_bytes(ciphers.length / 2, 2) +
|
132
|
+
ciphers +
|
133
|
+
int_bytes(compressions.length / 2, 1) +
|
134
|
+
compressions +
|
135
|
+
int_bytes(extensions.length / 2, 2) +
|
136
|
+
extensions
|
137
|
+
ssl_hello(c, VERSIONS[version])
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
data/sslshake.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sslshake/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'sslshake'
|
8
|
+
spec.version = SSLShake::VERSION
|
9
|
+
spec.authors = ['Dominik Richter']
|
10
|
+
spec.email = ['dominik.richter@gmail.com']
|
11
|
+
spec.summary = 'Ruby library for pure SSL/TLS handshake testing.'
|
12
|
+
spec.description = 'This is a library to simulate SSL and TLS handshake from SSLv2, SSLv3, to TLS 1.0-1.2. It does not rely on OpenSSL and is not designed as a replacement either. It targets full support for even older handshakes, which are not available in current releases of OpenSSL anymore. It also aims to be executable on all systems with a sufficiently modern version of Ruby without any additional requirements or pre-compiled binaries.'
|
13
|
+
spec.homepage = 'https://github.com/arlimus/sslshake'
|
14
|
+
spec.license = 'MPLv2'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject {|f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.require_paths = ['lib']
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sslshake
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.12
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dominik Richter
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-08-15 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: This is a library to simulate SSL and TLS handshake from SSLv2, SSLv3,
|
14
|
+
to TLS 1.0-1.2. It does not rely on OpenSSL and is not designed as a replacement
|
15
|
+
either. It targets full support for even older handshakes, which are not available
|
16
|
+
in current releases of OpenSSL anymore. It also aims to be executable on all systems
|
17
|
+
with a sufficiently modern version of Ruby without any additional requirements or
|
18
|
+
pre-compiled binaries.
|
19
|
+
email:
|
20
|
+
- dominik.richter@gmail.com
|
21
|
+
executables: []
|
22
|
+
extensions: []
|
23
|
+
extra_rdoc_files: []
|
24
|
+
files:
|
25
|
+
- ".gitignore"
|
26
|
+
- README.md
|
27
|
+
- lib/sslshake.rb
|
28
|
+
- lib/sslshake/ciphers.rb
|
29
|
+
- lib/sslshake/common.rb
|
30
|
+
- lib/sslshake/sslv2.rb
|
31
|
+
- lib/sslshake/tls.rb
|
32
|
+
- lib/sslshake/version.rb
|
33
|
+
- sslshake.gemspec
|
34
|
+
homepage: https://github.com/arlimus/sslshake
|
35
|
+
licenses:
|
36
|
+
- MPLv2
|
37
|
+
metadata: {}
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 2.5.1
|
55
|
+
signing_key:
|
56
|
+
specification_version: 4
|
57
|
+
summary: Ruby library for pure SSL/TLS handshake testing.
|
58
|
+
test_files: []
|