diff options
Diffstat (limited to 'myrpki/myirbe.py')
-rw-r--r-- | myrpki/myirbe.py | 61 |
1 files changed, 57 insertions, 4 deletions
diff --git a/myrpki/myirbe.py b/myrpki/myirbe.py index 6a7bc2d8..ecbf7b23 100644 --- a/myrpki/myirbe.py +++ b/myrpki/myirbe.py @@ -1,5 +1,28 @@ """ -IRBE-side stuff for myrpki testbed. +IRBE-side stuff for myrpki tools. + +The basic model here is that each entity with resources to certify +runs the myrpki tool, but not all of them necessarily run their own +RPKi engines. The entities that do run RPKI engines get data from the +entities they host via the XML files output by the myrpki tool. Those +XML files are the input to this script, which uses them to do all the +work of constructing certificates, populating SQL databases, and so +forth. A few operations (eg, BSC construction) generate data which +has to be shipped back to the resource holder, which we do by updating +the same XML file. + +In essence, the XML files are a sneakernet (or email, or carrier +pigeon) communication channel between the resource holders and the +RPKI engine operators. + +As a convenience, for the normal case where the RPKI engine operator +is itself a resource holder, this script also runs the myrpki script +directly to process the RPKI engine operator's own resources. + +Note that, due to the back and forth nature of some of these +operations, it may take several cycles for data structures to stablize +and everything to reach a steady state. This is normal. + $Id$ @@ -24,9 +47,15 @@ import rpki.exceptions, rpki.left_right, rpki.log, rpki.x509, rpki.async import myrpki, schema def tag(t): + """ + Wrap an element name in the right XML namespace goop. + """ return "{http://www.hactrn.net/uris/rpki/myrpki/}" + t def findbase64(tree, name, b64type = rpki.x509.X509): + """ + Find and extract a base64-encoded XML element, if present. + """ x = tree.findtext(tag(name)) return b64type(Base64 = x) if x else None @@ -112,17 +141,19 @@ if bpki_modified: print "BPKI (re)initialized. You need to (re)start daemons before continuing." sys.exit() +# Default values for CRL parameters are very low, for testing. + self_crl_interval = cfg.get("self_crl_interval", 300) self_regen_margin = cfg.get("self_regen_margin", 120) rsync_base = cfg.get("rsync_base") pubd_base = cfg.get("pubd_base") rpkid_base = cfg.get("rpkid_base") -# Nasty regexp for parsing rpkid's up-down service URLs +# Nasty regexp for parsing rpkid's up-down service URLs. updown_regexp = re.compile(re.escape(rpkid_base) + "up-down/([-A-Z0-9_]+)/([-A-Z0-9_]+)$", re.I) -# Wrappers to simplify calling rpkid and pubd +# Wrappers to simplify calling rpkid and pubd. call_rpkid = rpki.async.sync_wrapper(caller( proto = rpki.left_right, @@ -156,18 +187,26 @@ cur = db.cursor() xmlfiles = [] +# If [myrpki] section is present in config file, run myrpki.py +# internally, as a convenience, and include its output at the head of +# our list of XML files to process. + if cfg.has_section("myrpki"): myrpki.main() my_xmlfile = cfg.get("xml_filename", None, "myrpki") assert my_xmlfile is not None xmlfiles.append(my_xmlfile) +# Add any other XML files specified on the command line + xmlfiles.extend(argv) my_handle = None for xmlfile in xmlfiles: + # Parse XML file and validate it against our scheme + tree = lxml.etree.parse(xmlfile).getroot() schema.myrpki.assertValid(tree) @@ -176,6 +215,8 @@ for xmlfile in xmlfiles: if xmlfile == my_xmlfile: my_handle = handle + # Update IRDB with parsed resource and roa-request data. + cur.execute( """ DELETE @@ -231,14 +272,18 @@ for xmlfile in xmlfiles: db.commit() + # Check for certificates before attempting anything else + hosted_cacert = findbase64(tree, "bpki_ca_certificate") if not hosted_cacert: print "Nothing else I can do without a trust anchor for the entity I'm hosting." - sys.exit() + continue rpkid_xcert = rpki.x509.X509(PEM_file = bpki_rpkid.fxcert(handle + ".cacert.cer", hosted_cacert.get_PEM(), path_restriction = 1)) pubd_xcert = rpki.x509.X509(PEM_file = bpki_pubd.fxcert(handle + ".cacert.cer", hosted_cacert.get_PEM())) + # See what rpkid and pubd already have on file for this entity. + pubd_reply = call_pubd(( rpki.publication.client_elt.make_pdu(action = "get", tag = "client", client_handle = handle),)) @@ -411,6 +456,10 @@ for xmlfile in xmlfiles: rpkid_query.extend(rpki.left_right.parent_elt.make_pdu( action = "destroy", self_handle = handle, parent_handle = p) for p in parent_pdus) + # Children are simpler than parents, because they call us, so no URL + # to construct and figuring out what certificate to use is their + # problem, not ours. + for child in tree.getiterator(tag("child")): child_handle = child.get("handle") @@ -431,6 +480,8 @@ for xmlfile in xmlfiles: rpkid_query.extend(rpki.left_right.child_elt.make_pdu( action = "destroy", self_handle = handle, child_handle = c) for c in child_pdus) + # If we changed anything, ship updates off to daemons + if rpkid_query: rpkid_reply = call_rpkid(rpkid_query) bsc_pdus = dict((x.bsc_handle, x) for x in rpkid_reply if isinstance(x, rpki.left_right.bsc_elt)) @@ -441,6 +492,8 @@ for xmlfile in xmlfiles: pubd_reply = call_pubd(pubd_query) assert len(pubd_reply) == 1 and isinstance(pubd_reply[0], rpki.publication.client_elt) and pubd_reply[0].client_handle == handle + # Rewrite XML. + e = tree.find(tag("bpki_bsc_pkcs10")) if e is None and bsc_req is not None: e = lxml.etree.SubElement(tree, "bpki_bsc_pkcs10") |