-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathanalyze_dnskeys.py
executable file
·94 lines (68 loc) · 3.04 KB
/
analyze_dnskeys.py
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
#!/usr/bin/env python
"""
Looks at each RSA key and prints out all keys that either have small moduli < 1023
bits or small exponents (where a validating resolver implementation might be
susceptible to variants of Bleichenbacher attack).
Reports also keys with big exponents (which slow down verification at resolvers).
"""
import sys
import os.path
from math import log, ceil
from hashlib import sha1
from ConfigParser import SafeConfigParser
from db import DbSingleThreadOverSchema
from dns_scraper import DnskeyAlgo
#minimal modulus size and exponent size that is considered "safe"
#see http://www.keylength.com/en/3/ and referenced ECRYPT II yearly report
b1023 = 1<<1023
#see "Variants of Bleichenbacher's Low-Exponent Attacks on PKCS##1 RSA":
#http://www.cdc.informatik.tu-darmstadt.de/reports/reports/sigflaw.pdf
min_exponent = 65537
#see Adam Langley's blog: http://www.imperialviolet.org/2012/03/17/rsados.html
big_exponent = 0x100000000
# keys generated by Debian openssl bug
badkeysDir = os.path.dirname(os.path.realpath(__file__)) + os.path.sep
weakKeyHashes = set([line.rstrip() for line in \
file(badkeysDir + "openssl-blacklist/blacklist.RSA-1024") if not line.startswith("#")])
weakKeyHashes |= set([line.rstrip() for line in \
file(badkeysDir + "openssl-blacklist/blacklist.RSA-2048") if not line.startswith("#")])
if __name__ == '__main__':
if len(sys.argv) != 2:
print >> sys.stderr, "ERROR: usage: <scraper_config>"
sys.exit(1)
scraperConfig = SafeConfigParser()
scraperConfig.read(sys.argv[1])
db = DbSingleThreadOverSchema(scraperConfig)
#named cursor in order to not swap ourselves from the known universe
cursor = db.cursor(name="dnskeys")
sql = """SELECT dnskey_rr.id AS id, fqdn, rsa_exp, encode(rsa_mod, 'hex') AS rsa_mod_hex
FROM dnskey_rr INNER JOIN domains ON (fqdn_id=domains.id)
WHERE algo IN %s
"""
sql_data = (tuple(DnskeyAlgo.rsaAlgoIds),)
cursor.execute(sql, sql_data)
rows = cursor.fetchmany(db.dbRows)
while rows:
for row in rows:
rowId = row["id"]
fqdn = row["fqdn"]
rsa_exp = row["rsa_exp"]
rsa_mod_hex = row["rsa_mod_hex"].lstrip("0")
rsa_mod = int(rsa_mod_hex, 16)
bits_in = lambda n: ceil(log(abs(n)+1,2))
if rsa_mod < b1023:
print "Small modulus: id %s, fqdn %s, %d bits, mod 0x%s" % (rowId, fqdn, bits_in(rsa_mod), rsa_mod_hex)
if rsa_exp == -1: #special value for exponent that won't fit into int64_t
print "HUGE exponent: id %s, fqdn %s" % (rowId, fqdn)
elif rsa_exp < min_exponent:
print "Small exponent %s: id %s, fqdn %s" % (rsa_exp, rowId, fqdn)
elif rsa_exp > big_exponent:
print "Big exponent 0x%x: id %s, fqdn %s" % (rsa_exp, rowId, fqdn)
#debian weak key check
zeros = len(rsa_mod_hex)%2 #add zeros to have even number of hex digits
mod_to_hash = "Modulus="+("0"*zeros)+rsa_mod_hex.upper()+"\n"
mod_hash = sha1(mod_to_hash).hexdigest()
to_check = mod_hash[20:]
if to_check in weakKeyHashes:
print "Weak debian key: id %s, fqdn %s, mod 0x%s" % (rowId, fqdn, rsa_mod_hex)
rows = cursor.fetchmany(db.dbRows)