aboutsummaryrefslogtreecommitdiff
path: root/scripts/rp-sqlite
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/rp-sqlite')
-rwxr-xr-xscripts/rp-sqlite148
1 files changed, 110 insertions, 38 deletions
diff --git a/scripts/rp-sqlite b/scripts/rp-sqlite
index 56f0c440..4926bb93 100755
--- a/scripts/rp-sqlite
+++ b/scripts/rp-sqlite
@@ -29,7 +29,10 @@
import os
import sys
+import yaml
+import base64
import sqlite3
+import weakref
import rpki.POW
import rpki.x509
import rpki.resource_set
@@ -43,13 +46,18 @@ sqlite3.register_converter("RangeVal",
def main():
rpdb = RPDB()
+ rpdb.load()
test(rpdb)
rpdb.close()
-
def test(rpdb):
fn2s = [None] + rpdb.fn2map.keys()
+ print
+ print "Testing YAML parsing"
+ parse_yaml(rpdb)
+
+ print
print "Testing range functions"
for fn2 in fn2s:
if fn2 is not None:
@@ -84,11 +92,82 @@ def test(rpdb):
print "Trying", expr
for r in rpdb.find_by_resource_bag(rpki.resource_set.resource_bag.from_str(expr), fn2):
print r, r.uris
-
+
+
+def parse_xki(s):
+ """
+ Parse text form of an SKI or AKI. We accept two encodings:
+ colon-delimited hexadecimal, and URL-safe Base64. The former is
+ what OpenSSL prints in its text representation of SKI and AKI
+ extensions; the latter is the g(SKI) value that some RPKI CA engines
+ (including rpkid) use when constructing filenames.
+
+ In either case, we check that the decoded result contains the right
+ number of octets to be a SHA-1 hash.
+ """
+
+ if ":" in s:
+ b = "".join(chr(int(c, 16)) for c in s.split(":"))
+ else:
+ b = base64.urlsafe_b64decode(s + ("=" * (4 - len(s) % 4)))
+ if len(b) != 20:
+ raise RuntimeError("Bad length for SHA1 xKI value: %r" % s)
+ return b
+
+
+def parse_yaml(rpdb, fn = "rp-sqlite.yaml"):
+ yy = yaml.safe_load(open(fn, "r"))
+ for y in yy:
+
+ ski = None
+ uri = None
+ obj = set()
+
+ print
+
+ if "ski" in y:
+ ski = parse_xki(y["ski"])
+ obj.update(rpdb.find_by_ski(ski))
+ if "uri" in y:
+ uri = y["uri"]
+ obj.update(rpdb.find_by_uri(uri))
+ if len(obj) == 1:
+ obj = obj.pop()
+ else:
+ raise RuntimeError("Policy entry must name a unique object using SKI, URI, or both (%r, %r, %r)" % (
+ ski, uri, obj))
+
+ print "URI:", uri
+ print "SKI:", " ".join("%02X" % ord(c) for c in ski), "(" + y["ski"] + ")"
+
+ new_resources = old_resources = obj.get_3779resources()
+
+ if "set" in y:
+ new_resources = rpki.resource_set.resource_bag.from_str(y["set"])
+
+ if "add" in y:
+ new_resources = new_resources | rpki.resource_set.resource_bag.from_str(y["add"])
+
+ if "sub" in y:
+ new_resources = new_resources - rpki.resource_set.resource_bag.from_str(y["sub"])
+
+ if new_resources == old_resources:
+ print "No resource change, skipping"
+ continue
+
+ print "Old:", old_resources
+ print "New:", new_resources
+ print "Add:", new_resources - old_resources
+ print "Sub:", old_resources - new_resources
+
class RPDB(object):
"""
Relying party database.
+
+ For now just wire in the database name and rcynic root, fix this
+ later if overall approach seems usable. Might even end up just
+ being an in-memory SQL database, who knows?
"""
fn2map = dict(cer = rpki.x509.X509,
@@ -97,16 +176,7 @@ class RPDB(object):
roa = rpki.x509.ROA,
gbr = rpki.x509.Ghostbuster)
- def __init__(self,
- db_name = "rp-sqlite.db",
- rcynic_root = os.path.expanduser("~/rpki/subvert-rpki.hactrn.net/trunk/"
- "rcynic/rcynic-data/unauthenticated"),
- delete_old_db = True,
- spinner = 100):
-
- # For now just wire in the database name and rcynic root, fix this
- # later if overall approach seems usable. Might even end up just
- # being an in-memory SQL database, who knows?
+ def __init__(self, db_name = "rp-sqlite.db", delete_old_db = True):
if delete_old_db:
try:
@@ -114,10 +184,17 @@ class RPDB(object):
except:
pass
+ exists = os.path.exists(db_name)
+
self.db = sqlite3.connect(db_name, detect_types = sqlite3.PARSE_DECLTYPES)
self.db.text_factory = str
-
self.cur = self.db.cursor()
+
+ self.cache = weakref.WeakValueDictionary()
+
+ if exists:
+ return
+
self.cur.executescript('''
PRAGMA foreign_keys = on;
@@ -152,6 +229,11 @@ class RPDB(object):
CREATE INDEX range_index ON range(min, max);
''')
+ def load(self,
+ rcynic_root = os.path.expanduser("~/rpki/subvert-rpki.hactrn.net/trunk/"
+ "rcynic/rcynic-data/unauthenticated"),
+ spinner = 100):
+
nobj = 0
for root, dirs, files in os.walk(rcynic_root):
@@ -224,25 +306,13 @@ class RPDB(object):
def find_by_ski(self, ski, fn2 = None):
- return self._find_results(
- fn2,
- """
- SELECT id, fn2, der
- FROM object
- WHERE ski = ?
- """,
- [buffer(ski)])
-
+ return self._find_results(fn2, "SELECT id, fn2, der FROM object WHERE ski = ?", [buffer(ski)])
def find_by_aki(self, aki, fn2 = None):
- return self._find_results(
- fn2,
- """
- SELECT id, fn2, der
- FROM object
- WHERE aki = ?
- """,
- [buffer(aki)])
+ return self._find_results(fn2, "SELECT id, fn2, der FROM object WHERE aki = ?", [buffer(aki)])
+
+ def find_by_uri(self, uri):
+ return self._find_results(None, "SELECT object.id, fn2, der FROM object, uri WHERE uri.uri = ? AND object.id = uri.id", [uri])
# It's easiest to understand overlap conditions by understanding
@@ -262,8 +332,7 @@ class RPDB(object):
return self._find_results(
fn2,
"""
- SELECT object.id, fn2, der
- FROM object, range
+ SELECT object.id, fn2, der FROM object, range
WHERE ? <= max AND ? >= min AND object.id = range.id
""",
[range_min, range_max])
@@ -282,8 +351,7 @@ class RPDB(object):
return self._find_results(
fn2,
"""
- SELECT object.id, fn2, der
- FROM object, range
+ SELECT object.id, fn2, der FROM object, range
WHERE object.id = range.id AND (%s)
""" % (" OR ".join(qset)),
aset)
@@ -299,10 +367,14 @@ class RPDB(object):
self.cur.execute(query, args)
selections = self.cur.fetchall()
for rowid, fn2, der in selections:
- obj = self.fn2map[fn2](DER = der)
- self.cur.execute("SELECT uri FROM uri WHERE id = ?", (rowid,))
- obj.uris = [u[0] for u in self.cur.fetchall()]
- obj.uri = obj.uris[0] if len(obj.uris) == 1 else None
+ if rowid in self.cache:
+ obj = self.cache[rowid]
+ else:
+ obj = self.fn2map[fn2](DER = der)
+ self.cur.execute("SELECT uri FROM uri WHERE id = ?", (rowid,))
+ obj.uris = [u[0] for u in self.cur.fetchall()]
+ obj.uri = obj.uris[0] if len(obj.uris) == 1 else None
+ self.cache[rowid] = obj
results.append(obj)
return results