-
Notifications
You must be signed in to change notification settings - Fork 0
/
ssl_check_basic.py
executable file
·159 lines (141 loc) · 5.11 KB
/
ssl_check_basic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/usr/bin/env python
import socket
import ssl
import csv
from datetime import datetime
#
# linux local ca
#for cert in $(ls /etc/ssl/certs/); do openssl x509 -in /etc/ssl/certs/$cert -noout --issuer --issuer_hash --hash --serial; done > ~/.virtualenvs/ssl-check/linux-local-ca-issuers.txt
# bad issuers
# "Symantec",
# "GeoTrust",
# "thawte",
# "RapidSSL",
# "VeriSign",
# "Equifax",
# before 2017 december 1
domain_list_path = 'demo.txt'
cert_output_path = 'cert_ouput.txt'
cert_status_file = open(cert_output_path, 'w')
bad_issuers = ("Symantec", "GeoTrust", "thawte", "RapidSSL", "VeriSign",
"Equifax")
now_date = datetime.now()
one_day = 86400
timeout_seconds = 2
days_until_expired = 100
context = ssl.create_default_context()
output_dictionary = {
"domain": "None",
"valid_until": "None",
"reason": "None",
"checked_on": "None"
}
write = csv.DictWriter(cert_status_file, output_dictionary.keys())
write.writeheader()
"""
let's make a csv, all csvs have headers
"""
def datify_date(the_date):
# the_date = the_date.replace(tzinfo, "None")
# strftime Return a string representing the date and time, controlled by an explicit format string
# strptime Return a datetime corresponding to date_string
"""
This takes in the wierdo date like 'Dec 01 00:00:00 2018 GMT' and churns out a datetime compatible date
we only chew first 20 charactes, because i do not want to faff with timezones
"""
return datetime.strptime(the_date[:20], '%b %d %H:%M:%S %Y')
def flatten(elem, leaves=None):
"""
This accepts any nested lists and sublists, and expands it, so we have a flat structure, and we do not need to faff with optional nested lists.
"""
leaves = []
if isinstance(elem, tuple):
for member in elem:
leaves.extend(flatten(member))
else:
leaves.append(elem)
return leaves
def check_expiration_date(ssl_expiration_date):
"""
accepts expiration date, returns days left until expiration.
"""
if type(ssl_expiration_date) is datetime:
time_left = ssl_expiration_date - now_date
return time_left.total_seconds() / one_day
else:
print(ssl_expiration_date + " type, is not datetime")
return time_left.total_seconds() / one_day
def check_cert(domain):
try:
with socket.create_connection((domain, 443),
timeout=timeout_seconds) as sock:
with context.wrap_socket(
sock, server_hostname=domain) as connection:
result = connection.getpeercert()
issuer = ' '.join(
str(e) for e in flatten(result['issuer'][0:3]))
valid_until = flatten(result['notAfter'])[0]
result_dictionary = {
"domain": domain,
"issuer": issuer,
"valid_until": valid_until,
"checked_on": now_date.strftime("%Y-%m-%d")
}
valid_until = datify_date(result_dictionary['valid_until'])
bad_list = []
if check_expiration_date(valid_until) < days_until_expired:
"""
if expiration days left less than value, put it in the list of dictionaries
"""
reasons = {
"domain":
domain,
"valid_until":
valid_until.strftime("%Y-%m-%d"),
"reason":
"{} {} {}".format(
"less than", int(
check_expiration_date(valid_until)),
"days left"),
"checked_on":
now_date.strftime("%Y-%m-%d")
}
print(reasons)
write.writerow(reasons)
cert_status_file.flush()
if any(bad in issuer for bad in bad_issuers):
reasons = {
"domain": domain,
"valid_until": valid_until.strftime("%Y-%m-%d"),
"reason": "issuer",
"checked_on": now_date.strftime("%Y-%m-%d")
}
print(reasons)
write.writerow(reasons)
cert_status_file.flush()
except Exception as e:
fail = {
"domain": domain,
"valid_until": "none",
"reason": e,
"checked_on": now_date.strftime("%Y-%m-%d")
}
print(fail)
write.writerow(fail)
cert_status_file.flush()
return
def main():
domain_list = []
with open(domain_list_path, 'r') as file:
domains = file.readlines()
for domain in domains:
domain_list.append(domain.strip('\n'))
for domain in domain_list:
if domain:
"""
simple check if a line in domains list is empty or not.
"""
check_cert(domain)
cert_status_file.close()
if __name__ == '__main__':
main()