diff options
Diffstat (limited to 'rpkid.stable/rpki/publication.py')
-rw-r--r-- | rpkid.stable/rpki/publication.py | 282 |
1 files changed, 0 insertions, 282 deletions
diff --git a/rpkid.stable/rpki/publication.py b/rpkid.stable/rpki/publication.py deleted file mode 100644 index fe52b631..00000000 --- a/rpkid.stable/rpki/publication.py +++ /dev/null @@ -1,282 +0,0 @@ -"""RPKI "publication" protocol. - -$Id$ - -Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -""" - -import base64, lxml.etree, time, traceback, os -import rpki.resource_set, rpki.x509, rpki.sql, rpki.exceptions, rpki.xml_utils -import rpki.https, rpki.up_down, rpki.relaxng, rpki.sundial, rpki.log, rpki.roa - -class publication_namespace(object): - """XML namespace parameters for publication protocol.""" - - xmlns = "http://www.hactrn.net/uris/rpki/publication-spec/" - nsmap = { None : xmlns } - -class control_elt(rpki.xml_utils.data_elt, rpki.sql.sql_persistant, publication_namespace): - """Virtual class for control channel objects.""" - - def serve_dispatch(self, r_msg, client): - """Action dispatch handler. This needs special handling because - we need to make sure that this PDU arrived via the control channel. - """ - if client is not None: - raise rpki.exceptions.BadQuery, "Control query received on client channel" - rpki.xml_utils.data_elt.serve_dispatch(self, r_msg) - -class config_elt(control_elt): - """<config/> element. This is a little weird because there should - never be more than one row in the SQL config table, but we have to - put the BPKI CRL somewhere and SQL is the least bad place available. - - So we reuse a lot of the SQL machinery, but we nail config_id at 1, - we don't expose it in the XML protocol, and we only support the get - and set actions. - """ - - attributes = ("action", "tag") - element_name = "config" - elements = ("bpki_crl",) - - sql_template = rpki.sql.template("config", "config_id", ("bpki_crl", rpki.x509.CRL)) - - wired_in_config_id = 1 - - def startElement(self, stack, name, attrs): - """StartElement() handler for config object. This requires - special handling because of the weird way we treat config_id. - """ - control_elt.startElement(self, stack, name, attrs) - self.config_id = self.wired_in_config_id - - @classmethod - def fetch(cls, gctx): - """Fetch the config object from SQL. This requires special - handling because of the weird way we treat config_id. - """ - return cls.sql_fetch(gctx, cls.wired_in_config_id) - - def serve_set(self, r_msg): - """Handle a set action. This requires special handling because - config we don't support the create method. - """ - if self.sql_fetch(self.gctx, self.config_id) is None: - control_elt.serve_create(self, r_msg) - else: - control_elt.serve_set(self, r_msg) - - def serve_fetch_one(self): - """Find the config object on which a get or set method should - operate. - """ - r = self.sql_fetch(self.gctx, self.config_id) - if r is None: - raise rpki.exceptions.NotFound - return r - -class client_elt(control_elt): - """<client/> element.""" - - element_name = "client" - attributes = ("action", "tag", "client_id", "base_uri") - elements = ("bpki_cert", "bpki_glue") - - sql_template = rpki.sql.template("client", "client_id", "base_uri", ("bpki_cert", rpki.x509.X509), ("bpki_glue", rpki.x509.X509)) - - base_uri = None - bpki_cert = None - bpki_glue = None - - clear_https_ta_cache = False - - def endElement(self, stack, name, text): - """Handle subelements of <client/> element. These require special - handling because modifying them invalidates the HTTPS trust anchor - cache. - """ - control_elt.endElement(self, stack, name, text) - if name in self.elements: - self.clear_https_ta_cache = True - - def serve_post_save_hook(self, q_pdu, r_pdu): - """Extra server actions for client_elt.""" - if self.clear_https_ta_cache: - self.gctx.clear_https_ta_cache() - self.clear_https_ta_cache = False - - def serve_fetch_one(self): - """Find the client object on which a get, set, or destroy method - should operate. - """ - r = self.sql_fetch(self.gctx, self.client_id) - if r is None: - raise rpki.exceptions.NotFound - return r - - def serve_fetch_all(self): - """Find client objects on which a list method should operate.""" - return self.sql_fetch_all(self.gctx) - - def check_allowed_uri(self, uri): - if not uri.startswith(self.base_uri): - raise rpki.exceptions.ForbiddenURI - -class publication_object_elt(rpki.xml_utils.base_elt, publication_namespace): - """Virtual class for publishable objects. These have very similar - syntax, differences lie in underlying datatype and methods. XML - methods are a little different from the pattern used for objects - that support the create/set/get/list/destroy actions, but - publishable objects don't go in SQL either so these classes would be - different in any case. - """ - - attributes = ("action", "tag", "client_id", "uri") - payload = None - - def endElement(self, stack, name, text): - """Handle a publishable element element.""" - assert name == self.element_name, "Unexpected name %s, stack %s" % (name, stack) - if text: - self.payload = self.payload_type(Base64 = text) - stack.pop() - - def toXML(self): - """Generate XML element for publishable object.""" - elt = self.make_elt() - if self.payload: - elt.text = base64.b64encode(self.payload.get_DER()) - return elt - - def serve_dispatch(self, r_msg, client): - """Action dispatch handler.""" - if client is None: - raise rpki.exceptions.BadQuery, "Client query received on control channel" - dispatch = { "publish" : self.serve_publish, - "withdraw" : self.serve_withdraw } - if self.action not in dispatch: - raise rpki.exceptions.BadQuery, "Unexpected query: action %s" % self.action - client.check_allowed_uri(self.uri) - dispatch[self.action]() - r_pdu = self.__class__() - r_pdu.action = self.action - r_pdu.tag = self.tag - r_pdu.uri = self.uri - r_msg.append(r_pdu) - - def serve_publish(self): - """Publish an object.""" - rpki.log.info("Publishing %s as %s" % (repr(self.payload), repr(self.uri))) - filename = self.uri_to_filename() - dirname = os.path.dirname(filename) - if not os.path.isdir(dirname): - os.makedirs(dirname) - f = open(filename, "wb") - f.write(self.payload.get_DER()) - f.close() - - def serve_withdraw(self): - """Withdraw an object.""" - rpki.log.info("Withdrawing %s" % repr(self.uri)) - os.remove(self.uri_to_filename()) - - def uri_to_filename(self): - """Convert a URI to a local filename.""" - if not self.uri.startswith("rsync://"): - raise rpki.exceptions.BadURISyntax - filename = self.gctx.publication_base + self.uri[len("rsync://"):] - if filename.find("//") >= 0 or filename.find("/../") >= 0 or filename.endswith("/.."): - raise rpki.exceptions.BadURISyntax - return filename - -class certificate_elt(publication_object_elt): - """<certificate/> element.""" - - element_name = "certificate" - payload_type = rpki.x509.X509 - -class crl_elt(publication_object_elt): - """<crl/> element.""" - - element_name = "crl" - payload_type = rpki.x509.CRL - -class manifest_elt(publication_object_elt): - """<manifest/> element.""" - - element_name = "manifest" - payload_type = rpki.x509.SignedManifest - -class roa_elt(publication_object_elt): - """<roa/> element.""" - - element_name = "roa" - payload_type = rpki.x509.ROA - -## @var obj2elt -# Map of data types to publication element wrapper types - -obj2elt = dict((e.payload_type, e) for e in (certificate_elt, crl_elt, manifest_elt, roa_elt)) - -class report_error_elt(rpki.xml_utils.base_elt, publication_namespace): - """<report_error/> element.""" - - element_name = "report_error" - attributes = ("tag", "error_code") - - @classmethod - def from_exception(cls, exc): - """Generate a <report_error/> element from an exception.""" - self = cls() - self.error_code = exc.__class__.__name__ - return self - -class msg(rpki.xml_utils.msg, publication_namespace): - """Publication PDU.""" - - ## @var version - # Protocol version - version = 1 - - ## @var pdus - # Dispatch table of PDUs for this protocol. - pdus = dict((x.element_name, x) - for x in (config_elt, client_elt, certificate_elt, crl_elt, manifest_elt, roa_elt, report_error_elt)) - - def serve_top_level(self, gctx, client): - """Serve one msg PDU.""" - if self.type != "query": - raise rpki.exceptions.BadQuery, "Message type is not query" - r_msg = self.__class__() - r_msg.type = "reply" - for q_pdu in self: - q_pdu.gctx = gctx - q_pdu.serve_dispatch(r_msg, client) - return r_msg - -class sax_handler(rpki.xml_utils.sax_handler): - """SAX handler for publication protocol.""" - - pdu = msg - name = "msg" - version = "1" - -class cms_msg(rpki.x509.XML_CMS_object): - """Class to hold a CMS-signed publication PDU.""" - - encoding = "us-ascii" - schema = rpki.relaxng.publication - saxify = sax_handler.saxify |