summaryrefslogtreecommitdiff
path: root/support/ctlogconfig
diff options
context:
space:
mode:
authorJeff Trawick <trawick@apache.org>2014-04-21 21:14:21 +0000
committerJeff Trawick <trawick@apache.org>2014-04-21 21:14:21 +0000
commitc51e4d9cbc1e6185aab143c2670410d3b94eb1e8 (patch)
tree1522f719de513232ab7974b32ba1a8281cd0a8c3 /support/ctlogconfig
parent723c099e7aa98b273f875125098cd0d4b37fa079 (diff)
downloadhttpd-c51e4d9cbc1e6185aab143c2670410d3b94eb1e8.tar.gz
Add module mod_ssl_ct, which provides an implementation of Certificate
Transparency (RFC 6962) for httpd. mod_ssl_ct requires OpenSSL 1.0.2 (in beta) and must be explicitly enabled via configure. Note that support/ctauditscts is purposefully not installed; it does not properly function due to a dependency on a certificate-transparency open source project tool which itself is not sufficiently complete at this time. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1588987 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'support/ctlogconfig')
-rwxr-xr-xsupport/ctlogconfig313
1 files changed, 313 insertions, 0 deletions
diff --git a/support/ctlogconfig b/support/ctlogconfig
new file mode 100755
index 0000000000..4ebef5cb07
--- /dev/null
+++ b/support/ctlogconfig
@@ -0,0 +1,313 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import re
+import sqlite3
+import sys
+
+
+def create_tables(db_name):
+ cxn = sqlite3.connect(db_name)
+ cur = cxn.cursor()
+
+ cur.execute(
+ 'CREATE TABLE loginfo('
+ + 'id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, '
+ + 'log_id TEXT, '
+ + 'public_key TEXT, ' # path to PEM-encoded file
+ + 'distrusted INTEGER, ' # non-zero if not trusted
+ + 'min_valid_timestamp INTEGER, '
+ + 'max_valid_timestamp INTEGER, '
+ + 'url TEXT)'
+ )
+ cur.close()
+ cxn.commit()
+ cxn.close()
+
+
+def record_id_arg(cur, args, required=False):
+ if len(args) < 1 or args[0][0] != '#' or len(args[0]) < 2:
+ if required:
+ print >> sys.stderr, 'A record id was not provided'
+ sys.exit(1)
+ return None
+ record_id = args.pop(0)[1:]
+ stmt = 'SELECT * FROM loginfo WHERE id = ?'
+ cur.execute(stmt, [record_id])
+ recs = list(cur.fetchall())
+ assert len(recs) < 2
+ if len(recs) == 0:
+ print >> sys.stderr, 'Record #%s was not found' % record_id
+ sys.exit(1)
+ return record_id
+
+
+def log_id_arg(cur, args, required=True):
+ if len(args) < 1 or len(args[0]) != 64:
+ if not required:
+ return None
+ print >> sys.stderr, 'A log id was not provided'
+ sys.exit(1)
+ log_id = args.pop(0).upper()
+ if len(re.compile(r'[A-Z0-9]').findall(log_id)) != len(log_id):
+ print >> sys.stderr, 'The log id is not formatted properly'
+ sys.exit(1)
+ return log_id
+
+
+def public_key_arg(args):
+ if len(args) < 1:
+ print >> sys.stderr, 'A public key file was not provided'
+ sys.exit(1)
+ pubkey = args.pop(0)
+ if not os.path.exists(pubkey):
+ print >> sys.stderr, 'Public key file %s could not be read' % pubkey
+ sys.exit(1)
+ return pubkey
+
+
+def time_arg(args):
+ if len(args) < 1:
+ print >> sys.stderr, 'A timestamp was not provided'
+ sys.exit(1)
+ t = args.pop(0)
+ if t == '-':
+ return None
+ try:
+ return int(t)
+ except ValueError:
+ print >> sys.stderr, 'The timestamp "%s" is invalid' % t
+ sys.exit(1)
+
+
+def configure_public_key(cur, args):
+ record_id = record_id_arg(cur, args, False)
+ public_key = public_key_arg(args)
+ if len(args) != 0:
+ usage()
+ if not record_id:
+ stmt = 'INSERT INTO loginfo (public_key) VALUES(?)'
+ cur.execute(stmt, [public_key])
+ else:
+ stmt = 'UPDATE loginfo SET public_key = ? WHERE id = ?'
+ cur.execute(stmt, [public_key, record_id])
+
+
+def configure_url(cur, args):
+ # can't specify more than one of record-id and log-id
+ log_id = None
+ record_id = record_id_arg(cur, args, False)
+ if not record_id:
+ log_id = log_id_arg(cur, args, False)
+ if len(args) != 1:
+ usage()
+ url = args.pop(0)
+
+ if record_id:
+ stmt = 'UPDATE loginfo SET url = ? WHERE id = ?'
+ args = [url, record_id]
+ elif log_id:
+ stmt = 'INSERT INTO loginfo (log_id, url) VALUES(?, ?)'
+ args = [log_id, url]
+ else:
+ stmt = 'INSERT INTO loginfo (url) VALUES(?)'
+ args = [url]
+
+ cur.execute(stmt, args)
+
+
+def forget_log(cur, args):
+ record_id = record_id_arg(cur, args, False)
+ log_id = None
+ if not record_id:
+ log_id = log_id_arg(cur, args, True)
+ if len(args) != 0:
+ usage()
+ if record_id:
+ stmt = 'DELETE FROM loginfo WHERE id = ?'
+ args = [record_id]
+ else:
+ stmt = 'DELETE FROM loginfo WHERE log_id = ?'
+ args = [log_id]
+ cur.execute(stmt, args)
+
+
+def trust_distrust_log(cur, args):
+ # could take a record id or a log id
+ record_id = record_id_arg(cur, args, False)
+ if record_id:
+ log_id = None
+ else:
+ log_id = log_id_arg(cur, args)
+
+ if len(args) != 1:
+ usage()
+ flag = args.pop(0)
+
+ if not record_id:
+ stmt = 'INSERT INTO loginfo (log_id, distrusted) VALUES(?, ?)'
+ cur.execute(stmt, [log_id, flag])
+ else:
+ stmt = 'UPDATE loginfo SET distrusted = ? WHERE id = ?'
+ cur.execute(stmt, [flag, record_id])
+
+
+def trust_log(cur, args):
+ trust_distrust_log(cur, args + [0])
+
+
+def distrust_log(cur, args):
+ trust_distrust_log(cur, args + [1])
+
+
+def time_range(cur, args):
+ # could take a record id or a log id
+ record_id = record_id_arg(cur, args, False)
+ if record_id:
+ log_id = None
+ else:
+ log_id = log_id_arg(cur, args)
+
+ min_valid_time = time_arg(args)
+ max_valid_time = time_arg(args)
+ if len(args) != 0:
+ usage()
+ if not record_id:
+ stmt = 'INSERT INTO loginfo ' + \
+ '(log_id, min_valid_timestamp, max_valid_timestamp) ' + \
+ 'VALUES(?, ?, ?)'
+ cur.execute(stmt, [log_id, min_valid_time, max_valid_time])
+ else:
+ stmt = 'UPDATE loginfo SET min_valid_timestamp = ?, ' + \
+ 'max_valid_timestamp = ? WHERE id = ?'
+ cur.execute(stmt, [min_valid_time, max_valid_time, record_id])
+
+
+class ConfigEntry:
+
+ pass
+
+
+def dump_ll(cur):
+ stmt = 'SELECT * FROM loginfo'
+ cur.execute(stmt)
+ recs = []
+ for row in cur.fetchall():
+ obj = ConfigEntry()
+ obj.id = row[0]
+ obj.log_id = row[1]
+ obj.public_key = row[2]
+ obj.distrusted = row[3]
+ obj.min_valid_timestamp = row[4]
+ obj.max_valid_timestamp = row[5]
+ obj.url = row[6]
+ recs += [obj]
+ return recs
+
+
+def dump(cur, args):
+ if len(args) != 0:
+ usage()
+ recs = dump_ll(cur)
+ for rec in recs:
+ not_conf = '(not configured)'
+
+ mint = \
+ str(rec.min_valid_timestamp) if rec.min_valid_timestamp else '-INF'
+ maxt = \
+ str(rec.max_valid_timestamp) if rec.max_valid_timestamp else '+INF'
+ print 'Log entry:'
+ print ' Record ' + str(rec.id) + \
+ (' (DISTRUSTED)' if rec.distrusted else '')
+ print ' Log id : ' + (rec.log_id if rec.log_id else not_conf)
+ print ' Public key file: ' + \
+ (rec.public_key if rec.public_key else not_conf)
+ print ' URL : ' + (rec.url if rec.url else not_conf)
+ print ' Time range : ' + mint + ' to ' + maxt
+ print ''
+
+
+def usage():
+ help = """Usage: %s /path/to/log-config-db command args
+
+Commands:
+ display config-db contents:
+ dump
+ configure public key:
+ configure-public-key [log-id|record-id] /path/log-pub-key.pem
+ configure URL:
+ configure-url [log-id|record-id] http://www.example.com/path/
+ configure min and/or max valid timestamps:
+ valid-time-range log-id|record-id min-range max-range
+ mark log as trusted (default):
+ trust log-id|record-id
+ mark log as untrusted:
+ distrust log-id|record-id
+ remove log config from config-db:
+ forget log-id|record-id
+
+log-id is a 64-character hex string representation of a log id
+
+record-id references an existing entry and is in the form:
+ #<record-number>
+ (displayable with the dump command)
+""" % sys.argv[0]
+ print >> sys.stderr, help
+ sys.exit(1)
+
+
+def main(argv):
+ if len(argv) < 3:
+ usage()
+
+ db_name = argv[1]
+ cmd = argv[2]
+ args = argv[3:]
+
+ cmds = {'configure-public-key': configure_public_key,
+ 'configure-url': configure_url,
+ 'distrust': distrust_log,
+ 'trust': trust_log,
+ 'forget': forget_log,
+ 'valid-time-range': time_range,
+ 'dump': dump,
+ }
+
+ cmds_requiring_db = ['dump', 'forget'] # db must already exist
+
+ if not cmd in cmds:
+ usage()
+
+ if not os.path.exists(db_name):
+ if not cmd in cmds_requiring_db:
+ create_tables(db_name)
+ else:
+ print >> sys.stderr, 'Database "%s" does not exist' % db_name
+ sys.exit(1)
+
+ cxn = sqlite3.connect(db_name)
+ cur = cxn.cursor()
+
+ cmds[cmd](cur, args)
+
+ cur.close()
+ cxn.commit()
+ cxn.close()
+
+if __name__ == "__main__":
+ main(sys.argv)