Aeris 3 лет назад
Родитель
Сommit
f1c14eef39

+ 1
- 1
bin/check_xmpp.rb Просмотреть файл

@@ -11,5 +11,5 @@ if ::File.exist? file
11 11
 	::CryptCheck::Tls::Xmpp.analyze_file file, "output/#{name}.html"
12 12
 else
13 13
 	::CryptCheck::Logger.level = ENV['LOG'] || :info
14
-	::CryptCheck::Tls::Xmpp.analyze ARGV[0], type: (ARGV[1] || :s2s).to_sym
14
+	::CryptCheck::Tls::Xmpp.analyze_domain ARGV[0], type: (ARGV[1] || :s2s).to_sym
15 15
 end

+ 1
- 1
lib/cryptcheck/tls/server.rb Просмотреть файл

@@ -24,7 +24,7 @@ module CryptCheck
24 24
 			end
25 25
 			class TLSTimeout < Timeout
26 26
 			end
27
-			class ConnectionError < Exception
27
+			class ConnectionError < ::StandardError
28 28
 			end
29 29
 
30 30
 			attr_reader :family, :ip, :port, :hostname, :prefered_ciphers, :cert, :cert_valid, :cert_trusted, :dh

+ 1
- 7
lib/cryptcheck/tls/xmpp.rb Просмотреть файл

@@ -6,13 +6,7 @@ module CryptCheck
6 6
 		module Xmpp
7 7
 			def self.analyze(host, port=nil, domain: nil, type: :s2s)
8 8
 				domain ||= host
9
-				::CryptCheck.analyze host, port do |family, ip, host|
10
-					s = Server.new family, ip, port, hostname: host, type: type, domain: domain
11
-					g = Grade.new s
12
-					Logger.info { '' }
13
-					g.display
14
-					g
15
-				end
9
+				::CryptCheck.analyze host, port, Server, Grade, domain: domain, type: type
16 10
 			end
17 11
 
18 12
 			def self.analyze_domain(domain, type: :s2s)

+ 4
- 4
lib/cryptcheck/tls/xmpp/server.rb Просмотреть файл

@@ -17,7 +17,7 @@ module CryptCheck
17 17
 										 when :c2s
18 18
 											 5222
19 19
 									 end unless port
20
-					super family, ip, port, hostname: hostname
20
+					super hostname, family, ip, port
21 21
 					Logger.info { '' }
22 22
 					Logger.info { self.required? ? 'Required'.colorize(:green) : 'Not required'.colorize(:yellow) }
23 23
 				end
@@ -29,13 +29,13 @@ module CryptCheck
29 29
 							   when :c2s then
30 30
 								   'jabber:client'
31 31
 						   end
32
-					socket.write "<?xml version='1.0' ?><stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='#{type}' to='#{@domain}' version='1.0'>"
32
+					socket.puts "<?xml version='1.0' ?><stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='#{type}' to='#{@domain}' version='1.0'>"
33 33
 					response = ''
34 34
 					loop do
35 35
 						response += socket.recv 1024
36 36
 						xml      = ::Nokogiri::XML response
37 37
 						error    = xml.xpath '//stream:error'
38
-						raise Exception, error.text unless error.empty?
38
+						raise ConnectionError, error.first.child.to_s unless error.empty?
39 39
 						unless xml.xpath('//stream:features').empty?
40 40
 							response = xml
41 41
 							break
@@ -43,7 +43,7 @@ module CryptCheck
43 43
 					end
44 44
 					starttls = response.xpath '//tls:starttls', tls: TLS_NAMESPACE
45 45
 					raise TLSNotAvailableException unless starttls
46
-					@required = !starttls.xpath('//tls:required', tls: TLS_NAMESPACE).nil?
46
+					@required = !starttls.xpath('//tls:required', tls: TLS_NAMESPACE).empty?
47 47
 					socket.write "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' />\r\n"
48 48
 					response = ::Nokogiri::XML socket.recv 4096
49 49
 					raise TLSNotAvailableException unless response.xpath '//tls:proceed', tls: TLS_NAMESPACE

+ 8
- 11
spec/cryptcheck/https_spec.rb Просмотреть файл

