Skip to content

Commit 08738bf

Browse files
authored
Merge pull request #2 from netsec-ethz/juagargi/ct_log_utils
add CT log get STH small utility.
2 parents 089b424 + 02a6208 commit 08738bf

File tree

6 files changed

+1376
-0
lines changed

6 files changed

+1376
-0
lines changed

ct_log_utils/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# fpki

ct_log_utils/create_db.sql

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
DROP DATABASE IF EXISTS `google_xenon2022`;
2+
CREATE DATABASE google_xenon2022;
3+
CREATE USER IF NOT EXISTS 'clonetool'@localhost IDENTIFIED BY 'letmein';
4+
GRANT ALL PRIVILEGES ON google_xenon2022.* TO 'clonetool'@localhost;
5+
FLUSH PRIVILEGES;

ct_log_utils/get_sths/get_sths.py

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env python3
2+
3+
# this script is adapted from https://github.com/SSLMate/ct-honeybee. Original comment below:
4+
#
5+
# The Certificate Transparency Honeybee (ct-honeybee) is a lightweight
6+
# program that retrieves signed tree heads (STHs) from Certificate
7+
# Transparency logs and uploads them to auditors.
8+
#
9+
# You can help strengthen the integrity of the Certificate Transparency
10+
# ecosystem by running ct-honeybee on your workstation/server/toaster every
11+
# hour or so (pick a random minute so that not everyone runs ct-honeybee
12+
# at the same time). Running ct-honeybee from many different Internet
13+
# vantage points increases the likelihood of detecting a misbehaving log
14+
# which has presented a different view of the log to different clients.
15+
#
16+
# Written in 2017 by Opsmate, Inc. d/b/a SSLMate <[email protected]>
17+
#
18+
# To the extent possible under law, the author(s) have dedicated all
19+
# copyright and related and neighboring rights to this software to the
20+
# public domain worldwide. This software is distributed without any
21+
# warranty.
22+
#
23+
# You should have received a copy of the CC0 Public
24+
# Domain Dedication along with this software. If not, see
25+
# <https://creativecommons.org/publicdomain/zero/1.0/>.
26+
#
27+
28+
29+
import json
30+
import random
31+
import re
32+
import socket
33+
import ssl
34+
import sys
35+
import time
36+
import urllib.request
37+
38+
from pathlib import Path
39+
40+
version = '2021-09-14'
41+
log_servers_file = 'honeybee.json'
42+
log_timeout = 15
43+
44+
base64_re = re.compile('^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$')
45+
46+
47+
def is_base64(obj):
48+
return isinstance(obj, str) and base64_re.search(obj) is not None
49+
50+
51+
def is_sth(obj):
52+
return isinstance(obj, dict) \
53+
and 'sth_version' in obj and isinstance(obj['sth_version'], int) \
54+
and 'tree_size' in obj and isinstance(obj['tree_size'], int) \
55+
and 'timestamp' in obj and isinstance(obj['timestamp'], int) \
56+
and 'sha256_root_hash' in obj and is_base64(obj['sha256_root_hash']) \
57+
and 'tree_head_signature' in obj and is_base64(obj['tree_head_signature']) \
58+
and 'log_id' in obj and is_base64(obj['log_id'])
59+
60+
61+
def main():
62+
sths = []
63+
logs = {}
64+
with open(Path(Path(__file__).parent,log_servers_file)) as f:
65+
d = json.load(f)['operators']
66+
for ee in d:
67+
for e in ee['logs']:
68+
if e['url'] in logs:
69+
raise ValueError(f'multiple entries: {e["url"]}')
70+
logs[e['url']] = e
71+
72+
# Disable certificate validation. Unfortunately, there is no guarantee
73+
# that logs use a certificate from a widely-trusted CA. Fortunately,
74+
# all responses are signed by logs and verified by auditors, so there
75+
# is technically no need for certificate validation.
76+
try:
77+
_create_unverified_https_context = ssl._create_unverified_context
78+
except AttributeError:
79+
pass
80+
else:
81+
ssl._create_default_https_context = _create_unverified_https_context
82+
83+
for log_url, e in logs.items():
84+
try:
85+
req = urllib.request.Request(log_url + 'ct/v1/get-sth',
86+
data=None, headers={'User-Agent': ''})
87+
with urllib.request.urlopen(req, timeout=log_timeout) as response:
88+
sth = json.loads(response.read().decode('utf-8'))
89+
if isinstance(sth, dict):
90+
sth['url'] = log_url
91+
sth['sth_version'] = 0
92+
sth['log_id'] = e['log_id']
93+
if is_sth(sth):
94+
sths.append(sth)
95+
except Exception as err:
96+
print('[%s] ct-honeybee: Log error: %s: %s: %s' %
97+
(time.strftime('%Y-%m-%d %H:%M:%S %z'),
98+
log_url,
99+
type(err).__name__,
100+
err),
101+
file=sys.stderr)
102+
103+
print(json.dumps(sths, indent=4))
104+
105+
106+
if __name__ == '__main__':
107+
main()

0 commit comments

Comments
 (0)