sslshake 1.0.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,3 @@
1
+ performance
2
+ .ssldummies
3
+ .testssl
@@ -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/)
@@ -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
@@ -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
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+ # copyright: 2016, Dominik Richter
3
+ # license: MPLv2
4
+
5
+ module SSLShake
6
+ VERSION = '1.0.12'.freeze
7
+ end
@@ -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: []