@@ -1,13 +1,10 @@
1 1
 describe CryptCheck::Tls::Https do
2
-	def process
3
-		proc do |socket|
4
-			socket.print [
5
-								 'HTTP/1.1 200 OK',
6
-								 'Content-Type: text/plain',
7
-								 'Content-Length: 0',
8
-								 'Connection: close'
9
-						 ].join "\r\n"
10
-		end
2
+	def server(*args, **kargs, &block)
3
+		tls_serv *args, **kargs, &block
4
+	end
5
+
6
+	def plain_server(*args, **kargs, &block)
7
+		plain_serv *args, **kargs, &block
11 8
 	end
12 9
 
13 10
 	def analyze(*args)
@@ -18,7 +15,7 @@ describe CryptCheck::Tls::Https do
18 15
 
19 16
 	describe '#hsts?' do
20 17
 		it 'has no hsts' do
21
-			grades = server host: '127.0.0.1', process: process do
18
+			grades = server host: '127.0.0.1' do
22 19
 				analyze '127.0.0.1', 5000
23 20
 			end
24 21
 
@@ -48,7 +45,7 @@ describe CryptCheck::Tls::Https do
48 45
 
49 46
 	describe '#hsts_long?' do
50 47
 		it 'has no hsts' do
51
-			grades = server host: '127.0.0.1', process: process do
48
+			grades = server host: '127.0.0.1' do
52 49
 				analyze '127.0.0.1', 5000
53 50
 			end
54 51
 

+ 10
- 10
spec/cryptcheck/support/analysis.rb Просмотреть файл

@@ -1,7 +1,7 @@
1 1
 RSpec.shared_examples :analysis do
2 2
 	describe '#analyze' do
3 3
 		it 'return 1 grade with IPv4' do
4
-			grades = server host: '127.0.0.1', process: process do
4
+			grades = server host: '127.0.0.1' do
5 5
 				analyze '127.0.0.1', 5000
6 6
 			end
7 7
 
@@ -10,7 +10,7 @@ RSpec.shared_examples :analysis do
10 10
 		end
11 11
 
12 12
 		it 'return 1 grade with IPv6' do
13
-			grades = server host: '::1', process: process do
13
+			grades = server host: '::1' do
14 14
 				analyze '::1', 5000
15 15
 			end
16 16
 
@@ -24,7 +24,7 @@ RSpec.shared_examples :analysis do
24 24
 				addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) }
25 25
 			end
26 26
 
27
-			grades = server host: '::', process: process do
27
+			grades = server host: '::' do
28 28
 				analyze 'localhost', 5000
29 29
 			end
30 30
 
@@ -36,7 +36,7 @@ RSpec.shared_examples :analysis do
36 36
 			allow(Addrinfo).to receive(:getaddrinfo).with('localhost', nil, nil, :STREAM)
37 37
 									   .and_raise SocketError, 'getaddrinfo: Name or service not known'
38 38
 
39
-			grades = server process: process do
39
+			grades = server do
40 40
 				analyze 'localhost', 5000
41 41
 			end
42 42
 
@@ -48,7 +48,7 @@ RSpec.shared_examples :analysis do
48 48
 			stub_const 'CryptCheck::MAX_ANALYSIS_DURATION', 1
49 49
 			allow(CryptCheck::Tls::Server).to receive(:new) { sleep 2 }
50 50
 
51
-			grades = server process: process do
51
+			grades = server do
52 52
 				analyze 'localhost', 5000
53 53
 			end
54 54
 
@@ -62,7 +62,7 @@ RSpec.shared_examples :analysis do
62 62
 				addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) }
63 63
 			end
64 64
 
65
-			grades = server host: '::1', process: process do
65
+			grades = server host: '::1' do
66 66
 				analyze 'localhost', 5000
67 67
 			end
68 68
 
@@ -84,7 +84,7 @@ RSpec.shared_examples :analysis do
84 84
 				original.call *args, &block
85 85
 			end
86 86
 
87
-			grades = server host: '::', process: process do
87
+			grades = server host: '::' do
88 88
 				analyze 'localhost', 5000
89 89
 			end
