e6986bd30a870c646af566d177ddd62f9877ba51
[lets-encrypt-tiny.git] / certcheck
1 #!/usr/bin/python3
2 ## Call with "--help" for documentation.
3
4 import argparse, subprocess, re, os, datetime
5
6 def check_dir(dirname, days):
7     for name in os.listdir(dirname):
8         name = os.path.join(dirname, name)
9         if os.path.isdir(name):
10             check_dir(name, days)
11         elif name.endswith('.crt'):
12             check_file(name, days)
13
14 def check_file(filename, days):
15     valid_not_after = subprocess.check_output(["openssl", "x509", "-enddate", "-in", filename, "-out", "/dev/null"]).decode('utf-8')
16     match = re.match("notAfter=([a-zA-Z0-9: ]+)", valid_not_after)
17     assert match is not None, "Unexpected output from openssl: valid_not_after"
18     enddate = match.group(1)
19     enddate = datetime.datetime.strptime(enddate, '%b %d %X %Y %Z')
20     delta = enddate - datetime.datetime.now()
21     if delta < datetime.timedelta(days=days):
22         print("{} expires at {}, which is in {} days".format(filename, enddate, delta.days))
23
24 if __name__ == "__main__":
25     parser = argparse.ArgumentParser(description='Check for soon-to-expire (and already expired) certificates')
26     parser.add_argument("-d", "--days", metavar='N',
27                         dest="days", type=int, default=14,
28                         help="Warn about certificates valid for less than N (default 14).")
29     parser.add_argument("certs",  metavar='CERTS', nargs='+',
30                         help="These certificate files are checked. Directories are searched recursively for files called '*.crt'.")
31     args = parser.parse_args()
32     
33     for name in args.certs:
34         if os.path.isdir(name):
35             check_dir(name, args.days)
36         else:
37             check_file(name, args.days)
38
39