diff options
Diffstat (limited to 'rpki/up_down.py')
-rw-r--r-- | rpki/up_down.py | 79 |
1 files changed, 65 insertions, 14 deletions
diff --git a/rpki/up_down.py b/rpki/up_down.py index 73a0ae99..a145ed28 100644 --- a/rpki/up_down.py +++ b/rpki/up_down.py @@ -50,6 +50,7 @@ class base_elt(object): Some elements have no attributes and we only care about their text content. """ + pass def endElement(self, stack, name, text): @@ -58,12 +59,14 @@ class base_elt(object): If we don't need to do anything else, just pop the stack. """ + stack.pop() def make_elt(self, name, *attrs): """ Construct a element, copying over a set of attributes. """ + elt = lxml.etree.Element(xmlns + name, nsmap = nsmap) for key in attrs: val = getattr(self, key, None) @@ -75,6 +78,7 @@ class base_elt(object): """ Construct a sub-element with Base64 text content. """ + if value is not None and not value.empty(): lxml.etree.SubElement(elt, xmlns + name, nsmap = nsmap).text = value.get_Base64() @@ -82,12 +86,14 @@ class base_elt(object): """ Default PDU handler to catch unexpected types. """ + raise rpki.exceptions.BadQuery("Unexpected query type %s" % q_msg.type) def check_response(self): """ Placeholder for response checking. """ + pass class multi_uri(list): @@ -99,6 +105,7 @@ class multi_uri(list): """ Initialize a set of URIs, which includes basic some syntax checking. """ + list.__init__(self) if isinstance(ini, (list, tuple)): self[:] = ini @@ -114,12 +121,14 @@ class multi_uri(list): """ Convert a multi_uri back to a string representation. """ + return ",".join(self) def rsync(self): """ Find first rsync://... URI in self. """ + for s in self: if s.startswith("rsync://"): return s @@ -134,6 +143,7 @@ class certificate_elt(base_elt): """ Handle attributes of <certificate/> element. """ + assert name == "certificate", "Unexpected name %s, stack %s" % (name, stack) self.cert_url = multi_uri(attrs["cert_url"]) self.req_resource_set_as = rpki.resource_set.resource_set_as(attrs.get("req_resource_set_as")) @@ -144,6 +154,7 @@ class certificate_elt(base_elt): """ Handle text content of a <certificate/> element. """ + assert name == "certificate", "Unexpected name %s, stack %s" % (name, stack) self.cert = rpki.x509.X509(Base64 = text) stack.pop() @@ -152,6 +163,7 @@ class certificate_elt(base_elt): """ Generate a <certificate/> element. """ + elt = self.make_elt("certificate", "cert_url", "req_resource_set_as", "req_resource_set_ipv4", "req_resource_set_ipv6") elt.text = self.cert.get_Base64() @@ -168,6 +180,7 @@ class class_elt(base_elt): """ Initialize class_elt. """ + base_elt.__init__(self) self.certs = [] @@ -175,6 +188,7 @@ class class_elt(base_elt): """ Handle <class/> elements and their children. """ + if name == "certificate": cert = certificate_elt() self.certs.append(cert) @@ -194,6 +208,7 @@ class class_elt(base_elt): """ Handle <class/> elements and their children. """ + if name == "issuer": self.issuer = rpki.x509.X509(Base64 = text) else: @@ -204,10 +219,11 @@ class class_elt(base_elt): """ Generate a <class/> element. """ + elt = self.make_elt("class", "class_name", "cert_url", "resource_set_as", "resource_set_ipv4", "resource_set_ipv6", "resource_set_notafter", "suggested_sia_head") - elt.extend([i.toXML() for i in self.certs]) + elt.extend(i.toXML() for i in self.certs) self.make_b64elt(elt, "issuer", self.issuer) return elt @@ -215,6 +231,7 @@ class class_elt(base_elt): """ Build a resource_bag from from this <class/> element. """ + return rpki.resource_set.resource_bag(self.resource_set_as, self.resource_set_ipv4, self.resource_set_ipv6, @@ -224,6 +241,7 @@ class class_elt(base_elt): """ Set resources of this class element from a resource_bag. """ + self.resource_set_as = bag.asn self.resource_set_ipv4 = bag.v4 self.resource_set_ipv6 = bag.v6 @@ -235,7 +253,10 @@ class list_pdu(base_elt): """ def toXML(self): - """Generate (empty) payload of "list" PDU.""" + """ + Generate (empty) payload of "list" PDU. + """ + return [] def serve_pdu(self, q_msg, r_msg, child, callback, errback): @@ -282,6 +303,7 @@ class list_pdu(base_elt): """ Send a "list" query to parent. """ + try: logger.info('Sending "list" request to parent %s', parent.parent_handle) parent.query_up_down(cls(), cb, eb) @@ -299,6 +321,7 @@ class class_response_syntax(base_elt): """ Initialize class_response_syntax. """ + base_elt.__init__(self) self.classes = [] @@ -306,6 +329,7 @@ class class_response_syntax(base_elt): """ Handle "list_response" and "issue_response" PDUs. """ + assert name == "class", "Unexpected name %s, stack %s" % (name, stack) c = class_elt() self.classes.append(c) @@ -313,13 +337,17 @@ class class_response_syntax(base_elt): c.startElement(stack, name, attrs) def toXML(self): - """Generate payload of "list_response" and "issue_response" PDUs.""" + """ + Generate payload of "list_response" and "issue_response" PDUs. + """ + return [c.toXML() for c in self.classes] class list_response_pdu(class_response_syntax): """ Up-Down protocol "list_response" PDU. """ + pass class issue_pdu(base_elt): @@ -331,6 +359,7 @@ class issue_pdu(base_elt): """ Handle "issue" PDU. """ + assert name == "request", "Unexpected name %s, stack %s" % (name, stack) self.class_name = attrs["class_name"] self.req_resource_set_as = rpki.resource_set.resource_set_as(attrs.get("req_resource_set_as")) @@ -341,6 +370,7 @@ class issue_pdu(base_elt): """ Handle "issue" PDU. """ + assert name == "request", "Unexpected name %s, stack %s" % (name, stack) self.pkcs10 = rpki.x509.PKCS10(Base64 = text) stack.pop() @@ -349,6 +379,7 @@ class issue_pdu(base_elt): """ Generate payload of "issue" PDU. """ + elt = self.make_elt("request", "class_name", "req_resource_set_as", "req_resource_set_ipv4", "req_resource_set_ipv6") elt.text = self.pkcs10.get_Base64() @@ -432,6 +463,7 @@ class issue_pdu(base_elt): """ Send an "issue" request to parent associated with ca. """ + assert ca_detail is not None and ca_detail.state in ("pending", "active") self = cls() self.class_name = ca.parent_resource_class @@ -453,6 +485,7 @@ class issue_response_pdu(class_response_syntax): Check whether this looks like a reasonable issue_response PDU. XML schema should be tighter for this response. """ + if len(self.classes) != 1 or len(self.classes[0].certs) != 1: raise rpki.exceptions.BadIssueResponse @@ -462,12 +495,18 @@ class revoke_syntax(base_elt): """ def startElement(self, stack, name, attrs): - """Handle "revoke" PDU.""" + """ + Handle "revoke" PDU. + """ + self.class_name = attrs["class_name"] self.ski = attrs["ski"] def toXML(self): - """Generate payload of "revoke" PDU.""" + """ + Generate payload of "revoke" PDU. + """ + return [self.make_elt("key", "class_name", "ski")] class revoke_pdu(revoke_syntax): @@ -479,6 +518,7 @@ class revoke_pdu(revoke_syntax): """ Convert g(SKI) encoding from PDU back to raw SKI. """ + return base64.urlsafe_b64decode(self.ski + "=") def serve_pdu(self, q_msg, r_msg, child, cb, eb): @@ -505,6 +545,7 @@ class revoke_pdu(revoke_syntax): """ Send a "revoke" request for certificate(s) named by gski to parent associated with ca. """ + parent = ca.parent self = cls() self.class_name = ca.parent_resource_class @@ -545,6 +586,7 @@ class error_response_pdu(base_elt): """ Initialize an error_response PDU from an exception object. """ + base_elt.__init__(self) if exception is not None: logger.debug("Constructing up-down error response from exception %s", exception) @@ -570,6 +612,7 @@ class error_response_pdu(base_elt): """ Handle "error_response" PDU. """ + if name == "status": code = int(text) if code not in self.codes: @@ -586,6 +629,7 @@ class error_response_pdu(base_elt): """ Generate payload of "error_response" PDU. """ + assert self.status in self.codes elt = self.make_elt("status") elt.text = str(self.status) @@ -602,6 +646,7 @@ class error_response_pdu(base_elt): Handle an error response. For now, just raise an exception, perhaps figure out something more clever to do later. """ + raise rpki.exceptions.UpstreamError(self.codes[self.status]) class message_pdu(base_elt): @@ -611,16 +656,16 @@ class message_pdu(base_elt): version = 1 - name2type = { - "list" : list_pdu, - "list_response" : list_response_pdu, - "issue" : issue_pdu, - "issue_response" : issue_response_pdu, - "revoke" : revoke_pdu, - "revoke_response" : revoke_response_pdu, - "error_response" : error_response_pdu } + name2type = dict( + list = list_pdu, + list_response = list_response_pdu, + issue = issue_pdu, + issue_response = issue_response_pdu, + revoke = revoke_pdu, + revoke_response = revoke_response_pdu, + error_response = error_response_pdu) - type2name = dict((v, k) for k, v in name2type.items()) + type2name = dict((v, k) for k, v in name2type.iteritems()) error_pdu_type = error_response_pdu @@ -628,6 +673,7 @@ class message_pdu(base_elt): """ Generate payload of message PDU. """ + elt = self.make_elt("message", "version", "sender", "recipient", "type") elt.extend(self.payload.toXML()) return elt @@ -640,6 +686,7 @@ class message_pdu(base_elt): attribute, so after some basic checks we have to instantiate the right class object to handle whatever kind of PDU this is. """ + assert name == "message", "Unexpected name %s, stack %s" % (name, stack) assert self.version == int(attrs["version"]) self.sender = attrs["sender"] @@ -652,6 +699,7 @@ class message_pdu(base_elt): """ Convert a message PDU to a string. """ + return lxml.etree.tostring(self.toXML(), pretty_print = True, encoding = "UTF-8") def serve_top_level(self, child, callback): @@ -683,12 +731,14 @@ class message_pdu(base_elt): """ Log query we're handling. Separate method so rootd can override. """ + logger.info("Serving %s query from child %s [sender %s, recipient %s]", self.type, child.child_handle, self.sender, self.recipient) def serve_error(self, exception): """ Generate an error_response message PDU. """ + r_msg = message_pdu() r_msg.sender = self.recipient r_msg.recipient = self.sender @@ -701,6 +751,7 @@ class message_pdu(base_elt): """ Construct one message PDU. """ + assert not cls.type2name[type(payload)].endswith("_response") if sender is None: sender = "tweedledee" |