90 90
 
@@ -106,7 +106,7 @@ RSpec.shared_examples :analysis do
106 106
 				original.call *args, &block
107 107
 			end
108 108
 
109
-			grades = server host: '::', process: process do
109
+			grades = server host: '::' do
110 110
 				analyze 'localhost', 5000
111 111
 			end
112 112
 
@@ -122,8 +122,8 @@ RSpec.shared_examples :analysis do
122 122
 				addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) }
123 123
 			end
124 124
 
125
-			grades = plain_server host: '127.0.0.1', process: process do
126
-				server host: '::1', process: process do
125
+			grades = plain_server host: '127.0.0.1' do
126
+				server host: '::1' do
127 127
 					analyze 'localhost', 5000
128 128
 				end
129 129
 			end

+ 6
- 1
spec/cryptcheck/tls_spec.rb Просмотреть файл

@@ -1,5 +1,10 @@
1 1
 describe CryptCheck::Tls do
2
-	def process
2
+	def server(*args, &block)
3
+		tls_serv *args, &block
4
+	end
5
+
6
+	def plain_server(*args, &block)
7
+		plain_serv *args, &block
3 8
 	end
4 9
 
5 10
 	def analyze(*args)

+ 72
- 0
spec/cryptcheck/xmpp_spec.rb Просмотреть файл

@@ -0,0 +1,72 @@
1
+describe CryptCheck::Tls::Xmpp do
2
+	def server(*args, **kargs, &block)
3
+		kargs[:plain_process] = proc do |socket|
4
+			socket.gets
5
+			socket.puts "<?xml version='1.0'?><stream:stream xmlns:db='jabber:server:dialback' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' from='localhost' id='' xml:lang='en' xmlns='jabber:server'><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'></starttls><dialback xmlns='urn:xmpp:features:dialback'/></stream:features>"
6
+			socket.gets
7
+			socket.puts "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' />"
8
+			true
9
+		end unless kargs.include? :plain_process
10
+		starttls_serv *args, **kargs, &block
11
+	end
12
+
13
+	def plain_server(*args, **kargs, &block)
14
+		kargs[:plain_process] = proc do |socket|
15
+			socket.gets
16
+			socket.puts "<?xml version='1.0'?><stream:stream xmlns:db='jabber:server:dialback' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' from='localhost' id='' xml:lang='en' xmlns='jabber:server'><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'></starttls><dialback xmlns='urn:xmpp:features:dialback'/></stream:features>"
17
+			socket.gets
18
+			socket.puts "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' />"
19
+			false
20
+		end unless kargs.include? :plain_process
21
+		starttls_serv *args, **kargs, &block
22
+	end
23
+
24
+	def analyze(*args)
25
+		CryptCheck::Tls::Xmpp.analyze *args, type: :s2s
26
+	end
27
+
28
+	include_examples :analysis do
29
+		it 'return error on XMPP error' do
30
+			plain_process = proc do |socket|
31
+				socket.gets
32
+				socket.puts "<?xml version='1.0'?><stream:stream xmlns:db='jabber:server:dialback' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' from='localhost' id='' xml:lang='en' xmlns='jabber:server'><stream:error><invalid-namespace xmlns='urn:ietf:params:xml:ns:xmpp-streams'/></stream:error>"
33
+				false
34
+			end
35
+
36
+			grades = server host: '127.0.0.1', plain_process: plain_process do
37
+				analyze '127.0.0.1', 5000
38
+			end
39
+
40
+			expect_grade_error grades, '127.0.0.1', '127.0.0.1', 5000,
41
+					'<invalid-namespace xmlns="urn:ietf:params:xml:ns:xmpp-streams"/>'
42
+		end
43
+	end
44
+
45
+	describe '#required?' do
46
+		it 'has TLS not required' do
47
+			grades = server host: '127.0.0.1' do
48
+				analyze '127.0.0.1', 5000
49
+			end
50
+
51
+			_, server = expect_grade grades, '127.0.0.1', '127.0.0.1', 5000, :ipv4
52
+			expect(server.required?).to be false
53
+		end
54
+
55
+		it 'has TLS required' do
56
+			plain_process = proc do |socket|
57
+				socket.gets
58
+				socket.puts "<?xml version='1.0'?><stream:stream xmlns:db='jabber:server:dialback' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' from='localhost' id='' xml:lang='en' xmlns='jabber:server'><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><required/></starttls><dialback xmlns='urn:xmpp:features:dialback'/></stream:features>"
59
+				socket.gets
60
+				socket.puts "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' />"
61
+				true
62
+			end
63
+
64
+			grades = server host: '127.0.0.1', plain_process: plain_process do
65
+				analyze '127.0.0.1', 5000
66
+			end
67
+
68
+			_, server = expect_grade grades, '127.0.0.1', '127.0.0.1', 5000, :ipv4
69
+			expect(server.required?).to be true
70
+		end
71
+	end
72
+end

