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
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2015, NORDUnet A/S.
# See LICENSE for licensing information.
import sys
import argparse
import json
import errno
import shutil
from datetime import datetime, timedelta, tzinfo
from certtools import get_sth
NAGIOS_OK = 0
NAGIOS_WARN = 1
NAGIOS_CRIT = 2
NAGIOS_UNKNOWN = 3
DEFAULT_CUR_FILE = 'cur-sth.json'
DEFAULT_PREV_FILE = 'prev-sth.json'
parser = argparse.ArgumentParser(description="")
parser.add_argument('--cur-sth',
default=DEFAULT_CUR_FILE,
help="File containing current STH (default=%s)" % DEFAULT_CUR_FILE)
parser.add_argument('--prev-sth',
default=DEFAULT_PREV_FILE,
help="File containing previous STH (default=%s" % DEFAULT_PREV_FILE)
parser.add_argument('baseurl', help="Base URL for CT server")
def print_sth(sth):
if sth is None:
print "NONE"
else:
print sth['timestamp']
print sth['sha256_root_hash']
print sth['tree_size']
print sth['tree_head_signature']
def get_new_sth(baseurl):
try:
sth = get_sth(baseurl)
except Exception, e:
print e
sys.exit(NAGIOS_UNKNOWN)
return sth
def read_sth(fn):
try:
f = open(fn)
except IOError, errno.ENOENT:
return None
return json.loads(f.read())
def mv_file(fromfn, tofn):
shutil.move(fromfn, tofn)
def write_file(fn, sth):
open(fn, 'w').write(json.dumps(sth))
class UTC(tzinfo):
def utcoffset(self, dt):
return timedelta(hours=0)
def dst(self, dt):
return timedelta(0)
def check_age(sth):
now = datetime.now(UTC())
sth_time = datetime.fromtimestamp(sth['timestamp'] / 1000, UTC())
if now > sth_time + timedelta(0, 6 * 3600):
print "CRITICAL: %s is older than 6h: %s" % \
(sth['sha256_root_hash'], sth_time)
sys.exit(NAGIOS_CRIT)
if now > sth_time + timedelta(0, 2 * 3600):
print "WARNING: %s is older than 2h: %s" % \
(sth['sha256_root_hash'], sth_time)
sys.exit(NAGIOS_WARN)
def check_treesize(cur, prev):
if prev is not None:
if cur['tree_size'] < prev['tree_size']:
print "CRITICAL: new tree smaller than previous tree (%d < %d)" % \
(cur['tree_size'], prev['tree_size'])
sys.exit(NAGIOS_CRIT)
def main(args):
if args.cur_sth is None:
args.cur_sth = "cur-sth.json"
if args.prev_sth is None:
args.prev_sth = "prev-sth.json"
new = get_new_sth(args.baseurl)
cur = read_sth(args.cur_sth)
if cur is None or new['sha256_root_hash'] != cur['sha256_root_hash']:
if cur is not None:
mv_file(args.cur_sth, args.prev_sth)
write_file(args.cur_sth, new)
cur = new
prev = read_sth(args.prev_sth)
#print_sth(cur)
#print_sth(prev)
check_age(cur)
check_treesize(cur, prev)
# TODO: verify signature
# TODO: get and verify consistency proof
sys.exit(NAGIOS_OK)
if __name__ == '__main__':
main(parser.parse_args())
|