check_certificate_chain 2.3.0 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/check_certificate_chain +53 -13
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27a772594eae8ed954707e4d446184fc6bbfcde6348facdd9ee7b4a1f7050be2
|
4
|
+
data.tar.gz: 0015ff495b15b9bba9511b13c46762137945632af903cf4401d7c6310ce506e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b562158f6c3d2160f95d2f46be905bc6199eede081126b54d2b9b27572d55feef2f8eb9d41249143b51714a9e4d14e56170cfd244a8c002d79edc405baae3138
|
7
|
+
data.tar.gz: 57a5bc19f8524abec71372cbe4a71fc423d8bbc5861b4bcc79f0d0be624b7a53604679ad158af96f752215fc24ec095ddbd3cd686f7da5683f978435ee6fdacf
|
data/bin/check_certificate_chain
CHANGED
@@ -6,8 +6,33 @@ require 'socket'
|
|
6
6
|
require 'net/http'
|
7
7
|
require 'pastel'
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
servername = ""
|
10
|
+
host = ""
|
11
|
+
port = ""
|
12
|
+
|
13
|
+
|
14
|
+
def usage
|
15
|
+
puts "Usage: script.rb servername:host:port",
|
16
|
+
"Usage: script.rb host:port",
|
17
|
+
"Usage: script.rb host",
|
18
|
+
"Notice: if servername omitted, script takes host as TSL SNI servername",
|
19
|
+
"Notice: if port is omitted script takes 443 as default"
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
|
23
|
+
usage if ARGV.size != 1
|
24
|
+
|
25
|
+
argument_re = /^(((?<ip01>(\d{1,3}\.){3}\d{1,3})|(?<domain01>([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,})):)?
|
26
|
+
((?<ip02>(\d{1,3}\.){3}\d{1,3})|(?<domain02>([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}))
|
27
|
+
(:(?<port>\d{1,5}))?$/xi
|
28
|
+
|
29
|
+
|
30
|
+
argument_match_result = ARGV[0].match argument_re
|
31
|
+
|
32
|
+
host = argument_match_result[:ip02] || argument_match_result[:domain02]
|
33
|
+
servername = (argument_match_result[:ip01] || argument_match_result[:domain01]) || host
|
34
|
+
port = argument_match_result[:port] || "443"
|
35
|
+
|
11
36
|
|
12
37
|
pastel = Pastel.new(eachline: "\n")
|
13
38
|
|
@@ -22,13 +47,13 @@ warning = pastel.yellow.detach
|
|
22
47
|
|
23
48
|
openssl_context = OpenSSL::SSL::SSLContext.new
|
24
49
|
|
25
|
-
tcp_socket = TCPSocket.new(
|
50
|
+
tcp_socket = TCPSocket.new(host, port.to_i)
|
26
51
|
ip = tcp_socket.peeraddr(false).last
|
27
52
|
|
28
53
|
chain = nil
|
29
54
|
|
30
55
|
OpenSSL::SSL::SSLSocket.new(tcp_socket, openssl_context).tap do |ssl_socket|
|
31
|
-
ssl_socket.hostname =
|
56
|
+
ssl_socket.hostname = servername
|
32
57
|
ssl_socket.sync_close = true
|
33
58
|
ssl_socket.connect
|
34
59
|
|
@@ -43,7 +68,7 @@ certificate_store.set_default_paths
|
|
43
68
|
output = {}
|
44
69
|
output[:header] = "---"
|
45
70
|
|
46
|
-
output[:header] << "\nConnected to #{ip}\n---\n"
|
71
|
+
output[:header] << "\nConnected to #{ip}:#{port} with #{servername} as TLS SNI servername\n---\n"
|
47
72
|
|
48
73
|
output[:hostname_check] = ""
|
49
74
|
output[:date_check] = ""
|
@@ -66,11 +91,18 @@ end
|
|
66
91
|
certificate = chain.first
|
67
92
|
|
68
93
|
# Check certificate hostname
|
69
|
-
if OpenSSL::SSL.verify_certificate_identity certificate,
|
70
|
-
|
94
|
+
if OpenSSL::SSL.verify_certificate_identity certificate, servername
|
95
|
+
if certificate.subject.to_a.empty?
|
96
|
+
output[:issues] << warning[" Subject is empty"]
|
97
|
+
else
|
98
|
+
output[:issues] << warning[" Canonic Name is empty in subject"] unless certificate.subject.to_a.any?{|cn_entry_array| cn_entry_array.first.eql? "CN"}
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
output[:hostname_check] << good["The hostname #{good_bold[servername]} is correctly listed in the certificate."]
|
71
103
|
check_certificate_hostname = true
|
72
104
|
else
|
73
|
-
output[:hostname_check] << bad["None of the common names in the certificate match the name that was entered #{bad_bold[
|
105
|
+
output[:hostname_check] << bad["None of the common names in the certificate match the name that was entered #{bad_bold[servername]}."]
|
74
106
|
check_certificate_hostname = false
|
75
107
|
end
|
76
108
|
|
@@ -205,25 +237,33 @@ chain.each_with_index do |chain_certificate, index|
|
|
205
237
|
|
206
238
|
if chain_check_status
|
207
239
|
check_status = chain.any? do |possible_issuer|
|
208
|
-
unless possible_issuer.eql?
|
209
|
-
is_root?(chain_certificate)
|
240
|
+
unless possible_issuer.eql?(chain_certificate) && is_root?(chain_certificate)
|
210
241
|
if chain_certificate.verify possible_issuer.public_key
|
242
|
+
output[:issues] << bad[" Certificate is self-signed"] if chain_certificate.eql?(possible_issuer)
|
211
243
|
if chain.index(possible_issuer) - chain.index(chain_certificate) > 1
|
212
244
|
chain_order_status = false
|
213
245
|
end
|
214
246
|
true
|
215
247
|
end
|
248
|
+
else
|
249
|
+
check_status = false
|
216
250
|
end
|
217
251
|
end
|
218
252
|
|
219
253
|
# If check failed check against the root store
|
220
254
|
unless check_status
|
221
255
|
if certificate_store.verify chain_certificate
|
222
|
-
|
223
|
-
|
256
|
+
unless root_anchor
|
257
|
+
long_output(certificate_store.chain.last, output)
|
258
|
+
output[:data] << "---"
|
259
|
+
end
|
224
260
|
else
|
225
261
|
chain_check_status = false
|
226
|
-
|
262
|
+
if is_root? chain_certificate
|
263
|
+
output[:issues] << bad[" Root certificate is not trusted."]
|
264
|
+
else
|
265
|
+
output[:issues] << bad[" Chain is broken."]
|
266
|
+
end
|
227
267
|
end
|
228
268
|
end
|
229
269
|
else
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: check_certificate_chain
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.
|
4
|
+
version: 2.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jora Porcu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-11-
|
11
|
+
date: 2019-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: openssl
|