+ 76
- 59
spec/helpers.rb Просмотреть файл

@@ -52,28 +52,7 @@ module Helpers
52 52
 		cert.sign key, OpenSSL::Digest::SHA512.new
53 53
 	end
54 54
 
55
-	def server(key: 'rsa-1024', domain: 'localhost', # Key & certificate
56
-			   host: '127.0.0.1', port: 5000, # Binding
57
-			   version: :TLSv1_2, ciphers: 'AES128-SHA', # TLS version and ciphers
58
-			   dh: 1024, ecdh: 'secp256r1', # DHE & ECDHE
59
-			   process: nil)
60
-		key  = key key
61
-		cert = certificate key, domain
62
-
63
-		context         = OpenSSL::SSL::SSLContext.new version
64
-		context.cert    = cert
65
-		context.key     = key
66
-		context.ciphers = ciphers
67
-
68
-		if dh
69
-			dh                      = dh dh
70
-			context.tmp_dh_callback = proc { dh }
71
-		end
72
-		if ecdh
73
-			ecdh                      = key ecdh
74
-			context.tmp_ecdh_callback = proc { ecdh }
75
-		end
76
-
55
+	def serv(server, process, &block)
77 56
 		IO.pipe do |stop_pipe_r, stop_pipe_w|
78 57
 			threads = []
79 58
 
@@ -81,16 +60,14 @@ module Helpers
81 60
 			started = ConditionVariable.new
82 61
 
83 62
 			threads << Thread.start do
84
-				tcp_server = TCPServer.new host, port
85
-				ssl_server = OpenSSL::SSL::SSLServer.new tcp_server, context
86
-
87 63
 				mutex.synchronize { started.signal }
88 64
 
89 65
 				loop do
90
-					readable, = IO.select [ssl_server, stop_pipe_r]
66
+					readable, = IO.select [server, stop_pipe_r]
91 67
 					break if readable.include? stop_pipe_r
68
+
92 69
 					begin
93
-						socket = ssl_server.accept
70
+						socket = server.accept
94 71
 						begin
95 72
 							process.call socket if process
96 73
 						ensure
@@ -99,13 +76,12 @@ module Helpers
99 76
 					rescue
100 77
 					end
101 78
 				end
102
-				ssl_server.close
103
-				tcp_server.close
79
+				server.close
104 80
 			end
105 81
 
106 82
 			mutex.synchronize { started.wait mutex }
107 83
 			begin
108
-				yield
84
+				block.call if block
109 85
 			ensure
110 86
 				stop_pipe_w.close
111 87
 				threads.each &:join
@@ -113,41 +89,82 @@ module Helpers
113 89
 		end
114 90
 	end
115 91
 
116
-	def plain_server(host: '127.0.0.1', port: 5000, process: nil)
117
-		IO.pipe do |stop_pipe_r, stop_pipe_w|
118
-			threads = []
92
+	def context(key: 'rsa-1024', domain: 'localhost', # Key & certificate
93
+				version: :TLSv1_2, ciphers: 'AES128-SHA', # TLS version and ciphers
94
+				dh: 1024, ecdh: 'secp256r1') # DHE & ECDHE
95
+		key  = key key
96
+		cert = certificate key, domain
119 97
 
