aboutsummaryrefslogtreecommitdiff
path: root/rpki
diff options
context:
space:
mode:
Diffstat (limited to 'rpki')
-rw-r--r--rpki/left_right.py134
-rw-r--r--rpki/publication_control.py20
-rw-r--r--rpki/xml_utils.py75
3 files changed, 176 insertions, 53 deletions
diff --git a/rpki/left_right.py b/rpki/left_right.py
index 55f893b8..c7517e26 100644
--- a/rpki/left_right.py
+++ b/rpki/left_right.py
@@ -23,6 +23,7 @@ RPKI "left-right" protocol.
import base64
import logging
+import collections
import rpki.resource_set
import rpki.x509
import rpki.sql
@@ -179,10 +180,13 @@ class self_elt(data_elt):
element_name = "self"
attributes = ("action", "tag", "self_handle", "crl_interval", "regen_margin")
- elements = ("bpki_cert", "bpki_glue")
booleans = ("rekey", "reissue", "revoke", "run_now", "publish_world_now", "revoke_forgotten",
"clear_replay_protection")
+ elements = collections.OrderedDict((
+ ("bpki_cert", rpki.x509.X509),
+ ("bpki_glue", rpki.x509.X509)))
+
sql_template = rpki.sql.template(
"self",
"self_id",
@@ -489,9 +493,13 @@ class bsc_elt(data_elt):
element_name = "bsc"
attributes = ("action", "tag", "self_handle", "bsc_handle", "key_type", "hash_alg", "key_length")
- elements = ("signing_cert", "signing_cert_crl", "pkcs10_request")
booleans = ("generate_keypair",)
+ elements = collections.OrderedDict((
+ ("signing_cert", rpki.x509.X509),
+ ("signing_cert_crl", rpki.x509.CRL),
+ ("pkcs10_request", rpki.x509.PKCS10)))
+
sql_template = rpki.sql.template(
"bsc",
"bsc_id",
@@ -557,9 +565,12 @@ class repository_elt(data_elt):
element_name = "repository"
attributes = ("action", "tag", "self_handle", "repository_handle", "bsc_handle", "peer_contact_uri")
- elements = ("bpki_cert", "bpki_glue")
booleans = ("clear_replay_protection",)
+ elements = collections.OrderedDict((
+ ("bpki_cert", rpki.x509.X509),
+ ("bpki_glue", rpki.x509.X509)))
+
sql_template = rpki.sql.template(
"repository",
"repository_id",
@@ -677,9 +688,12 @@ class parent_elt(data_elt):
element_name = "parent"
attributes = ("action", "tag", "self_handle", "parent_handle", "bsc_handle", "repository_handle",
"peer_contact_uri", "sia_base", "sender_name", "recipient_name")
- elements = ("bpki_cms_cert", "bpki_cms_glue")
booleans = ("rekey", "reissue", "revoke", "revoke_forgotten", "clear_replay_protection")
+ elements = collections.OrderedDict((
+ ("bpki_cms_cert", rpki.x509.X509),
+ ("bpki_cms_glue", rpki.x509.X509)))
+
sql_template = rpki.sql.template(
"parent",
"parent_id",
@@ -969,9 +983,12 @@ class child_elt(data_elt):
element_name = "child"
attributes = ("action", "tag", "self_handle", "child_handle", "bsc_handle")
- elements = ("bpki_cert", "bpki_glue")
booleans = ("reissue", "clear_replay_protection")
+ elements = collections.OrderedDict((
+ ("bpki_cert", rpki.x509.X509),
+ ("bpki_glue", rpki.x509.X509)))
+
sql_template = rpki.sql.template(
"child",
"child_id",
@@ -1271,14 +1288,11 @@ class list_resources_elt(rpki.xml_utils.base_elt, left_right_namespace):
def __repr__(self):
return rpki.log.log_repr(self, self.self_handle, self.child_handle, self.asn, self.ipv4, self.ipv6)
- def startElement(self, stack, name, attrs):
+ def fix_attribute_types(self):
"""
- Handle <list_resources/> element. This requires special handling
- due to the data types of some of the attributes.
+ Fix data types for certain attributes.
"""
- assert name == "list_resources", "Unexpected name %s, stack %s" % (name, stack)
- self.read_attrs(attrs)
if isinstance(self.valid_until, str):
self.valid_until = rpki.sundial.datetime.fromXMLtime(self.valid_until)
if self.asn is not None:
@@ -1288,6 +1302,27 @@ class list_resources_elt(rpki.xml_utils.base_elt, left_right_namespace):
if self.ipv6 is not None:
self.ipv6 = rpki.resource_set.resource_set_ipv6(self.ipv6)
+ def startElement(self, stack, name, attrs):
+ """
+ Handle <list_resources/> element. This requires special handling
+ due to the data types of some of the attributes.
+ """
+
+ assert name == "list_resources", "Unexpected name %s, stack %s" % (name, stack)
+ self.read_attrs(attrs)
+ self.fix_attribute_types()
+
+ @classmethod
+ def fromXML(cls, elt):
+ """
+ Handle <list_resources/> element. This requires special handling
+ due to the data types of some of the attributes.
+ """
+
+ self = super(list_resources_elt, cls).fromXML(elt)
+ self.fix_attribute_types()
+ return self
+
def toXML(self):
"""
Generate <list_resources/> element. This requires special
@@ -1307,6 +1342,16 @@ class list_roa_requests_elt(rpki.xml_utils.base_elt, left_right_namespace):
element_name = "list_roa_requests"
attributes = ("self_handle", "tag", "asn", "ipv4", "ipv6")
+ def fix_attribute_types(self):
+ """
+ Fix data types for certain attributes.
+ """
+
+ if self.ipv4 is not None:
+ self.ipv4 = rpki.resource_set.roa_prefix_set_ipv4(self.ipv4)
+ if self.ipv6 is not None:
+ self.ipv6 = rpki.resource_set.roa_prefix_set_ipv6(self.ipv6)
+
def startElement(self, stack, name, attrs):
"""
Handle <list_roa_requests/> element. This requires special handling
@@ -1315,10 +1360,18 @@ class list_roa_requests_elt(rpki.xml_utils.base_elt, left_right_namespace):
assert name == "list_roa_requests", "Unexpected name %s, stack %s" % (name, stack)
self.read_attrs(attrs)
- if self.ipv4 is not None:
- self.ipv4 = rpki.resource_set.roa_prefix_set_ipv4(self.ipv4)
- if self.ipv6 is not None:
- self.ipv6 = rpki.resource_set.roa_prefix_set_ipv6(self.ipv6)
+ self.fix_attribute_types()
+
+ @classmethod
+ def fromXML(self, elt):
+ """
+ Handle <list_roa_requests/> element. This requires special handling
+ due to the data types of some of the attributes.
+ """
+
+ self = super(list_roa_requests_elt, cls).fromXML(elt)
+ self.fix_attribute_types()
+ return self
def __repr__(self):
return rpki.log.log_repr(self, self.self_handle, self.asn, self.ipv4, self.ipv6)
@@ -1344,7 +1397,9 @@ class list_ee_certificate_requests_elt(rpki.xml_utils.base_elt, left_right_names
element_name = "list_ee_certificate_requests"
attributes = ("self_handle", "tag", "gski", "valid_until", "asn", "ipv4", "ipv6", "cn", "sn", "eku")
- elements = ("pkcs10",)
+
+ elements = collections.OrderedDict((
+ ("pkcs10", rpki.x509.PKCS10),))
pkcs10 = None
valid_until = None
@@ -1353,6 +1408,22 @@ class list_ee_certificate_requests_elt(rpki.xml_utils.base_elt, left_right_names
def __repr__(self):
return rpki.log.log_repr(self, self.self_handle, self.gski, self.cn, self.sn, self.asn, self.ipv4, self.ipv6)
+ def fix_attribute_types(self):
+ """
+ Fix data types for certain attributes.
+ """
+
+ if isinstance(self.valid_until, str):
+ self.valid_until = rpki.sundial.datetime.fromXMLtime(self.valid_until)
+ if self.asn is not None:
+ self.asn = rpki.resource_set.resource_set_as(self.asn)
+ if self.ipv4 is not None:
+ self.ipv4 = rpki.resource_set.resource_set_ipv4(self.ipv4)
+ if self.ipv6 is not None:
+ self.ipv6 = rpki.resource_set.resource_set_ipv6(self.ipv6)
+ if self.eku is not None:
+ self.eku = self.eku.split(",")
+
def startElement(self, stack, name, attrs):
"""
Handle <list_ee_certificate_requests/> element. This requires special
@@ -1362,16 +1433,18 @@ class list_ee_certificate_requests_elt(rpki.xml_utils.base_elt, left_right_names
if name not in self.elements:
assert name == self.element_name, "Unexpected name %s, stack %s" % (name, stack)
self.read_attrs(attrs)
- if isinstance(self.valid_until, str):
- self.valid_until = rpki.sundial.datetime.fromXMLtime(self.valid_until)
- if self.asn is not None:
- self.asn = rpki.resource_set.resource_set_as(self.asn)
- if self.ipv4 is not None:
- self.ipv4 = rpki.resource_set.resource_set_ipv4(self.ipv4)
- if self.ipv6 is not None:
- self.ipv6 = rpki.resource_set.resource_set_ipv6(self.ipv6)
- if self.eku is not None:
- self.eku = self.eku.split(",")
+ self.fix_attribute_types()
+
+ @classmethod
+ def fromXML(cls, elt):
+ """
+ Handle <list_ee_certificate_requests/> element. This requires special
+ handling due to the data types of some of the attributes.
+ """
+
+ self = super(list_ee_certificate_requests_elt, cls).fromXML(elt)
+ self.fix_attribute_types()
+ return self
def endElement(self, stack, name, text):
"""
@@ -1569,14 +1642,6 @@ class msg(rpki.xml_utils.msg, left_right_namespace):
rpki.async.iterator(self, loop, done)
-class sax_handler(rpki.xml_utils.sax_handler):
- """
- SAX handler for Left-Right protocol.
- """
-
- pdu = msg
- name = "msg"
- version = rpki.relaxng.left_right.version
class cms_msg(rpki.x509.XML_CMS_object):
"""
@@ -1585,7 +1650,8 @@ class cms_msg(rpki.x509.XML_CMS_object):
encoding = "us-ascii"
schema = rpki.relaxng.left_right
- saxify = sax_handler.saxify
+ saxify = msg.fromXML
+
class cms_msg_no_sax(cms_msg):
"""
diff --git a/rpki/publication_control.py b/rpki/publication_control.py
index 478f183b..b814346e 100644
--- a/rpki/publication_control.py
+++ b/rpki/publication_control.py
@@ -25,6 +25,7 @@ protocol itself.
"""
import logging
+import collections
import rpki.resource_set
import rpki.x509
import rpki.sql
@@ -87,9 +88,12 @@ class client_elt(rpki.xml_utils.data_elt, rpki.sql.sql_persistent, publication_c
element_name = "client"
attributes = ("action", "tag", "client_handle", "base_uri")
- elements = ("bpki_cert", "bpki_glue")
booleans = ("clear_replay_protection",)
+ elements = collections.OrderedDict((
+ ("bpki_cert", rpki.x509.X509),
+ ("bpki_glue", rpki.x509.X509)))
+
sql_template = rpki.sql.template(
"client",
"client_id",
@@ -239,16 +243,6 @@ class msg(rpki.xml_utils.msg, publication_control_namespace):
return cb(r_msg)
-class sax_handler(rpki.xml_utils.sax_handler):
- """
- SAX handler for publication control protocol.
- """
-
- pdu = msg
- name = "msg"
- version = rpki.relaxng.publication_control.version
-
-
class cms_msg(rpki.x509.XML_CMS_object):
"""
Class to hold a CMS-signed publication control PDU.
@@ -256,9 +250,9 @@ class cms_msg(rpki.x509.XML_CMS_object):
encoding = "us-ascii"
schema = rpki.relaxng.publication_control
- saxify = sax_handler.saxify
-
+ saxify = msg.fromXML # Not really SAX anymore
+
class cms_msg_no_sax(cms_msg):
"""
Class to hold a CMS-signed publication control PDU without legacy
diff --git a/rpki/xml_utils.py b/rpki/xml_utils.py
index 9b443d0b..99377e17 100644
--- a/rpki/xml_utils.py
+++ b/rpki/xml_utils.py
@@ -56,6 +56,8 @@ class sax_handler(xml.sax.handler.ContentHandler):
many XML namespace games.
"""
+ # .pdu, .name, and .version are provided by subclass
+
def __init__(self):
"""
Initialize SAX handler.
@@ -145,8 +147,7 @@ class sax_handler(xml.sax.handler.ContentHandler):
class base_elt(object):
"""
Virtual base class for XML message elements. The left-right and
- publication protocols use this. At least for now, the up-down
- protocol does not, due to different design assumptions.
+ publication_control protocols use this.
"""
## @var attributes
@@ -161,6 +162,10 @@ class base_elt(object):
# Boolean attributes (value "yes" or "no") for this element.
booleans = ()
+ ## @var text_attribute
+ # Name of class attribute that tells us where to put text values, if any.
+ text_attribute = None
+
def startElement(self, stack, name, attrs):
"""
Default startElement() handler: just process attributes.
@@ -178,6 +183,47 @@ class base_elt(object):
assert name == self.element_name, "Unexpected name %s, stack %s" % (name, stack)
stack.pop()
+ @classmethod
+ def fromXML(cls, elt):
+ """
+ First cut at non-SAX message unpacker. This will probably change.
+ """
+
+ logger.warning("base_elt(): Element %r (len %s)", elt, len(elt))
+
+ self = cls()
+
+ for key in self.attributes:
+ val = elt.get(key, None)
+ if val is not None:
+ val = val.encode("ascii")
+ if val.isdigit() and not key.endswith("_handle"):
+ val = long(val)
+ setattr(self, key, val)
+ for key in self.booleans:
+ setattr(self, key, elt.get(key, False))
+
+ # This test could go in an extended method in text_elt. Then
+ # again, perhaps spreading the logic in as many places as we
+ # possibly can is not really helping matters....
+
+ if self.text_attribute is not None:
+ setattr(self, self.text_attribute, elt.text)
+
+ # In the long run, we probably want the key for that to include
+ # the namespace, but that would break the current .toXML() code,
+ # so kludge it for now.
+
+ for b64 in elt:
+ # XXX
+ logger.warning("base_elt(): XML tag %r, XML namespace %r", b64.tag, self.xmlns)
+ assert b64.tag.startswith(self.xmlns)
+ ename = b64.tag[len(self.xmlns):]
+ etype = self.elements[ename]
+ setattr(self, ename, etype(Base64 = b64.text))
+
+ return self
+
def toXML(self):
"""
Default toXML() element generator.
@@ -246,10 +292,6 @@ class text_elt(base_elt):
Virtual base class for XML message elements that contain text.
"""
- ## @var text_attribute
- # Name of the class attribute that holds the text value.
- text_attribute = None
-
def endElement(self, stack, name, text):
"""
Extract text from parsed XML.
@@ -530,3 +572,24 @@ class msg(list):
"""
return self.type == "reply"
+
+ @classmethod
+ def fromXML(cls, elt):
+ """
+ First cut at non-SAX message unpacker. This will probably change.
+ """
+
+ assert cls.version == int(elt.get("version"))
+ self = cls()
+ self.type = elt.get("type")
+
+ # This could be simplified by including the namespace name in the .pdus[] key.
+
+ for sub in elt:
+ # XXX
+ logger.warning("msg(): XML tag %r, XML namespace %r", sub.tag, self.xmlns)
+ assert sub.tag.startswith(self.xmlns)
+ self.append(self.pdus[sub.tag[len(self.xmlns):]].fromXML(sub))
+
+ logger.warning("msg(): parsed %r", self)
+ return self