aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2013-10-03 21:04:20 +0000
committerRob Austein <sra@hactrn.net>2013-10-03 21:04:20 +0000
commitb3eb006675c43ac69b41955ece0368f82ac04489 (patch)
tree35278467bb526dcfa48738a69a298deb0d82a260 /scripts
parent0f4e6b81d500fea8d8cc5050f7c48b3b8e3fa1f4 (diff)
Archive what now looks like another blind alley.
svn path=/trunk/; revision=5540
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/rcynic-lta382
-rw-r--r--scripts/rcynic-lta.yaml31
2 files changed, 113 insertions, 300 deletions
diff --git a/scripts/rcynic-lta b/scripts/rcynic-lta
index 36a7f8a8..e1a80fc3 100755
--- a/scripts/rcynic-lta
+++ b/scripts/rcynic-lta
@@ -71,6 +71,8 @@ ltacrl = ltauri + "/lta.crl"
cer_delta = rpki.sundial.timedelta(days = 7)
crl_delta = rpki.sundial.timedelta(hours = 1)
+all_mentioned_resources = rpki.resource_set.resource_bag()
+
# Teach SQLite3 about our data types.
sqlite3.register_adapter(rpki.POW.IPAddress,
@@ -97,18 +99,15 @@ def main():
print
print "Loading DB"
rpdb.load()
+
print
- print "Validating DB"
- rpdb.validate()
- print
- print "Processing targets"
- process_targets(rpdb)
- print
- print "Processing ancestors"
- process_ancestors(rpdb)
+ print "Compute resources we need to prune from input forest"
+ compute_all_mentioned_resources()
+
print
- print "Processing trees"
- process_trees(rpdb)
+ print "Processing deletions"
+ process_constraint_deletions(rpdb)
+
print
print "Re-parenting TAs"
re_parent_tas(rpdb)
@@ -119,35 +118,12 @@ def main():
print "Committing final changes to DB"
rpdb.commit()
print
- print "Linking source tree"
- link_tree()
- print
print "Dumping para-objects"
rpdb.dump_paras()
print
print "Closing DB"
rpdb.close()
-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 create_ca(rpdb):
global serial
@@ -167,8 +143,8 @@ def create_ca(rpdb):
sia = (ltasia, ltamft, None),
notAfter = rpki.sundial.now() + cer_delta,
resources = rpki.resource_set.resource_bag.from_str("0-4294967295,0.0.0.0/0,::/0"))
- rpdb.cur.execute("INSERT INTO object (der, fn2, ski, aki, issuer, subject, nochain, para) "
- "VALUES (?, 'cer', ?, NULL, ?, ?, 0, 1)",
+ rpdb.cur.execute("INSERT INTO object (der, fn2, ski, aki, issuer, subject, para) "
+ "VALUES (?, 'cer', ?, NULL, ?, ?, 1)",
(buffer(cer.get_DER()), buffer(cer.get_SKI()), cer.getIssuer(), cer.getSubject()))
rowid = rpdb.cur.lastrowid
rpdb.cur.execute("INSERT INTO uri (id, uri) VALUES (?, ?)", (rowid, ltaaia))
@@ -177,31 +153,28 @@ def create_ca(rpdb):
class Constraint(object):
+ roa_asn = None
+ roa_maxlen = None
+ router_cert_key = None
+ router_cert_subject = None
+
def __init__(self, y):
- self.ski = parse_xki(y["ski"]) if "ski" in y else None
- self.uri = y.get("uri", None)
- self.set = rpki.resource_set.resource_bag.from_str(y.get("set", ""))
- self.add = rpki.resource_set.resource_bag.from_str(y.get("add", ""))
- self.sub = rpki.resource_set.resource_bag.from_str(y.get("sub", ""))
-
- def find(self, rpdb):
- found = rpdb.find_by_ski_or_uri(self.ski, self.uri)
- if len(found) == 0:
- print "Constraint entry matched nothing (%s %s)" % (ski, uri)
- elif len(found) > 1:
- print "Constraint entry matched multiple objects, skipping (%s %s %r)" % (ski, uri, found)
- else:
- return found[0]
+ self.prefixes = rpki.resource_set.resource_bag.from_str(str(y.get("prefix", "")))
+ self.asns = rpki.resource_set.resource_bag.from_str(str(y.get("asn", "")))
+ self.ghostbuster = y.get("ghostbuster")
+
+ if "roa" in y:
+ self.roa_asn = long(y["roa"]["asn"])
+ if "maxlen" in y["roa"]:
+ self.roa_maxlen = long(y["roa"]["maxlen"])
- def constrained_resources(self, obj):
- r = self.set or obj.get_3779resources()
- r |= self.add
- r -= self.sub
- return r
+ if "router-cert" in y:
+ self.router_cert_key = y["router-cert"]["key"]
+ self.router_cert_subject = y["router-cert"]["subject"]
@property
def mentioned_resources(self):
- return self.set | self.add | self.sub
+ return self.prefixes | self.asns
def parse_yaml(fn = "rcynic-lta.yaml"):
@@ -217,6 +190,7 @@ def parse_yaml(fn = "rcynic-lta.yaml"):
keyfile = y["keyfile"]
constraints = [Constraint(yy) for yy in y["constraints"]]
+
def parse_tals():
global tals
tals = {}
@@ -227,37 +201,22 @@ def parse_tals():
tals[uri] = key
-def process_targets(rpdb):
+def compute_all_mentioned_resources():
+ global all_mentioned_resources
for constraint in constraints:
- obj = constraint.find(rpdb)
- if obj is not None:
- obj.target = True
- rpdb.add_para(obj, constraint.constrained_resources(obj))
-
+ all_mentioned_resources |= constraint.mentioned_resources
-def process_ancestors(rpdb):
- for target in rpdb.find_targets():
- target_resources = target.resources
- for ancestor in rpdb.find_ancestors(target):
- resources = ancestor.para_resources - target_resources
- if resources:
- rpdb.add_para(ancestor, resources)
-
-def process_trees(rpdb):
- for constraint in constraints:
- mentioned_resources = constraint.mentioned_resources
- if mentioned_resources:
- for obj in rpdb.find_by_resource_bag(mentioned_resources, "cer"):
- if not obj.target:
- rpdb.add_para(obj, obj.resources - mentioned_resources)
+def process_constraint_deletions(rpdb):
+ for obj in rpdb.find_by_resource_bag(all_mentioned_resources):
+ rpdb.add_para(obj, obj.resources - all_mentioned_resources)
def re_parent_tas(rpdb):
for uri, key in tals.iteritems():
for ta in rpdb.find_by_ski_or_uri(key.calculateSKI(), uri):
if ta.para_obj is None:
- rpdb.add_para(ta, ta.resources)
+ rpdb.add_para(ta, ta.resources - all_mentioned_resources)
def generate_crl_and_manifest(rpdb):
@@ -275,8 +234,8 @@ def generate_crl_and_manifest(rpdb):
nextUpdate = nextUpdate,
revokedCertificates = ())
- rpdb.cur.execute("INSERT INTO object (der, fn2, ski, aki, issuer, subject, nochain, para) "
- "VALUES (?, 'crl', NULL, ?, ?, NULL, 0, 1)",
+ rpdb.cur.execute("INSERT INTO object (der, fn2, ski, aki, issuer, subject, para) "
+ "VALUES (?, 'crl', NULL, ?, ?, NULL, 1)",
(buffer(crl.get_DER()), aki, issuer))
rowid = rpdb.cur.lastrowid
rpdb.cur.execute("INSERT INTO uri (id, uri) VALUES (?, ?)", (rowid, ltacrl))
@@ -303,24 +262,13 @@ def generate_crl_and_manifest(rpdb):
keypair = key,
certs = cer)
- rpdb.cur.execute("INSERT INTO object (der, fn2, ski, aki, issuer, subject, nochain, para) "
- "VALUES (?, 'mft', ?, ?, ?, ?, 0, 1)",
+ rpdb.cur.execute("INSERT INTO object (der, fn2, ski, aki, issuer, subject, para) "
+ "VALUES (?, 'mft', ?, ?, ?, ?, 1)",
(buffer(mft.get_DER()), buffer(cer.get_SKI()), aki, issuer, cer.getSubject()))
rowid = rpdb.cur.lastrowid
rpdb.cur.execute("INSERT INTO uri (id, uri) VALUES (?, ?)", (rowid, ltamft))
-def link_tree():
- sroot = os.path.abspath(rcynic_input)
- droot = os.path.abspath(rcynic_output)
- shutil.rmtree(droot, ignore_errors = True)
- for sdir, dirs, files in os.walk(sroot):
- ddir = droot + sdir[len(sroot):]
- os.makedirs(ddir)
- for fn in files:
- os.link(os.path.join(sdir, fn), os.path.join(ddir, fn))
-
-
class DER_object_mixin(object):
"""
Mixin to add some SQL-related methods to classes derived from
@@ -329,12 +277,8 @@ class DER_object_mixin(object):
_rpdb = None
_rowid = None
- _nochain = True
- _original = False
_para = False
_target = False
- _left = None
- _right = None
_para_id = None
_orig_id = None
@@ -343,14 +287,6 @@ class DER_object_mixin(object):
return self._rowid
@property
- def left(self):
- return self._left
-
- @property
- def right(self):
- return self._right
-
- @property
def resources(self):
return self.get_3779resources()
@@ -380,22 +316,6 @@ class DER_object_mixin(object):
#self._rpdb.db.commit()
@property
- def nochain(self):
- return self._nochain
-
- @nochain.setter
- def nochain(self, value):
- self._update_bool("nochain", value)
-
- @property
- def original(self):
- return self._original
-
- @original.setter
- def original(self, value):
- self._update_bool("original", value)
-
- @property
def para(self):
return self._para
@@ -437,121 +357,6 @@ class VerifyContextNoRFC3779(rpki.POW.X509StoreCTX):
return ok or self.getError() in (rpki.POW.X509_V_ERR_UNNESTED_RESOURCE,
rpki.POW.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
-
-class Verifier(object):
- """
- Perform X.509 and CMS validation checks and store markers indicating
- shape of the resulting tree in SQL.
- """
-
- # http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
-
- def __init__(self, rpdb):
- self.rpdb = rpdb
- self.counter = 0
-
- self.store = rpki.POW.X509Store()
- self.store.setFlags(rpki.POW.X509_V_FLAG_CRL_CHECK_ALL)
- self.store.setContextClass(VerifyContextNoRFC3779)
-
- self.spin = 0
- self.start = rpki.sundial.now()
-
- for uri, key in tals.iteritems():
- self.rpdb.cur.execute(
- "SELECT id, der FROM object WHERE nochain = 1 AND fn2 = 'cer' AND ski = ?",
- (buffer(key.calculateSKI()),))
- for rowid, der in self.rpdb.cur.fetchall():
- cer = rpki.POW.X509.derRead(der)
- if cer.getPublicKey().derWritePublic() == key.derWritePublic():
- self.rpdb.cur.execute("UPDATE object SET nochain = 0 WHERE id = ?", (rowid,))
- self.walk_tree(cer, rowid)
- else:
- sys.stderr.write("TAL public key mismatch for %s\n" % uri)
-
- self.rpdb.cur.execute(
- "SELECT object.id, uri FROM object, uri WHERE uri.id = object.id AND nochain = 1")
- for rowid, uri in self.rpdb.cur.fetchall():
- sys.stderr.write("Unchained %s\n" % uri)
-
- sys.stderr.write("\r= %d objects in %s, committing..." % (
- (self.counter + 1) / 2, rpki.sundial.now() - self.start))
-
- #self.rpdb.cur.execute("DELETE FROM object WHERE nochain = 1")
- self.rpdb.db.commit()
-
- sys.stderr.write("done.\n")
-
-
- def query(self, where, args):
- self.rpdb.cur.execute(
- "SELECT id, der FROM object WHERE nochain = 1 AND aki = ? AND issuer = ? AND " + where,
- args)
- return self.rpdb.cur.fetchall()
-
-
- def next_counter(self):
- self.counter += 1
- return self.counter
-
-
- def walk_tree(self, issuer, issuer_id):
- issuer_key = issuer.getPublicKey()
- self.store.addTrust(issuer)
-
- self.rpdb.cur.execute(
- "UPDATE object SET nochain = 0, left_ = ? WHERE id = ?",
- (self.next_counter(), issuer_id))
-
- self.spin += 1
- sys.stderr.write("\r%s %d %s...\r" % ("|\\-/"[self.spin & 3],
- (self.counter + 1) / 2,
- rpki.sundial.now() - self.start))
-
- args = (buffer(issuer.getSKI()), rpki.x509.X501DN.from_POW(issuer.getSubject()))
-
- for rowid, der in self.query("fn2 = 'crl'", args):
- crl = rpki.POW.CRL.derRead(der)
- if crl.verify(issuer_key):
- self.rpdb.cur.execute(
- "UPDATE object SET nochain = 0, left_ = ?, right_ = ? WHERE id = ?",
- (self.next_counter(), self.next_counter(), rowid))
- self.store.addCrl(crl)
- else:
- sys.stderr.write("CRL check failed for %s\n" % " ".join(self.rpdb.find_uris(rowid)))
-
- for rowid, der in self.query("fn2 <> 'crl' AND fn2 <> 'cer'", args):
- obj = rpki.POW.CMS.derRead(der)
- try:
- for cer in obj.certs():
- ctx = self.store.verify(cer)
- if ctx.getError():
- raise RuntimeError(ctx.getErrorString())
- obj.verify(self.store, flags = rpki.POW.CMS_NO_SIGNER_CERT_VERIFY)
- self.rpdb.cur.execute(
- "UPDATE object SET nochain = 0, left_ = ?, right_ = ? WHERE id = ?",
- (self.next_counter(), self.next_counter(), rowid))
- except RuntimeError, e:
- sys.stderr.write("Certificate check failed for %s: %s\n" % (
- " ".join(self.rpdb.find_uris(rowid)), e))
- except POW.OpenSSLError, e:
- sys.stderr.write("CMS check failed for %s: %s\n" % (
- " ".join(self.rpdb.find_uris(rowid)), e))
-
- for rowid, der in self.query("fn2 = 'cer'", args):
- cer = rpki.POW.X509.derRead(der)
- ctx = self.store.verify(cer)
- if not ctx.getError():
- self.walk_tree(cer, rowid)
- else:
- sys.stderr.write("Certificate check failed for %s: %s\n" % (
- " ".join(self.rpdb.find_uris(rowid)), ctx.getErrorString()))
-
- self.rpdb.cur.execute(
- "UPDATE object SET right_ = ? WHERE id = ?",
- (self.next_counter(), issuer_id))
-
-
class RPDB(object):
"""
Relying party database.
@@ -570,7 +375,7 @@ class RPDB(object):
mapfn2 = dict((v, k) for k, v in fn2map.iteritems())
object_fields = " %s " % ", ".join("object.%s" % field for field in (
- "id", "fn2", "der", "nochain", "original", "para", "target", "left_", "right_", "para_id", "orig_id"))
+ "id", "fn2", "der", "para", "target", "para_id", "orig_id"))
def __init__(self, db_name = "rcynic-lta.db"):
@@ -596,12 +401,8 @@ class RPDB(object):
aki BLOB,
issuer TEXT,
subject TEXT,
- nochain BOOLEAN NOT NULL DEFAULT 1,
- original BOOLEAN NOT NULL DEFAULT 0,
para BOOLEAN NOT NULL DEFAULT 0,
target BOOLEAN NOT NULL DEFAULT 0,
- left_ INTEGER,
- right_ INTEGER,
para_id INTEGER
REFERENCES object(id)
ON DELETE SET NULL
@@ -712,45 +513,38 @@ class RPDB(object):
def add_para(self, obj, resources):
- """
- As far as I can tell at the moment, we only generate
- paracertificates for CA certificates, never for EE certificates.
-
- At present, ROAs are the only signed objects that specify
- resources explictly rather than using inheritance, and EE
- certificates for ROAs are supposed to be an exact match for the
- address resources in the ROA anyway, so this is likely not a
- serious restriction, at least for now.
-
- Fixing this, if it's a problem, would require extending POW.c to
- allow us to whack the certificate(s) bundled into a CMS object.
- There's no documentation on how we would even do that, although I
- suspect that the OpenSSL library routine CMS_set1_signers_certs()
- might do the trick. Ignore for now.
- """
-
- assert isinstance(obj, X509)
- # As currently used, obj could be a paracert or an original cert.
- # We want links between the two using object.para_id and
- # object.orig_id, but we also want to check for resource overlaps
- # that would indicate overlapping constraints.
+ # At least some of the following is probably wrong at this point.
+ # Under the new scheme we're going to need to generate signed
+ # objects too.
#
- # I think we want to change the lookup so we always get the
- # original cert (which probably happens anyway once we're using
- # the tree-structured SQL lookups, as we're not copying those
- # markers to paracerts), then we can just check for an existing
- # paracert.
+ # As far as I can tell at the moment, we only generate
+ # paracertificates for CA certificates, never for EE certificates.
+ #
+ # At present, ROAs are the only signed objects that specify
+ # resources explictly rather than using inheritance, and EE
+ # certificates for ROAs are supposed to be an exact match for the
+ # address resources in the ROA anyway, so this is likely not a
+ # serious restriction, at least for now.
+ #
+ # Fixing this, if it's a problem, would require extending POW.c to
+ # allow us to whack the certificate(s) bundled into a CMS object.
+ # There's no documentation on how we would even do that, although
+ # I suspect that the OpenSSL library routine
+ # CMS_set1_signers_certs() might do the trick. Ignore for now.
+
+ assert isinstance(obj, X509)
assert not obj.para
if obj.para_obj is not None:
- changed = obj.resources ^ obj.para_obj.resources
- if not (changed & resources).empty():
- raise Blarg
+ resources &= obj.para_obj.resources
obj.para_obj = None
+ if not resources:
+ return
+
global serial
serial += 1
@@ -791,14 +585,13 @@ class RPDB(object):
der = buffer(cer.get_DER())
uri = ltasia + cer.gSKI() + ".cer"
- self.cur.execute("INSERT INTO object (der, fn2, ski, aki, issuer, subject, para, nochain, orig_id) "
- "VALUES (?, 'cer', ?, ?, ?, ?, 1, 0, ?)",
+ self.cur.execute("INSERT INTO object (der, fn2, ski, aki, issuer, subject, para, orig_id) "
+ "VALUES (?, 'cer', ?, ?, ?, ?, 1, ?)",
(der, ski, aki, issuer, subject, obj.rowid))
rowid = self.cur.lastrowid
- self.cur.execute("UPDATE object SET para_id = ?, original = 1 WHERE id = ?", (rowid, obj.rowid))
+ self.cur.execute("UPDATE object SET para_id = ? WHERE id = ?", (rowid, obj.rowid))
obj._para_id = rowid
- obj._original = True
self.cur.execute("INSERT INTO uri (id, uri) VALUES (?, ?)", (rowid, uri))
@@ -806,6 +599,7 @@ class RPDB(object):
def dump_paras(self):
+ shutil.rmtree(rcynic_output, ignore_errors = True)
rsync = "rsync://"
for obj in self.find_paras():
assert obj.uri.startswith(rsync)
@@ -860,11 +654,11 @@ class RPDB(object):
def find_targets(self, fn2 = None):
return self._find_results(fn2,
- "SELECT" + self.object_fields + "FROM object WHERE target <> 0 AND nochain = 0")
+ "SELECT" + self.object_fields + "FROM object WHERE target <> 0")
def find_paras(self, fn2 = None):
return self._find_results(fn2,
- "SELECT" + self.object_fields + "FROM object WHERE para <> 0 AND nochain = 0")
+ "SELECT" + self.object_fields + "FROM object WHERE para <> 0")
def find_parent(self, child):
return self._find_results(None,
@@ -934,9 +728,7 @@ class RPDB(object):
None,
"""
SELECT %s from object, object AS child
- WHERE object.left_ < child.left_
- AND object.right_ > child.right_
- AND child.id = ?
+ WHERE child.id = ?
""" % self.object_fields,
[target.rowid])
@@ -957,14 +749,10 @@ class RPDB(object):
results = []
self.cur.execute(query, args)
selections = self.cur.fetchall()
- for rowid, fn2, der, nochain, original, para, target, left, right, para_id, orig_id in selections:
+ for rowid, fn2, der, para, target, para_id, orig_id in selections:
if rowid in self.cache:
obj = self.cache[rowid]
assert obj._rowid == rowid
- assert obj._left == left
- assert obj._right == right
- assert obj._nochain == nochain
- assert obj._original == original
assert obj._para == para
assert obj._target == target
assert obj._para_id == para_id, "Assertion failure: obj._para_id %s para_id %s" % (obj._para_id, para_id)
@@ -976,10 +764,6 @@ class RPDB(object):
obj.uri = obj.uris[0] if len(obj.uris) == 1 else None
obj._rpdb = self
obj._rowid = rowid
- obj._left = left
- obj._right = right
- obj._nochain = nochain
- obj._original = original
obj._para = para
obj._target = target
obj._para_id = para_id
@@ -999,8 +783,25 @@ class RPDB(object):
self.db.close()
- def validate(self):
- Verifier(self)
+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
if __name__ == "__main__":
@@ -1016,3 +817,4 @@ if __name__ == "__main__":
sys.stderr.write("Dumped profile data to %s\n" % profile)
else:
main()
+
diff --git a/scripts/rcynic-lta.yaml b/scripts/rcynic-lta.yaml
index 35841659..7ac30780 100644
--- a/scripts/rcynic-lta.yaml
+++ b/scripts/rcynic-lta.yaml
@@ -1,5 +1,5 @@
rcynic-input:
- /u/sra/rpki/subvert-rpki.hactrn.net/trunk/rcynic/rcynic-data/unauthenticated
+ /u/sra/rpki/subvert-rpki.hactrn.net/trunk/rcynic/rcynic-data/authenticated
rcynic-output:
/u/sra/rpki/subvert-rpki.hactrn.net/trunk/rcynic/rcynic-data/lta-unauthenticated
@@ -10,16 +10,27 @@ tal-directory:
keyfile:
/u/sra/rpki/subvert-rpki.hactrn.net/trunk/scripts/rcynic-lta.key
+shared-strings:
+
+ - &GB1 |
+ BEGIN:VCARD
+ VERSION:4.0
+ FN:R0
+ ORG:Organizational Entity
+ ADR;TYPE=WORK:;;42 Twisty Passage;Deep Cavern;WA;98666;U.S.A.
+ TEL;TYPE=VOICE,TEXT,WORK;VALUE=uri:tel:+1-666-555-1212
+ TEL;TYPE=FAX,WORK;VALUE=uri:tel:+1-666-555-1213
+ EMAIL:human@example.com
+ END:VCARD
+
constraints:
- - ski: B8:14:5D:13:53:7D:AE:6E:E2:E3:95:84:A8:99:EB:7D:1A:7D:E5:DF
- uri: rsync://repo0.rpki.net/rpki/root.cer
- add: 10.0.0.44/32
+ - prefix: 10.0.0.0/8
+ roa: { asn: 666, maxlen: 16 }
+ ghostbuster: *GB1
- - ski: A2:B3:2A:99:20:07:7A:E9:A4:9F:3F:02:F2:32:F9:3D:54:F8:7E:78
- uri: rsync://repo0.rpki.net/rpki/root/iana.cer
- sub: 10.0.0.0/8
+ - prefix: 192.168.0.0/16
- - ski: 3NYgwt_HYV91MeCGLWdUL4uq65M
- uri: rsync://repo0.rpki.net/rpki/root/iana/5/3NYgwt_HYV91MeCGLWdUL4uq65M.cer
- add: 10.0.0.0/8
+ - asn: 666
+ ghostbuster: *GB1
+ #router-cert: { ski: "B8:14:5D:13:53:7D:AE:6E:E2:E3:95:84:A8:99:EB:7D:1A:7D:E5:DF" }