120
-			mutex   = Mutex.new
121
-			started = ConditionVariable.new
98
+		context         = OpenSSL::SSL::SSLContext.new version
99
+		context.cert    = cert
100
+		context.key     = key
101
+		context.ciphers = ciphers
122 102
 
123
-			threads << Thread.start do
124
-				tcp_server = TCPServer.new host, port
125
-				mutex.synchronize { started.signal }
103
+		if dh
104
+			dh                      = dh dh
105
+			context.tmp_dh_callback = proc { dh }
106
+		end
107
+		if ecdh
108
+			ecdh                      = key ecdh
109
+			context.tmp_ecdh_callback = proc { ecdh }
110
+		end
126 111
 
127
-				loop do
128
-					readable, = IO.select [tcp_server, stop_pipe_r]
129
-					break if readable.include? stop_pipe_r
112
+		context
113
+	end
130 114
 
131
-					begin
132
-						socket = tcp_server.accept
133
-						begin
134
-							process.call socket if process
135
-						ensure
136
-							socket.close
137
-						end
138
-					rescue
139
-					end
115
+	def tls_serv(key: 'rsa-1024', domain: 'localhost', # Key & certificate
116
+				 version: :TLSv1_2, ciphers: 'AES128-SHA', # TLS version and ciphers
117
+				 dh: 1024, ecdh: 'secp256r1', # DHE & ECDHE
118
+				 host: '127.0.0.1', port: 5000, # Binding
119
+				 process: nil, &block)
120
+		context    = context(key: key, domain: domain, version: version, ciphers: ciphers, dh: dh, ecdh: ecdh)
121
+		tcp_server = TCPServer.new host, port
122
+		tls_server = OpenSSL::SSL::SSLServer.new tcp_server, context
123
+		begin
124
+			serv tls_server, process, &block
125
+		ensure
126
+			tls_server.close
127
+			tcp_server.close
128
+		end
129
+	end
130
+
131
+	def plain_serv(host: '127.0.0.1', port: 5000, process: nil, &block)
132
+		tcp_server = TCPServer.new host, port
133
+		begin
134
+			serv tcp_server, process, &block
135
+		ensure
136
+			tcp_server.close
137
+		end
138
+	end
139
+
140
+	def starttls_serv(key: 'rsa-1024', domain: 'localhost', # Key & certificate
141
+					  version: :TLSv1_2, ciphers: 'AES128-SHA', # TLS version and ciphers
142
+					  dh: 1024, ecdh: 'secp256r1', # DHE & ECDHE
143
+					  host: '127.0.0.1', port: 5000, # Binding
144
+					  plain_process: nil, process: nil, &block)
145
+		context                      = context(key: key, domain: domain, version: version, ciphers: ciphers, dh: dh, ecdh: ecdh)
146
+		tcp_server                   = TCPServer.new host, port
147
+		tls_server                   = OpenSSL::SSL::SSLServer.new tcp_server, context
148
+		tls_server.start_immediately = false
149
+
150
+		internal_process = proc do |socket|
151
+			accept = false
152
+			accept = plain_process.call socket if plain_process
153
+			if accept
154
+				tls_socket = socket.accept
155
+				begin
156
+					process.call tls_socket if process
157
+				ensure
158
+					socket.close
140 159
 				end
141
-				tcp_server.close
142 160
 			end
161
+		end
143 162
 
144
-			mutex.synchronize { started.wait mutex }
145
-			begin
146
-				yield
147
-			ensure
148
-				stop_pipe_w.close
149
-				threads.each &:join
150
-			end
163
+		begin
164
+			serv tls_server, internal_process, &block
165
+		ensure
166
+			tls_server.close
167
+			tcp_server.close
151 168
 		end
152 169
 	end
153 170
 
@@ -157,7 +174,7 @@ module Helpers
157 174
 
158 175
 	def expect_grade(grades, host, ip, port, family)
159 176
 		grade = grade grades, host, ip, port
160
-		expect(grade).to_not be nil
177
+		expect(grade).to be_a CryptCheck::Tls::Grade
161 178
 		server = grade.server
162 179
 		expect(server).to be_a CryptCheck::Tls::Server
163 180
 		expect(server.hostname).to eq host

Загрузка…
Отмена
Сохранить