mirror of
https://github.com/Hopiu/linkchecker.git
synced 2026-03-25 18:30:23 +00:00
Test SSL certificate expiration.
This commit is contained in:
parent
da7c68981b
commit
4cce99a77d
11 changed files with 506 additions and 404 deletions
|
|
@ -168,6 +168,12 @@
|
|||
#localwebroot=/var/www/
|
||||
# Windows example:
|
||||
#localwebroot=/C|/public_html/
|
||||
# Check that SSL certificates are at least the given number of days valid.
|
||||
# The number must not be negative.
|
||||
# If the number of days is zero a warning is printed only for certificates
|
||||
# that are already expired.
|
||||
# The default number of days is 14.
|
||||
#sslcertwarndays=14
|
||||
|
||||
|
||||
##################### filtering options ##########################
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
8.0 "" (released xx.xx.2012)
|
||||
|
||||
Features:
|
||||
- checking: Verify SSL certificates for HTTPS connections.
|
||||
- checking: Verify SSL certificates for HTTPS connections. Both the
|
||||
hostname and the expiration date are checked.
|
||||
- cmdline: Added Nagios plugin script.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -131,6 +131,15 @@ Aneinanderfügen von Verzeichnissen benutzen. Und das angegebene Verzeichnis
|
|||
muss mit einem Schrägstrich enden.
|
||||
.br
|
||||
Kommandozeilenoption: keine
|
||||
.TP
|
||||
\fBwarnsslcertdaysvalid=\fP\fINUMBER\fP
|
||||
Prüfe ob SSL\-Zertifikate mindestens die angegebene Anzahl an Tagen gültig
|
||||
sind. Die Anzahl darf nicht negativ sein. Falls die Anzahl Null ist wird
|
||||
eine Warnung nur für Zertifikate ausgegeben, die schon abgelaufen sind.
|
||||
.br
|
||||
The Standardanzahl an Tagen ist 14.
|
||||
.br
|
||||
Kommandozeilenoption: keine
|
||||
.SS [filtering]
|
||||
.TP
|
||||
\fBignore=\fP\fIREGEX\fP (MULTILINE)
|
||||
|
|
|
|||
|
|
@ -123,6 +123,16 @@ to join directories instead of a backslash.
|
|||
And the given directory must end with a slash.
|
||||
.br
|
||||
Command line option: none
|
||||
.TP
|
||||
\fBwarnsslcertdaysvalid=\fP\fINUMBER\fP
|
||||
Check that SSL certificates are at least the given number of days valid.
|
||||
The number must not be negative.
|
||||
If the number of days is zero a warning is printed only for certificates
|
||||
that are already expired.
|
||||
.br
|
||||
The default number of days is 14.
|
||||
.br
|
||||
Command line option: none
|
||||
.SS \fB[filtering]\fP
|
||||
.TP
|
||||
\fBignore=\fP\fIREGEX\fP (MULTILINE)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -17,9 +17,10 @@
|
|||
"""
|
||||
Handle https links.
|
||||
"""
|
||||
|
||||
import time
|
||||
from . import httpurl
|
||||
from .const import WARN_HTTPS_CERTIFICATE
|
||||
from .. import log, LOG_CHECK, strformat
|
||||
|
||||
|
||||
class HttpsUrl (httpurl.HttpUrl):
|
||||
|
|
@ -47,6 +48,7 @@ class HttpsUrl (httpurl.HttpUrl):
|
|||
OpenSSL already checked the SSL notBefore and notAfter dates.
|
||||
"""
|
||||
cert = ssl_sock.getpeercert()
|
||||
log.debug(LOG_CHECK, "Got SSL certificate %s", cert)
|
||||
if not cert:
|
||||
msg = _('empty or no certificate found')
|
||||
self.add_ssl_warning(ssl_sock, msg)
|
||||
|
|
@ -56,6 +58,11 @@ class HttpsUrl (httpurl.HttpUrl):
|
|||
else:
|
||||
msg = _('certificate did not include "subject" information')
|
||||
self.add_ssl_warning(ssl_sock, msg)
|
||||
if 'notAfter' in cert:
|
||||
self.check_ssl_valid_date(ssl_sock, cert)
|
||||
else:
|
||||
msg = _('certificate did not include "notAfter" information')
|
||||
self.add_ssl_warning(ssl_sock, msg)
|
||||
|
||||
def check_ssl_hostname(self, ssl_sock, cert, host):
|
||||
"""Check the hostname against the certificate according to
|
||||
|
|
@ -66,6 +73,26 @@ class HttpsUrl (httpurl.HttpUrl):
|
|||
except CertificateError, msg:
|
||||
self.add_ssl_warning(ssl_sock, msg)
|
||||
|
||||
def check_ssl_valid_date(self, ssl_sock, cert):
|
||||
"""Check if the certificate is still valid, or if configured check
|
||||
if it's at least a number of days valid.
|
||||
"""
|
||||
import ssl
|
||||
checkDaysValid = self.aggregate.config["warnsslcertdaysvalid"]
|
||||
notAfter = ssl.cert_time_to_seconds(cert['notAfter'])
|
||||
curTime = time.time()
|
||||
# Calculate seconds until certifcate expires. Can be negative if
|
||||
# the certificate is already expired.
|
||||
secondsValid = notAfter - curTime
|
||||
if secondsValid < 0:
|
||||
msg = _('certficate is expired on %s') % cert['notAfter']
|
||||
self.add_ssl_warning(ssl_sock, msg)
|
||||
elif checkDaysValid > 0 and \
|
||||
secondsValid < (checkDaysValid * strformat.SECONDS_PER_DAY):
|
||||
strSecondsValid = strformat.str_duration_long(secondsValid)
|
||||
msg = _('certificate is only %s valid') % strSecondsValid
|
||||
self.add_ssl_warning(ssl_sock, msg)
|
||||
|
||||
def add_ssl_warning(self, ssl_sock, msg):
|
||||
"""Add a warning message about an SSL certificate error."""
|
||||
cipher_name, ssl_protocol, secret_bits = ssl_sock.cipher()
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ class Configuration (dict):
|
|||
self["useragent"] = UserAgent
|
||||
self["debugmemory"] = False
|
||||
self["localwebroot"] = None
|
||||
self["warnsslcertdaysvalid"] = 14
|
||||
from ..logger import Loggers
|
||||
self.loggers = dict(**Loggers)
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,17 @@ class LCConfigParser (ConfigParser.RawConfigParser, object):
|
|||
if self.has_option(section, option):
|
||||
self.config[option] = self.getboolean(section, option)
|
||||
|
||||
def read_int_option (self, section, option, key=None, allownegative=False):
|
||||
"""Read an integer option."""
|
||||
if self.has_option(section, option):
|
||||
num = self.getint(section, option)
|
||||
if not allownegative and num < 0:
|
||||
raise LinkCheckerError(
|
||||
_("invalid negative value for %s: %d\n") % (option, num))
|
||||
if key is None:
|
||||
key = option
|
||||
self.config[key] = num
|
||||
|
||||
def read_output_config (self):
|
||||
"""Read configuration options in section "output"."""
|
||||
section = "output"
|
||||
|
|
@ -112,12 +123,7 @@ class LCConfigParser (ConfigParser.RawConfigParser, object):
|
|||
if self.has_option(section, "threads"):
|
||||
num = self.getint(section, "threads")
|
||||
self.config['threads'] = max(0, num)
|
||||
if self.has_option(section, "timeout"):
|
||||
num = self.getint(section, "timeout")
|
||||
if num < 0:
|
||||
raise LinkCheckerError(
|
||||
_("invalid negative value for timeout: %d\n") % num)
|
||||
self.config['timeout'] = num
|
||||
self.read_int_option(section, "timeout")
|
||||
self.read_boolean_option(section, "anchors")
|
||||
if self.has_option(section, "recursionlevel"):
|
||||
num = self.getint(section, "recursionlevel")
|
||||
|
|
@ -133,12 +139,7 @@ class LCConfigParser (ConfigParser.RawConfigParser, object):
|
|||
self.config["nntpserver"] = self.get(section, "nntpserver")
|
||||
if self.has_option(section, "useragent"):
|
||||
self.config["useragent"] = self.get(section, "useragent")
|
||||
if self.has_option(section, "pause"):
|
||||
num = self.getint(section, "pause")
|
||||
if num < 0:
|
||||
raise LinkCheckerError(
|
||||
_("invalid negative value for pause: %d\n") % num)
|
||||
self.config["wait"] = num
|
||||
self.read_int_option(section, "pause", key="wait")
|
||||
self.read_check_options(section)
|
||||
|
||||
def read_check_options (self, section):
|
||||
|
|
@ -155,6 +156,7 @@ class LCConfigParser (ConfigParser.RawConfigParser, object):
|
|||
self.config['cookiefile'] = self.get(section, 'cookiefile')
|
||||
if self.has_option(section, "localwebroot"):
|
||||
self.config['localwebroot'] = self.get(section, 'localwebroot')
|
||||
self.read_int_option(section, "warnsslcertdaysvalid")
|
||||
|
||||
def read_authentication_config (self):
|
||||
"""Read configuration options in section "authentication"."""
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ cookiefile=blablabla
|
|||
useragent=Example/0.0
|
||||
pause=99
|
||||
debugmemory=1
|
||||
localwebroot=foo
|
||||
warnsslcertdaysvalid=99
|
||||
|
||||
[filtering]
|
||||
ignore=
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ class TestConfig (unittest.TestCase):
|
|||
self.assertEqual(config["useragent"], "Example/0.0")
|
||||
self.assertEqual(config["wait"], 99)
|
||||
self.assertEqual(config["debugmemory"], 1)
|
||||
self.assertEqual(config["localwebroot"], "foo")
|
||||
self.assertEqual(config["warnsslcertdaysvalid"], 99)
|
||||
# filtering section
|
||||
patterns = [x["pattern"].pattern for x in config["externlinks"]]
|
||||
for prefix in ("ignore_", "nofollow_"):
|
||||
|
|
|
|||
Loading…
Reference in a new issue