sslshake 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []