check_cert.py 3.89 KB
Newer Older
1 2 3 4
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# check_cert.py -- Petit mail de vérification du certificat d'un serveur
5 6
# ce script vérifie principalement la date d'expiration et envoie un mail
# d'avertissement si celle-ci est proche (paramétrable)
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#
# Copyright (c) 2013 Daniel STAN
# Authors: Daniel STAN <daniel.stan@crans.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

24

25
from M2Crypto import SSL
26
from M2Crypto import X509
27 28 29 30
import ssl
import socket

import time
31 32 33 34 35 36 37 38 39 40
import datetime
import sys

# Envoyer des mails
from email.mime.text import MIMEText
import smtplib

#
# Config !
#
41
host = 'localhost'
42
port = 443
43
filename = False # if True, port ignored and host is in fact a path
44 45 46 47 48 49 50 51 52
# afficher la sortie plutôt que l'envoyer:
verb = False
# delai d'avertissement
delay = datetime.timedelta(days=15)

# infos mails
mail_src = 'root@crans.org'
mail_dest = "roots@crans.org"
mail_host = 'localhost'
53 54 55 56 57

#
# Argument parsing !
#
# TODO argparse + doc
58 59 60 61
for arg in sys.argv[1:]:
    if arg == '-v':
        verb = True
        continue
62 63
    if arg == '--filename':
        filename = True
64 65 66 67 68
    try:
        port = int(arg)
    except ValueError:
        host = arg

69 70 71 72 73
# Va-t-on faire du starttls ?
# pour l'instant, uniquement pour smtp, mais on peut imaginer étendre à
# l'avenir à d'autre protocole (xmpp en aurait bien besoin par exemple)
starttls = (port == 25)

74
#
75
# Getting cert ! (sauf starttls)
76 77 78
#
if filename:
    cert = X509.load_cert(host)
79
elif not starttls:
80 81 82 83 84 85
    conn = SSL.Connection(SSL.Context())
    try:
        conn.connect((host, port))
    except SSL.Checker.WrongHost:
        if host != 'localhost':
            raise
86

87 88
    cert = conn.get_peer_cert()
    conn.close()
89 90 91 92 93
#
# Getting subject, altname et expire_date
#
# Sans starttls, pour les fichiers simples comme pour les connexions
if not starttls:
94
    expire_date = cert.get_not_after().get_datetime()
95
    subject = cert.get_subject().as_text()
96 97 98 99
    try:
        altname = "(alt: %s)" % cert.get_ext('subjectAltName').get_value()
    except LookupError:
        altname = ""
100 101
# Avec starttls, on fait totalement autre chose (et on n'utilise pas la variable
# cert d'au dessus)
102 103 104 105 106 107 108 109 110 111 112 113 114 115
else:    
    smtp = socket.socket()
    smtp.connect((host, port))
    resp = smtp.recv(4096)
    smtp.send("EHLO localhost\n")
    resp = smtp.recv(4096)
    smtp.send("STARTTLS\n")
    resp = smtp.recv(4096)
    smtp = ssl.wrap_socket(smtp, cert_reqs=ssl.CERT_REQUIRED, ca_certs="/etc/ssl/certs/ca-certificates.crt")
    cert = smtp.getpeercert()
    # DROOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOGUES
    expire_date = datetime.datetime.fromtimestamp(time.mktime(time.strptime(cert['notAfter'], "%b %d %H:%M:%S %Y %Z")))
    subject = cert["subject"][0][0][1].decode("UTF-8")
    altname = ""
116

117 118 119
#
# Real computation (woah !)
#
120
now = datetime.datetime.now(expire_date.tzinfo)
121
if now + delay > expire_date or verb:
122
    short_sub = subject
123
    subject += altname
124 125 126 127 128 129
    msg = MIMEText(u"""Attention, le certificat suivant arrive bientôt à expiration :\n%s\n
Temps avant expiration: %s""" % (subject,(expire_date - now)), _charset="utf-8")
    msg['From'] = mail_src
    msg['To'] = mail_dest
    msg['Subject'] = u"Expiration imminente du certificat %s" % short_sub
    if not verb:
130
        conn = smtplib.SMTP(mail_host)
131
        conn.sendmail(mail_src, mail_dest, msg.as_string())
132
        conn.quit()
133
    else:
134
        print msg.get_payload(decode=True)
135