summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--monitor/josef_lib.py2
-rwxr-xr-xmonitor/josef_monitor.py4
-rw-r--r--monitor/monitor_conf.py76
-rwxr-xr-xmonitor/verify_sct.py239
4 files changed, 279 insertions, 42 deletions
diff --git a/monitor/josef_lib.py b/monitor/josef_lib.py
index 28ea0c0..24c0c32 100644
--- a/monitor/josef_lib.py
+++ b/monitor/josef_lib.py
@@ -18,7 +18,7 @@ import zipfile
import shutil
from certkeys import publickeys
-from Crypto.Hash import SHA256
+# from Crypto.Hash import SHA256
import Crypto.PublicKey.RSA as RSA
from Crypto.Signature import PKCS1_v1_5
diff --git a/monitor/josef_monitor.py b/monitor/josef_monitor.py
index aacc59c..97092bc 100755
--- a/monitor/josef_monitor.py
+++ b/monitor/josef_monitor.py
@@ -266,11 +266,9 @@ def verify_inclusion_by_hash(base_url, leaf_hash):
return True
else:
print time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(proof["leaf_index"]) + " in " + base_url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for entry " + str(proof["leaf_index"]) + " in " + base_url)
return False
except:
print time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for hashed entry in " + base_url
- errors.append(time.strftime('%H:%M:%S') + " ERROR: Could not prove inclusion for hashed entry in " + base_url)
return False
def verify_inclusion_by_index(base_url, index):
@@ -343,7 +341,7 @@ def main(args):
logs = []
try:
for item in ctlogs:
- logs.append(ctlog(item, ctlogs[item][0], ctlogs[item][1], ctlogs[item][2]))
+ logs.append(ctlog(item["name"], item["url"], item["key"], item["id"]))
print time.strftime('%H:%M:%S') + " Setting up monitor for " + str(len(logs)) + " logs..."
# Set up state
diff --git a/monitor/monitor_conf.py b/monitor/monitor_conf.py
index 38de5ff..326caa8 100644
--- a/monitor/monitor_conf.py
+++ b/monitor/monitor_conf.py
@@ -28,49 +28,49 @@ MONITORED_DOMAINS = [
]
# CT logs and associated keys
-ctlogs = {
- # "pilot":
- # ["https://ct.googleapis.com/pilot/",
- # "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA==",
- # "pLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BA="],
+ctlogs = [
+ # {"name" : "pilot":,
+ # "url" : "https://ct.googleapis.com/pilot/",
+ # "key" : "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA==",
+ # "id" : "pLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BA="},
- # "plausible":
- # ["https://plausible.ct.nordu.net/",
- # "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9UV9+jO2MCTzkabodO2F7LM03MUBc8MrdAtkcW6v6GA9taTTw9QJqofm0BbdAsbtJL/unyEf0zIkRgXjjzaYqQ==",
- # "qucLfzy41WbIbC8Wl5yfRF9pqw60U1WJsvd6AwEE880="],
+ # {"name" : "plausible",
+ # "url" : "https://plausible.ct.nordu.net/",
+ # "key" : "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9UV9+jO2MCTzkabodO2F7LM03MUBc8MrdAtkcW6v6GA9taTTw9QJqofm0BbdAsbtJL/unyEf0zIkRgXjjzaYqQ==",
+ # "id" : "qucLfzy41WbIbC8Wl5yfRF9pqw60U1WJsvd6AwEE880="},
- # "digicert":
- # ["https://ct1.digicert-ct.com/log/",
- # "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4+HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs6A==",
- # "VhQGmi/XwuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ0N0="],
+ # {"name" : "digicert",
+ # "url" : "https://ct1.digicert-ct.com/log/",
+ # "key" : "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4+HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs6A==",
+ # "id" : "VhQGmi/XwuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ0N0="},
- "izenpe":
- ["https://ct.izenpe.com/",
- "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ2Q5DC3cUBj4IQCiDu0s6j51up+TZAkAEcQRF6tczw90rLWXkJMAW7jr9yc92bIKgV8vDXU4lDeZHvYHduDuvg==",
- "dGG0oJz7PUHXUVlXWy52SaRFqNJ3CbDMVkpkgrfrQaM="],
+ {"name" : "izenpe",
+ "url" : "https://ct.izenpe.com/",
+ "key" : "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ2Q5DC3cUBj4IQCiDu0s6j51up+TZAkAEcQRF6tczw90rLWXkJMAW7jr9yc92bIKgV8vDXU4lDeZHvYHduDuvg==",
+ "id" : "dGG0oJz7PUHXUVlXWy52SaRFqNJ3CbDMVkpkgrfrQaM="},
- "certly":
- ["https://log.certly.io/",
- "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECyPLhWKYYUgEc+tUXfPQB4wtGS2MNvXrjwFCCnyYJifBtd2Sk7Cu+Js9DNhMTh35FftHaHu6ZrclnNBKwmbbSA==",
- "zbUXm3/BwEb+6jETaj+PAC5hgvr4iW/syLL1tatgSQA="],
+ {"name" : "certly",
+ "url" : "https://log.certly.io/",
+ "key" : "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECyPLhWKYYUgEc+tUXfPQB4wtGS2MNvXrjwFCCnyYJifBtd2Sk7Cu+Js9DNhMTh35FftHaHu6ZrclnNBKwmbbSA==",
+ "id" : "zbUXm3/BwEb+6jETaj+PAC5hgvr4iW/syLL1tatgSQA="},
- # "aviator":
- # ["https://ct.googleapis.com/aviator/",
- # "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q==",
- # "aPaY+B9kgr46jO65KB1M/HFRXWeT1ETRCmesu09P+8Q="],
+ # {"name" : "aviator",
+ # "url" : "https://ct.googleapis.com/aviator/",
+ # "key" : "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q==",
+ # "id" : "aPaY+B9kgr46jO65KB1M/HFRXWeT1ETRCmesu09P+8Q="},
- # "rocketeer":
- # ["https://ct.googleapis.com/rocketeer/",
- # "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIFsYyDzBi7MxCAC/oJBXK7dHjG+1aLCOkHjpoHPqTyghLpzA9BYbqvnV16mAw04vUjyYASVGJCUoI3ctBcJAeg==",
- # "7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/cs="],
+ # {"name" : "rocketeer",
+ # "url" : "https://ct.googleapis.com/rocketeer/",
+ # "key" : "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIFsYyDzBi7MxCAC/oJBXK7dHjG+1aLCOkHjpoHPqTyghLpzA9BYbqvnV16mAw04vUjyYASVGJCUoI3ctBcJAeg==",
+ # "id": "7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/cs="},
- "symantec":
- ["https://ct.ws.symantec.com/",
- "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEluqsHEYMG1XcDfy1lCdGV0JwOmkY4r87xNuroPS2bMBTP01CEDPwWJePa75y9CrsHEKqAy8afig1dpkIPSEUhg==",
- "3esdK3oNT6Ygi4GtgWhwfi6OnQHVXIiNPRHEzbbsvsw="],
+ {"name" : "symantec":
+ "url" : "https://ct.ws.symantec.com/",
+ "key" : "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEluqsHEYMG1XcDfy1lCdGV0JwOmkY4r87xNuroPS2bMBTP01CEDPwWJePa75y9CrsHEKqAy8afig1dpkIPSEUhg==",
+ "id" : "3esdK3oNT6Ygi4GtgWhwfi6OnQHVXIiNPRHEzbbsvsw="},
- "venafi":
- ["https://ctlog.api.venafi.com/",
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAolpIHxdSlTXLo1s6H1OCdpSj/4DyHDc8wLG9wVmLqy1lk9fz4ATVmm+/1iN2Nk8jmctUKK2MFUtlWXZBSpym97M7frGlSaQXUWyA3CqQUEuIJOmlEjKTBEiQAvpfDjCHjlV2Be4qTM6jamkJbiWtgnYPhJL6ONaGTiSPm7Byy57iaz/hbckldSOIoRhYBiMzeNoA0DiRZ9KmfSeXZ1rB8y8X5urSW+iBzf2SaOfzBvDpcoTuAaWx2DPazoOl28fP1hZ+kHUYvxbcMjttjauCFx+JII0dmuZNIwjfeG/GBb9frpSX219k1O4Wi6OEbHEr8at/XQ0y7gTikOxBn/s5wQIDAQAB",
- "rDua7X+pZ0dXFZ5tfVdWcvnZgQCUHpve/+yhMTt1eC0="],
-}
+ {"name" : "venafi",
+ "url" : "https://ctlog.api.venafi.com/",
+ "key" : "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAolpIHxdSlTXLo1s6H1OCdpSj/4DyHDc8wLG9wVmLqy1lk9fz4ATVmm+/1iN2Nk8jmctUKK2MFUtlWXZBSpym97M7frGlSaQXUWyA3CqQUEuIJOmlEjKTBEiQAvpfDjCHjlV2Be4qTM6jamkJbiWtgnYPhJL6ONaGTiSPm7Byy57iaz/hbckldSOIoRhYBiMzeNoA0DiRZ9KmfSeXZ1rB8y8X5urSW+iBzf2SaOfzBvDpcoTuAaWx2DPazoOl28fP1hZ+kHUYvxbcMjttjauCFx+JII0dmuZNIwjfeG/GBb9frpSX219k1O4Wi6OEbHEr8at/XQ0y7gTikOxBn/s5wQIDAQAB",
+ "id" : "rDua7X+pZ0dXFZ5tfVdWcvnZgQCUHpve/+yhMTt1eC0="},
+]
diff --git a/monitor/verify_sct.py b/monitor/verify_sct.py
new file mode 100755
index 0000000..32e460d
--- /dev/null
+++ b/monitor/verify_sct.py
@@ -0,0 +1,239 @@
+#!/usr/bin/env python
+
+# Signed Certificate Timestamp TLS extension verifier
+# Copyright (c) 2015 Pier Carlo Chiodi - http://www.pierky.com
+#
+# https://github.com/pierky/sct-verify
+
+import sys
+import subprocess
+import base64
+import struct
+
+OPENSSL_PATH="/usr/local/ssl/bin/openssl"
+
+LOGS = [
+ { "Name": "Aviator",
+ "Key": "-----BEGIN PUBLIC KEY-----\n"
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1J\n"
+ "YP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q==\n"
+ "-----END PUBLIC KEY-----",
+ "LogID": "aPaY+B9kgr46jO65KB1M/HFRXWeT1ETRCmesu09P+8Q=" },
+
+ { "Name": "Digicert Log",
+ "Key": "-----BEGIN PUBLIC KEY-----\n"
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4+HCF\n"
+ "RkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs6A==\n"
+ "-----END PUBLIC KEY-----",
+ "LogID": "VhQGmi/XwuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ0N0=" },
+
+ { "Name": "Pilot",
+ "Key": "-----BEGIN PUBLIC KEY-----\n"
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHT\n"
+ "DM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA==\n"
+ "-----END PUBLIC KEY-----",
+ "LogID": "pLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BA=" },
+
+ { "Name": "Rocketeer",
+ "Key": "-----BEGIN PUBLIC KEY-----\n"
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIFsYyDzBi7MxCAC/oJBXK7dHjG+1\n"
+ "aLCOkHjpoHPqTyghLpzA9BYbqvnV16mAw04vUjyYASVGJCUoI3ctBcJAeg==\n"
+ "-----END PUBLIC KEY-----",
+ "LogID": "7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/cs=" },
+
+ { "Name": "Izenpe",
+ "Key": "-----BEGIN PUBLIC KEY-----\n"
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ2Q5DC3cUBj4IQCiDu0s6j51up+T\n"
+ "ZAkAEcQRF6tczw90rLWXkJMAW7jr9yc92bIKgV8vDXU4lDeZHvYHduDuvg==\n"
+ "-----END PUBLIC KEY-----",
+ "LogID": "dGG0oJz7PUHXUVlXWy52SaRFqNJ3CbDMVkpkgrfrQaM=" },
+
+ { "Name": "Certly",
+ "Key": "-----BEGIN PUBLIC KEY-----\n"
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECyPLhWKYYUgEc+tUXfPQB4wtGS2M\n"
+ "NvXrjwFCCnyYJifBtd2Sk7Cu+Js9DNhMTh35FftHaHu6ZrclnNBKwmbbSA==\n"
+ "-----END PUBLIC KEY-----",
+ "LogID": "zbUXm3/BwEb+6jETaj+PAC5hgvr4iW/syLL1tatgSQA=" }
+
+ ]
+
+if len( sys.argv ) <= 1:
+ print( "Missing hostname argument." )
+ print( "Usage: ./sct-verify hostname" )
+ print( "" )
+ print( "Example:" )
+ print( " ./sct-verify sni.velox.ch" )
+ print( "" )
+ print( "Known hosts implementing SCT TLS Extensions:" )
+ print( " - sni.velox.ch" )
+ print( " - ritter.vg" )
+ quit()
+
+HostName = sys.argv[1]
+
+Args = [ OPENSSL_PATH ]
+Args.extend( [ "s_client", "-serverinfo", "18", "-connect", "%s:443" % HostName, "-servername", HostName ])
+
+OpenSSL= subprocess.Popen( Args, stdin=open('/dev/null', 'r'), stdout=subprocess.PIPE, stderr=subprocess.PIPE )
+OpenSSL_stdout, OpenSSL_stderr = OpenSSL.communicate()
+OpenSSL_exitcode = OpenSSL.wait()
+
+if OpenSSL_exitcode != 0:
+ print("OpenSSL can't connect to %s" % HostName)
+ print(OpenSSL_stderr)
+ quit()
+
+ServerInfo18 = ""
+ServerInfo18_Add = False
+EECert = ""
+EECert_Add = False
+for L in OpenSSL_stdout.split('\n'):
+ if L == "-----BEGIN SERVERINFO FOR EXTENSION 18-----":
+ ServerInfo18_Add = True
+ elif L == "-----END SERVERINFO FOR EXTENSION 18-----":
+ ServerInfo18_Add = False
+ elif L == "-----BEGIN CERTIFICATE-----":
+ EECert_Add = True
+ elif L == "-----END CERTIFICATE-----":
+ EECert_Add = False
+ elif ServerInfo18_Add:
+ if ServerInfo18:
+ ServerInfo18 = ServerInfo18 + '\n'
+ ServerInfo18 = ServerInfo18 + L
+ elif EECert_Add:
+ if EECert:
+ EECert = EECert + '\n'
+ EECert = EECert + L
+
+EECertDER = base64.b64decode( EECert )
+
+Data = base64.b64decode( ServerInfo18 )
+DataLen = len(Data)
+
+def ToHex( v ):
+ if type(v) is int or type(v) is long:
+ return hex(v)
+ else:
+ return ":".join("{:02x}".format(ord(c)) for c in v)
+
+def Read( buf, offset, format ):
+ Values = struct.unpack_from( format, buf, offset )
+ NewOffset = offset + struct.calcsize( format )
+
+ Ret = ()
+ Ret = Ret + ( NewOffset, )
+ Ret = Ret + Values
+ return Ret
+
+def ReadSCT( SCT ):
+ print("===========================================================")
+ Offset = 0
+
+ Offset, SCTVersion = Read( SCT, Offset, "!B" )
+
+ Offset, SCTLogID = Read( SCT, Offset, "!32s" )
+ Base64LogID = base64.b64encode( SCTLogID )
+
+ Offset, SCTTimestamp = Read( SCT, Offset, "!Q" )
+
+ Offset, SCTExtensionsLen = Read( SCT, Offset, "!H" )
+
+ #FIXME
+ if SCTExtensionsLen > 0:
+ print("Extensions length > 0; not implemented")
+ return
+
+ Offset, SCTSignatureAlgHash = Read( SCT, Offset, "!B" )
+ Offset, SCTSignatureAlgSign = Read( SCT, Offset, "!B" )
+
+ Offset, SCTSignatureLen = Read( SCT, Offset, "!H" )
+ Offset, SCTSignature = Read( SCT, Offset, "!%ss" % SCTSignatureLen )
+
+ # print SCT information
+
+ print( "Version : %s" % ToHex( SCTVersion ) )
+ SCTLogID1, SCTLogID2 = struct.unpack( "!16s16s", SCTLogID )
+ print( "LogID : %s" % ToHex( SCTLogID1 ) )
+ print( " %s" % ToHex( SCTLogID2 ) )
+ print( "LogID b64 : %s" % Base64LogID )
+ print( "Timestamp : %s (%s)" % ( SCTTimestamp, ToHex( SCTTimestamp ) ) )
+ print( "Extensions: %s (%s)" % ( SCTExtensionsLen, ToHex( SCTExtensionsLen )) )
+ print( "Algorithms: %s/%s (hash/sign)" % ( ToHex( SCTSignatureAlgHash ), ToHex ( SCTSignatureAlgSign ) ))
+
+ SigOffset = 0
+ while SigOffset < len( SCTSignature ):
+ if len( SCTSignature ) - SigOffset > 16:
+ SigBytesToRead = 16
+ else:
+ SigBytesToRead = len( SCTSignature ) - SigOffset
+ SigBytes = struct.unpack_from( "!%ss" % SigBytesToRead, SCTSignature, SigOffset )[0]
+
+ if SigOffset == 0:
+ print( "Signature : %s" % ToHex( SigBytes ) )
+ else:
+ print( " %s" % ToHex( SigBytes ) )
+
+ SigOffset = SigOffset + SigBytesToRead
+
+ # look for signing log and its key
+
+ PubKey = None
+ for Log in LOGS:
+ if Log["LogID"] == Base64LogID:
+ print( "Log found : %s" % Log["Name"])
+ PubKey = Log["Key"]
+
+ if not PubKey:
+ print("Log not found")
+ return
+
+ # signed data
+
+ # 1 version
+ # 1 signature_type
+ # 8 timestamp
+ # 2 entry_type
+ # 3 DER lenght
+ # x DER
+ # 2 extensions length
+
+ EECertDERLen = len( EECertDER )
+ _, EECertDERLen1, EECertDERLen2, EECertDERLen3 = struct.unpack( "!4B", struct.pack( "!I", EECertDERLen ) )
+
+ Data = struct.pack("!BBQhBBB%ssh" % len( EECertDER ), SCTVersion, 0, SCTTimestamp, 0, EECertDERLen1, EECertDERLen2, EECertDERLen3, EECertDER, SCTExtensionsLen )
+
+ File = open("tmp-signeddata.bin", "wb")
+ File.write( Data )
+ File.close()
+
+ File = open("tmp-pubkey.pem", "w")
+ File.write( PubKey )
+ File.close()
+
+ File = open("tmp-signature.bin", "wb")
+ File.write( SCTSignature )
+ File.close()
+
+ Args = [ OPENSSL_PATH ]
+ Args.extend( [ "dgst", "-sha256", "-verify", "tmp-pubkey.pem", "-signature", "tmp-signature.bin", "tmp-signeddata.bin" ] )
+
+ OpenSSL= subprocess.Popen( Args, stdin=open('/dev/null', 'r'), stdout=subprocess.PIPE, stderr=subprocess.PIPE )
+ OpenSSL_stdout, OpenSSL_stderr = OpenSSL.communicate()
+ OpenSSL_exitcode = OpenSSL.wait()
+
+ if OpenSSL_exitcode == 0:
+ print( "Result : %s" % OpenSSL_stdout )
+ else:
+ print( "OpenSSL error - Exit code %d" % OpenSSL_exitcode )
+ print( OpenSSL_stderr )
+
+Offset = 0
+Offset, TLS_ExtensionType, TLS_ExtensionLen = Read( Data, Offset, "!HH" )
+Offset, SignedCertificateTimestampListLen = Read( Data, Offset, "!H" )
+
+while Offset < DataLen:
+ Offset, SCTLen = Read( Data, Offset, "!H" )
+ Offset, SCT = Read( Data, Offset, "!%ss" % SCTLen )
+ # print SCT
+ ReadSCT( SCT )
+