aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in6
-rw-r--r--rpki/irdb/migrations/0002_remove_client_parent_handle.py18
-rw-r--r--rpki/irdb/models.py1
-rw-r--r--rpki/irdb/zookeeper.py307
-rw-r--r--rpki/relaxng.py172
-rw-r--r--rpki/rpkidb/migrations/0001_initial.py57
-rw-r--r--rpki/x509.py2
-rw-r--r--schemas/relaxng/oob-setup.rnc68
-rw-r--r--schemas/relaxng/oob-setup.rng168
9 files changed, 611 insertions, 188 deletions
diff --git a/Makefile.in b/Makefile.in
index 3121c7c4..d688ef04 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -51,7 +51,8 @@ RNGS = schemas/relaxng/left-right.rng \
schemas/relaxng/publication-control.rng \
schemas/relaxng/myrpki.rng \
schemas/relaxng/router-certificate.rng \
- schemas/relaxng/rrdp.rng
+ schemas/relaxng/rrdp.rng \
+ schemas/relaxng/oob-setup.rng
SQLS = schemas/sql/rpkid.sql \
schemas/sql/pubd.sql
@@ -210,6 +211,9 @@ schemas/relaxng/router-certificate.rng: schemas/relaxng/router-certificate.rnc
schemas/relaxng/rrdp.rng: schemas/relaxng/rrdp.rnc
${TRANG} schemas/relaxng/rrdp.rnc schemas/relaxng/rrdp.rng
+schemas/relaxng/oob-setup.rng: schemas/relaxng/oob-setup.rnc
+ ${TRANG} schemas/relaxng/oob-setup.rnc schemas/relaxng/oob-setup.rng
+
# Eg: PYLINT_FLAGS='--disable=W0311'
lint:
diff --git a/rpki/irdb/migrations/0002_remove_client_parent_handle.py b/rpki/irdb/migrations/0002_remove_client_parent_handle.py
new file mode 100644
index 00000000..f86d165d
--- /dev/null
+++ b/rpki/irdb/migrations/0002_remove_client_parent_handle.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('irdb', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='client',
+ name='parent_handle',
+ ),
+ ]
diff --git a/rpki/irdb/models.py b/rpki/irdb/models.py
index ac65f0bc..c8e47717 100644
--- a/rpki/irdb/models.py
+++ b/rpki/irdb/models.py
@@ -537,7 +537,6 @@ class Repository(CrossCertification):
class Client(CrossCertification):
issuer = django.db.models.ForeignKey(ServerCA, related_name = "clients")
sia_base = django.db.models.TextField()
- parent_handle = HandleField()
# This shouldn't be necessary
class Meta:
diff --git a/rpki/irdb/zookeeper.py b/rpki/irdb/zookeeper.py
index 53418854..98201f95 100644
--- a/rpki/irdb/zookeeper.py
+++ b/rpki/irdb/zookeeper.py
@@ -42,13 +42,11 @@ from lxml.etree import (Element, SubElement, ElementTree,
from rpki.csv_utils import csv_reader
-# XML namespace and protocol version for OOB setup protocol. The name
-# is historical and may change before we propose this as the basis for
-# a standard.
+# XML namespace and protocol version for OOB setup protocol.
-myrpki_xmlns = rpki.relaxng.myrpki.xmlns
-myrpki_nsmap = rpki.relaxng.myrpki.nsmap
-myrpki_version = rpki.relaxng.myrpki.version
+oob_xmlns = rpki.relaxng.oob_setup.xmlns
+oob_nsmap = rpki.relaxng.oob_setup.nsmap
+oob_version = rpki.relaxng.oob_setup.version
# XML namespace and protocol version for router certificate requests.
# We probably ought to be pulling this sort of thing from the schema,
@@ -62,33 +60,18 @@ routercert_version = rpki.relaxng.router_certificate.version
# XML tags for elements in the above
-tag_myrpki_identity = myrpki_xmlns + "identity"
-tag_myrpki_bpki_ta = myrpki_xmlns + "bpki_ta"
-tag_myrpki_repository = myrpki_xmlns + "repository"
-tag_myrpki_bpki_client_ta = myrpki_xmlns + "bpki_client_ta"
-tag_myrpki_bpki_ta = myrpki_xmlns + "bpki_ta"
-tag_myrpki_parent = myrpki_xmlns + "parent"
-tag_myrpki_bpki_resource_ta = myrpki_xmlns + "bpki_resource_ta"
-tag_myrpki_bpki_child_ta = myrpki_xmlns + "bpki_child_ta"
-tag_myrpki_repository = myrpki_xmlns + "repository"
-tag_myrpki_referral = myrpki_xmlns + "referral"
-tag_myrpki_repository = myrpki_xmlns + "repository"
-tag_myrpki_authorization = myrpki_xmlns + "authorization"
-tag_myrpki_contact_info = myrpki_xmlns + "contact_info"
-tag_myrpki_repository = myrpki_xmlns + "repository"
-tag_myrpki_authorization = myrpki_xmlns + "authorization"
-tag_myrpki_bpki_resource_ta = myrpki_xmlns + "bpki_resource_ta"
-tag_myrpki_repository = myrpki_xmlns + "repository"
-tag_myrpki_authorization = myrpki_xmlns + "authorization"
-tag_myrpki_contact_info = myrpki_xmlns + "contact_info"
-tag_myrpki_bpki_client_ta = myrpki_xmlns + "bpki_client_ta"
-tag_myrpki_bpki_client_ta = myrpki_xmlns + "bpki_client_ta"
-tag_myrpki_authorization = myrpki_xmlns + "authorization"
-tag_myrpki_repository = myrpki_xmlns + "repository"
-tag_myrpki_bpki_server_ta = myrpki_xmlns + "bpki_server_ta"
-tag_myrpki_bpki_client_ta = myrpki_xmlns + "bpki_client_ta"
-tag_myrpki_contact_info = myrpki_xmlns + "contact_info"
-tag_myrpki_bpki_server_ta = myrpki_xmlns + "bpki_server_ta"
+tag_oob_authorization = oob_xmlns + "authorization"
+tag_oob_child_bpki_ta = oob_xmlns + "child_bpki_ta"
+tag_oob_child_request = oob_xmlns + "child_request"
+tag_oob_error = oob_xmlns + "error"
+tag_oob_offer = oob_xmlns + "offer"
+tag_oob_parent_bpki_ta = oob_xmlns + "parent_bpki_ta"
+tag_oob_parent_response = oob_xmlns + "parent_response"
+tag_oob_publisher_bpki_ta = oob_xmlns + "publisher_bpki_ta"
+tag_oob_publisher_request = oob_xmlns + "publisher_request"
+tag_oob_referral = oob_xmlns + "referral"
+tag_oob_repository_bpki_ta = oob_xmlns + "repository_bpki_ta"
+tag_oob_repository_response = oob_xmlns + "repository_response"
tag_router_certificate_request = routercert_xmlns + "router_certificate_request"
@@ -108,6 +91,7 @@ class CouldntTalkToDaemon(Exception): "Couldn't talk to daemon."
class BadXMLMessage(Exception): "Bad XML message."
class PastExpiration(Exception): "Expiration date has already passed."
class CantRunRootd(Exception): "Can't run rootd."
+class CouldntFindRepoParent(Exception): "Couldn't find repository's parent."
def B64Element(e, tag, obj, **kwargs):
@@ -164,7 +148,7 @@ class PEM_writer(object):
self.wrote.add(filename)
-def etree_read(filename_or_etree_wrapper, schema = rpki.relaxng.myrpki):
+def etree_read(filename_or_etree_wrapper, schema = rpki.relaxng.oob_setup):
"""
Read an etree from a file, verifying then stripping XML namespace
cruft. As a convenience, we also accept an etree_wrapper object in
@@ -186,7 +170,7 @@ class etree_wrapper(object):
without requiring the caller to understand much about them.
"""
- def __init__(self, e, msg = None, debug = False, schema = rpki.relaxng.myrpki):
+ def __init__(self, e, msg = None, debug = False, schema = rpki.relaxng.oob_setup):
self.msg = msg
e = copy.deepcopy(e)
if debug:
@@ -355,9 +339,9 @@ class Zookeeper(object):
easier for the GUI this way.
"""
- e = Element(tag_myrpki_identity, nsmap = myrpki_nsmap, version = myrpki_version,
- handle = self.handle)
- B64Element(e, tag_myrpki_bpki_ta, self.resource_ca.certificate)
+ e = Element(tag_oob_child_request, nsmap = oob_nsmap, version = oob_version,
+ child_handle = self.handle)
+ B64Element(e, tag_oob_child_bpki_ta, self.resource_ca.certificate)
return etree_wrapper(e, msg = 'This is the "identity" file you will need to send to your parent')
@@ -387,7 +371,8 @@ class Zookeeper(object):
rpki.irdb.models.Rootd.objects.get_or_certify(
issuer = self.resource_ca,
- service_uri = "http://localhost:%s/" % self.cfg.get("rootd_server_port", section = myrpki_section))
+ service_uri = "http://localhost:%s/" % self.cfg.get("rootd_server_port",
+ section = myrpki_section))
return self.generate_rootd_repository_offer()
@@ -398,18 +383,14 @@ class Zookeeper(object):
configure_rootd() because that's easier for the GUI.
"""
- # The following assumes we'll set up the respository manually.
- # Not sure this is a reasonable assumption, particularly if we
- # ever fix rootd to use the publication protocol.
-
try:
self.resource_ca.repositories.get(handle = self.handle)
return None
except rpki.irdb.models.Repository.DoesNotExist:
- e = Element(tag_myrpki_repository, nsmap = myrpki_nsmap, version = myrpki_version,
- type = "offer", handle = self.handle, parent_handle = self.handle)
- B64Element(e, tag_myrpki_bpki_client_ta, self.resource_ca.certificate)
+ e = Element(tag_oob_publisher_request, nsmap = oob_nsmap, version = oob_version,
+ publisher_handle = self.handle)
+ B64Element(e, tag_oob_publisher_bpki_ta, self.resource_ca.certificate)
return etree_wrapper(e, msg = 'This is the "repository offer" file for you to use if you want to publish in your own repository')
@@ -599,10 +580,10 @@ class Zookeeper(object):
data and up-down protocol service URI.
"""
- c = etree_read(filename)
+ x = etree_read(filename)
if child_handle is None:
- child_handle = c.get("handle")
+ child_handle = x.get("child_handle")
if valid_until is None:
valid_until = rpki.sundial.now() + rpki.sundial.timedelta(days = 365)
@@ -611,12 +592,12 @@ class Zookeeper(object):
if valid_until < rpki.sundial.now():
raise PastExpiration("Specified new expiration time %s has passed" % valid_until)
- self.log("Child calls itself %r, we call it %r" % (c.get("handle"), child_handle))
+ self.log("Child calls itself %r, we call it %r" % (x.get("child_handle"), child_handle))
child, created = rpki.irdb.models.Child.objects.get_or_certify(
issuer = self.resource_ca,
handle = child_handle,
- ta = rpki.x509.X509(Base64 = c.findtext(tag_myrpki_bpki_ta)),
+ ta = rpki.x509.X509(Base64 = x.findtext(tag_oob_child_bpki_ta)),
valid_until = valid_until)
return self.generate_parental_response(child), child_handle
@@ -634,11 +615,11 @@ class Zookeeper(object):
self.cfg.get("rpkid_server_port", section = myrpki_section),
self.handle, child.handle)
- e = Element(tag_myrpki_parent, nsmap = myrpki_nsmap, version = myrpki_version,
- parent_handle = self.handle, child_handle = child.handle,
- service_uri = service_uri, valid_until = str(child.valid_until))
- B64Element(e, tag_myrpki_bpki_resource_ta, self.resource_ca.certificate)
- B64Element(e, tag_myrpki_bpki_child_ta, child.ta)
+ e = Element(tag_oob_parent_response, nsmap = oob_nsmap, version = oob_version,
+ service_uri = service_uri,
+ child_handle = child.handle,
+ parent_handle = self.handle)
+ B64Element(e, tag_oob_parent_bpki_ta, self.resource_ca.certificate)
try:
if self.default_repository:
@@ -652,21 +633,18 @@ class Zookeeper(object):
self.log("Couldn't find any usable repositories, not giving referral")
elif repo.handle == self.handle:
- SubElement(e, tag_myrpki_repository, type = "offer")
+ SubElement(e, tag_oob_offer)
else:
proposed_sia_base = repo.sia_base + child.handle + "/"
referral_cert, created = rpki.irdb.models.Referral.objects.get_or_certify(issuer = self.resource_ca)
auth = rpki.x509.SignedReferral()
- auth.set_content(B64Element(None, tag_myrpki_referral, child.ta,
- version = myrpki_version,
+ auth.set_content(B64Element(None, tag_oob_authorization, child.ta,
+ nsmap = oob_nsmap, version = oob_version,
authorized_sia_base = proposed_sia_base))
auth.schema_check()
auth.sign(referral_cert.private_key, referral_cert.certificate, self.resource_ca.latest_crl)
-
- r = SubElement(e, tag_myrpki_repository, type = "referral")
- B64Element(r, tag_myrpki_authorization, auth, referrer = repo.client_handle)
- SubElement(r, tag_myrpki_contact_info)
+ B64Element(e, tag_oob_referral, auth, referrer = repo.client_handle)
return etree_wrapper(e, msg = "Send this file back to the child you just configured")
@@ -693,35 +671,39 @@ class Zookeeper(object):
the user wants to avail herself of the referral or offer.
"""
- p = etree_read(filename)
+ x = etree_read(filename)
if parent_handle is None:
- parent_handle = p.get("parent_handle")
+ parent_handle = x.get("parent_handle")
- r = p.find(tag_myrpki_repository)
+ offer = x.find(tag_oob_offer)
+ referral = x.find(tag_oob_referral)
- repository_type = "none"
- referrer = None
- referral_authorization = None
+ if offer is not None:
+ repository_type = "offer"
+ referrer = None
+ referral_authorization = None
- if r is not None:
- repository_type = r.get("type")
+ elif referral is not None:
+ repository_type = "referral"
+ referrer = referral.get("referrer")
+ referral_authorization = rpki.x509.SignedReferral(Base64 = referral.text)
- if repository_type == "referral":
- a = r.find(tag_myrpki_authorization)
- referrer = a.get("referrer")
- referral_authorization = rpki.x509.SignedReferral(Base64 = a.text)
+ else:
+ repository_type = "none"
+ referrer = None
+ referral_authorization = None
- self.log("Parent calls itself %r, we call it %r" % (p.get("parent_handle"), parent_handle))
- self.log("Parent calls us %r" % p.get("child_handle"))
+ self.log("Parent calls itself %r, we call it %r" % (x.get("parent_handle"), parent_handle))
+ self.log("Parent calls us %r" % x.get("child_handle"))
parent, created = rpki.irdb.models.Parent.objects.get_or_certify(
issuer = self.resource_ca,
handle = parent_handle,
- child_handle = p.get("child_handle"),
- parent_handle = p.get("parent_handle"),
- service_uri = p.get("service_uri"),
- ta = rpki.x509.X509(Base64 = p.findtext(tag_myrpki_bpki_resource_ta)),
+ child_handle = x.get("child_handle"),
+ parent_handle = x.get("parent_handle"),
+ service_uri = x.get("service_uri"),
+ ta = rpki.x509.X509(Base64 = x.findtext(tag_oob_parent_bpki_ta)),
repository_type = repository_type,
referrer = referrer,
referral_authorization = referral_authorization)
@@ -734,12 +716,13 @@ class Zookeeper(object):
Generate repository request for a given parent.
"""
- e = Element(tag_myrpki_repository, nsmap = myrpki_nsmap, version = myrpki_version,
- handle = self.handle, parent_handle = parent.handle, type = parent.repository_type)
+ e = Element(tag_oob_publisher_request, nsmap = oob_nsmap, version = oob_version,
+ publisher_handle = self.handle)
+ B64Element(e, tag_oob_publisher_bpki_ta, self.resource_ca.certificate)
if parent.repository_type == "referral":
- B64Element(e, tag_myrpki_authorization, parent.referral_authorization, referrer = parent.referrer)
- SubElement(e, tag_myrpki_contact_info)
- B64Element(e, tag_myrpki_bpki_client_ta, self.resource_ca.certificate)
+ B64Element(e, tag_oob_referral, parent.referral_authorization,
+ referrer = parent.referrer)
+
return etree_wrapper(e, msg = "This is the file to send to the repository operator")
@@ -771,65 +754,67 @@ class Zookeeper(object):
and service URI.
"""
- client = etree_read(filename)
+ x = etree_read(filename)
- client_ta = rpki.x509.X509(Base64 = client.findtext(tag_myrpki_bpki_client_ta))
+ client_ta = rpki.x509.X509(Base64 = x.findtext(tag_oob_publisher_bpki_ta))
+
+ referral = x.find(tag_oob_referral)
+
+ default_sia_base = "rsync://{self.rsync_server}/{self.rsync_module}/{handle}/".format(
+ self = self, handle = x.get("publisher_handle"))
if sia_base is None and flat:
self.log("Flat publication structure forced, homing client at top-level")
- sia_base = "rsync://%s/%s/%s/" % (self.rsync_server, self.rsync_module, client.get("handle"))
+ sia_base = default_sia_base
- if sia_base is None and client.get("type") == "referral":
+ if sia_base is None and referral is not None:
self.log("This looks like a referral, checking")
try:
- auth = client.find(tag_myrpki_authorization)
- referrer = self.server_ca.clients.get(handle = auth.get("referrer"))
- referral_cms = rpki.x509.SignedReferral(Base64 = auth.text)
- referral_xml = referral_cms.unwrap(ta = (referrer.certificate, self.server_ca.certificate))
- if rpki.x509.X509(Base64 = referral_xml.text) != client_ta:
+ referrer = referral.get("referrer")
+ referrer = self.server_ca.clients.get(handle = referrer)
+ referral = rpki.x509.SignedReferral(Base64 = referral.text)
+ referral = referral.unwrap(ta = (referrer.certificate, self.server_ca.certificate))
+ if rpki.x509.X509(Base64 = referral.text) != client_ta:
raise BadXMLMessage("Referral trust anchor does not match")
- sia_base = referral_xml.get("authorized_sia_base")
+ sia_base = referral.get("authorized_sia_base")
except rpki.irdb.models.Client.DoesNotExist:
- self.log("We have no record of the client (%s) alleged to have made this referral" % auth.get("referrer"))
+ self.log("We have no record of the client ({}) alleged to have made this referral".format(referrer))
- if sia_base is None and client.get("type") == "offer":
- self.log("This looks like an offer, checking")
+ if sia_base is None and referral is None:
+ self.log("This might be an offer, checking")
try:
parent = rpki.irdb.models.ResourceHolderCA.objects.get(children__ta__exact = client_ta)
if "/" in parent.repositories.get(ta = self.server_ca.certificate).client_handle:
self.log("Client's parent is not top-level, this is not a valid offer")
else:
self.log("Found client and its parent, nesting")
- sia_base = "rsync://%s/%s/%s/%s/" % (self.rsync_server, self.rsync_module,
- parent.handle, client.get("handle"))
+ sia_base = "rsync://{self.rsync_server}/{self.rsync_module}/{parent_handle}/{client_handle}/".format(
+ self = self, parent_handle = parent.handle, client_handle = x.get("publisher_handle"))
except rpki.irdb.models.Repository.DoesNotExist:
self.log("Found client's parent, but repository isn't set, this shouldn't happen!")
except rpki.irdb.models.ResourceHolderCA.DoesNotExist:
try:
rpki.irdb.models.Rootd.objects.get(issuer__certificate__exact = client_ta)
- except rpki.irdb.models.Rootd.DoesNotExist:
- self.log("We don't host this client's parent, so we didn't make this offer")
- else:
self.log("This client's parent is rootd")
+ sia_base = default_sia_base
+ except rpki.irdb.models.Rootd.DoesNotExist:
+ self.log("We don't host this client's parent, so we didn't make an offer")
if sia_base is None:
- self.log("Don't know where to nest this client, defaulting to top-level")
- sia_base = "rsync://%s/%s/%s/" % (self.rsync_server, self.rsync_module, client.get("handle"))
+ self.log("Don't know where else to nest this client, so defaulting to top-level")
+ sia_base = default_sia_base
if not sia_base.startswith("rsync://"):
raise BadXMLMessage("Malformed sia_base parameter %r, should start with 'rsync://'" % sia_base)
client_handle = "/".join(sia_base.rstrip("/").split("/")[4:])
- parent_handle = client.get("parent_handle")
-
- self.log("Client calls itself %r, we call it %r" % (client.get("handle"), client_handle))
- self.log("Client says its parent handle is %r" % parent_handle)
+ self.log("Client calls itself %r, we call it %r" % (
+ x.get("publisher_handle"), client_handle))
client, created = rpki.irdb.models.Client.objects.get_or_certify(
issuer = self.server_ca,
handle = client_handle,
- parent_handle = parent_handle,
ta = client_ta,
sia_base = sia_base)
@@ -841,21 +826,19 @@ class Zookeeper(object):
Generate repository response XML to a given client.
"""
- service_uri = "http://%s:%s/client/%s" % (
- self.cfg.get("pubd_server_host", section = myrpki_section),
- self.cfg.get("pubd_server_port", section = myrpki_section),
- client.handle)
-
- e = Element(tag_myrpki_repository, nsmap = myrpki_nsmap, version = myrpki_version,
- type = "confirmed",
- client_handle = client.handle,
- parent_handle = client.parent_handle,
- sia_base = client.sia_base,
- service_uri = service_uri)
-
- B64Element(e, tag_myrpki_bpki_server_ta, self.server_ca.certificate)
- B64Element(e, tag_myrpki_bpki_client_ta, client.ta)
- SubElement(e, tag_myrpki_contact_info).text = self.pubd_contact_info
+ service_uri = "http://{host}:{port}/client/{handle}".format(
+ host = self.cfg.get("pubd_server_host", section = myrpki_section),
+ port = self.cfg.get("pubd_server_port", section = myrpki_section),
+ handle = client.handle)
+
+ e = Element(tag_oob_repository_response, nsmap = oob_nsmap, version = oob_version,
+ service_uri = service_uri,
+ publisher_handle = client.handle,
+ sia_base = client.sia_base)
+
+ # This is where we'd insert the rrdp_notification_uri attribute
+
+ B64Element(e, tag_oob_repository_bpki_ta, self.server_ca.certificate)
return etree_wrapper(e, msg = "Send this file back to the publication client you just configured")
@@ -878,32 +861,52 @@ class Zookeeper(object):
corresponding parent data in our local database.
"""
- r = etree_read(filename)
+ x = etree_read(filename)
- if parent_handle is None:
- parent_handle = r.get("parent_handle")
+ self.log("Repository calls us %r" % (x.get("client_handle")))
- self.log("Repository calls us %r" % (r.get("client_handle")))
- self.log("Repository response associated with parent_handle %r" % parent_handle)
+ if parent_handle is not None:
+ self.log("Explicit parent_handle given")
+ try:
+ if parent_handle == self.handle:
+ turtle = self.resource_ca.rootd
+ else:
+ turtle = self.resource_ca.parents.get(handle = parent_handle)
+ except (rpki.irdb.models.Parent.DoesNotExist, rpki.irdb.models.Rootd.DoesNotExist):
+ self.log("Could not find parent %r in our database" % parent_handle)
+ raise CouldntFindRepoParent
- try:
- if parent_handle == self.handle:
- turtle = self.resource_ca.rootd
+ else:
+ turtles = []
+ for parent in self.resource_ca.parents.all():
+ try:
+ _ = parent.repository
+ except rpki.irdb.models.Repository.DoesNotExist:
+ turtles.append(parent)
+ try:
+ _ = self.resource_ca.rootd.repository
+ except rpki.irdb.models.Repository.DoesNotExist:
+ turtles.append(self.resource_ca.rootd)
+ except rpki.irdb.models.Rootd.DoesNotExist:
+ pass
+ if len(turtles) != 1:
+ self.log("No explicit parent_handle given and unable to guess")
+ raise CouldntFindRepoParent
+ turtle = turtles[0]
+ if isinstance(turtle, rpki.irdb.models.Rootd):
+ parent_handle = self.handle
else:
- turtle = self.resource_ca.parents.get(handle = parent_handle)
-
- except (rpki.irdb.models.Parent.DoesNotExist, rpki.irdb.models.Rootd.DoesNotExist):
- self.log("Could not find parent %r in our database" % parent_handle)
+ parent_handle = turtle.handle
+ self.log("No explicit parent_handle given, guessing parent {}".format(parent_handle))
- else:
- rpki.irdb.models.Repository.objects.get_or_certify(
- issuer = self.resource_ca,
- handle = parent_handle,
- client_handle = r.get("client_handle"),
- service_uri = r.get("service_uri"),
- sia_base = r.get("sia_base"),
- ta = rpki.x509.X509(Base64 = r.findtext(tag_myrpki_bpki_server_ta)),
- turtle = turtle)
+ rpki.irdb.models.Repository.objects.get_or_certify(
+ issuer = self.resource_ca,
+ handle = parent_handle,
+ client_handle = x.get("publisher_handle"),
+ service_uri = x.get("service_uri"),
+ sia_base = x.get("sia_base"),
+ ta = rpki.x509.X509(Base64 = x.findtext(tag_oob_repository_bpki_ta)),
+ turtle = turtle)
@django.db.transaction.atomic
@@ -1684,15 +1687,15 @@ class Zookeeper(object):
router-ID supplied in the XML.
"""
- xml = etree_read(router_certificate_request_xml, schema = rpki.relaxng.router_certificate)
+ x = etree_read(router_certificate_request_xml, schema = rpki.relaxng.router_certificate)
- for req in xml.getiterator(tag_router_certificate_request):
+ for x in x.getiterator(tag_router_certificate_request):
- pkcs10 = rpki.x509.PKCS10(Base64 = req.text)
- router_id = long(req.get("router_id"))
- asns = rpki.resource_set.resource_set_as(req.get("asn"))
+ pkcs10 = rpki.x509.PKCS10(Base64 = x.text)
+ router_id = long(x.get("router_id"))
+ asns = rpki.resource_set.resource_set_as(x.get("asn"))
if not valid_until:
- valid_until = req.get("valid_until")
+ valid_until = x.get("valid_until")
if valid_until and isinstance(valid_until, (str, unicode)):
valid_until = rpki.sundial.datetime.fromXMLtime(valid_until)
diff --git a/rpki/relaxng.py b/rpki/relaxng.py
index 6eaf5e2e..829cddc2 100644
--- a/rpki/relaxng.py
+++ b/rpki/relaxng.py
@@ -1479,6 +1479,178 @@ myrpki = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?>
-->
''')
+## @var oob_setup
+## Parsed RelaxNG oob_setup schema
+oob_setup = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?>
+<!-- $Id: rpki-setup.rnc 3429 2015-10-14 23:46:50Z sra $ -->
+<grammar ns="http://www.hactrn.net/uris/rpki/rpki-setup/" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+ <define name="version">
+ <value>1</value>
+ </define>
+ <define name="base64">
+ <data type="base64Binary">
+ <param name="maxLength">512000</param>
+ </data>
+ </define>
+ <define name="handle">
+ <data type="string">
+ <param name="maxLength">255</param>
+ <param name="pattern">[\-_A-Za-z0-9/]*</param>
+ </data>
+ </define>
+ <define name="uri">
+ <data type="anyURI">
+ <param name="maxLength">4096</param>
+ </data>
+ </define>
+ <define name="any">
+ <element>
+ <anyName/>
+ <zeroOrMore>
+ <attribute>
+ <anyName/>
+ </attribute>
+ </zeroOrMore>
+ <zeroOrMore>
+ <choice>
+ <ref name="any"/>
+ <text/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+ <define name="authorization_token">
+ <ref name="base64"/>
+ </define>
+ <define name="bpki_ta">
+ <ref name="base64"/>
+ </define>
+ <start combine="choice">
+ <element name="child_request">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="child_handle">
+ <ref name="handle"/>
+ </attribute>
+ <element name="child_bpki_ta">
+ <ref name="bpki_ta"/>
+ </element>
+ </element>
+ </start>
+ <start combine="choice">
+ <element name="parent_response">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="service_uri">
+ <ref name="uri"/>
+ </attribute>
+ <attribute name="child_handle">
+ <ref name="handle"/>
+ </attribute>
+ <attribute name="parent_handle">
+ <ref name="handle"/>
+ </attribute>
+ <element name="parent_bpki_ta">
+ <ref name="bpki_ta"/>
+ </element>
+ <optional>
+ <element name="offer">
+ <empty/>
+ </element>
+ </optional>
+ <zeroOrMore>
+ <element name="referral">
+ <attribute name="referrer">
+ <ref name="handle"/>
+ </attribute>
+ <optional>
+ <attribute name="contact_uri">
+ <ref name="uri"/>
+ </attribute>
+ </optional>
+ <ref name="authorization_token"/>
+ </element>
+ </zeroOrMore>
+ </element>
+ </start>
+ <start combine="choice">
+ <element name="publisher_request">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="publisher_handle">
+ <ref name="handle"/>
+ </attribute>
+ <element name="publisher_bpki_ta">
+ <ref name="bpki_ta"/>
+ </element>
+ <zeroOrMore>
+ <element name="referral">
+ <attribute name="referrer">
+ <ref name="handle"/>
+ </attribute>
+ <ref name="authorization_token"/>
+ </element>
+ </zeroOrMore>
+ </element>
+ </start>
+ <start combine="choice">
+ <element name="repository_response">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="service_uri">
+ <ref name="uri"/>
+ </attribute>
+ <attribute name="publisher_handle">
+ <ref name="handle"/>
+ </attribute>
+ <attribute name="sia_base">
+ <ref name="uri"/>
+ </attribute>
+ <optional>
+ <attribute name="rrdp_notification_uri">
+ <ref name="uri"/>
+ </attribute>
+ </optional>
+ <element name="repository_bpki_ta">
+ <ref name="bpki_ta"/>
+ </element>
+ </element>
+ </start>
+ <start combine="choice">
+ <element name="authorization">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="authorized_sia_base">
+ <ref name="uri"/>
+ </attribute>
+ <ref name="bpki_ta"/>
+ </element>
+ </start>
+ <start combine="choice">
+ <element name="error">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="reason">
+ <choice>
+ <value>syntax-error</value>
+ <value>authentication-failure</value>
+ <value>refused</value>
+ </choice>
+ </attribute>
+ <optional>
+ <ref name="any"/>
+ </optional>
+ </element>
+ </start>
+</grammar>
+''')
+
## @var publication_control
## Parsed RelaxNG publication_control schema
publication_control = RelaxNGParser(r'''<?xml version="1.0" encoding="UTF-8"?>
diff --git a/rpki/rpkidb/migrations/0001_initial.py b/rpki/rpkidb/migrations/0001_initial.py
index 77c9012f..f88f0cdd 100644
--- a/rpki/rpkidb/migrations/0001_initial.py
+++ b/rpki/rpkidb/migrations/0001_initial.py
@@ -27,11 +27,11 @@ class Migration(migrations.Migration):
name='CA',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('last_crl_sn', models.BigIntegerField()),
- ('last_manifest_sn', models.BigIntegerField()),
+ ('last_crl_sn', models.BigIntegerField(default=1)),
+ ('last_manifest_sn', models.BigIntegerField(default=1)),
('next_manifest_update', rpki.fields.SundialField(null=True)),
('next_crl_update', rpki.fields.SundialField(null=True)),
- ('last_issued_sn', models.BigIntegerField()),
+ ('last_issued_sn', models.BigIntegerField(default=1)),
('sia_uri', models.TextField(null=True)),
('parent_resource_class', models.TextField(null=True)),
],
@@ -52,7 +52,7 @@ class Migration(migrations.Migration):
('manifest_published', rpki.fields.SundialField(null=True)),
('state', rpki.fields.EnumField(choices=[(1, 'pending'), (2, 'active'), (3, 'deprecated'), (4, 'revoked')])),
('ca_cert_uri', models.TextField(null=True)),
- ('ca', models.ForeignKey(to='rpkidb.CA')),
+ ('ca', models.ForeignKey(related_name='ca_details', to='rpkidb.CA')),
],
),
migrations.CreateModel(
@@ -63,7 +63,7 @@ class Migration(migrations.Migration):
('bpki_cert', rpki.fields.CertificateField(default=None, serialize=False, null=True, blank=True)),
('bpki_glue', rpki.fields.CertificateField(default=None, serialize=False, null=True, blank=True)),
('last_cms_timestamp', rpki.fields.SundialField(null=True)),
- ('bsc', models.ForeignKey(to='rpkidb.BSC')),
+ ('bsc', models.ForeignKey(related_name='children', to='rpkidb.BSC')),
],
),
migrations.CreateModel(
@@ -73,8 +73,8 @@ class Migration(migrations.Migration):
('cert', rpki.fields.CertificateField(default=None, serialize=False, blank=True)),
('published', rpki.fields.SundialField(null=True)),
('ski', rpki.fields.BlobField(default=None, serialize=False, blank=True)),
- ('ca_detail', models.ForeignKey(to='rpkidb.CADetail')),
- ('child', models.ForeignKey(to='rpkidb.Child')),
+ ('ca_detail', models.ForeignKey(related_name='child_certs', to='rpkidb.CADetail')),
+ ('child', models.ForeignKey(related_name='child_certs', to='rpkidb.Child')),
],
),
migrations.CreateModel(
@@ -84,7 +84,7 @@ class Migration(migrations.Migration):
('ski', rpki.fields.BlobField(default=None, serialize=False, blank=True)),
('cert', rpki.fields.CertificateField(default=None, serialize=False, blank=True)),
('published', rpki.fields.SundialField(null=True)),
- ('ca_detail', models.ForeignKey(to='rpkidb.CADetail')),
+ ('ca_detail', models.ForeignKey(related_name='ee_certs', to='rpkidb.CADetail')),
],
),
migrations.CreateModel(
@@ -95,7 +95,7 @@ class Migration(migrations.Migration):
('cert', rpki.fields.CertificateField(default=None, serialize=False, blank=True)),
('ghostbuster', rpki.fields.GhostbusterField(default=None, serialize=False, blank=True)),
('published', rpki.fields.SundialField(null=True)),
- ('ca_detail', models.ForeignKey(to='rpkidb.CADetail')),
+ ('ca_detail', models.ForeignKey(related_name='ghostbusters', to='rpkidb.CADetail')),
],
),
migrations.CreateModel(
@@ -110,7 +110,7 @@ class Migration(migrations.Migration):
('sender_name', models.TextField(null=True)),
('recipient_name', models.TextField(null=True)),
('last_cms_timestamp', rpki.fields.SundialField(null=True)),
- ('bsc', models.ForeignKey(to='rpkidb.BSC')),
+ ('bsc', models.ForeignKey(related_name='parents', to='rpkidb.BSC')),
],
),
migrations.CreateModel(
@@ -122,7 +122,7 @@ class Migration(migrations.Migration):
('bpki_cert', rpki.fields.CertificateField(default=None, serialize=False, null=True, blank=True)),
('bpki_glue', rpki.fields.CertificateField(default=None, serialize=False, null=True, blank=True)),
('last_cms_timestamp', rpki.fields.SundialField(null=True)),
- ('bsc', models.ForeignKey(to='rpkidb.BSC')),
+ ('bsc', models.ForeignKey(related_name='repositories', to='rpkidb.BSC')),
],
),
migrations.CreateModel(
@@ -132,7 +132,7 @@ class Migration(migrations.Migration):
('serial', models.BigIntegerField()),
('revoked', rpki.fields.SundialField()),
('expires', rpki.fields.SundialField()),
- ('ca_detail', models.ForeignKey(to='rpkidb.CADetail')),
+ ('ca_detail', models.ForeignKey(related_name='revoked_certs', to='rpkidb.CADetail')),
],
),
migrations.CreateModel(
@@ -140,21 +140,12 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('asn', models.BigIntegerField()),
+ ('ipv4', models.TextField(null=True)),
+ ('ipv6', models.TextField(null=True)),
('cert', rpki.fields.CertificateField(default=None, serialize=False, blank=True)),
('roa', rpki.fields.ROAField(default=None, serialize=False, blank=True)),
('published', rpki.fields.SundialField(null=True)),
- ('ca_detail', models.ForeignKey(to='rpkidb.CADetail')),
- ],
- ),
- migrations.CreateModel(
- name='ROAPrefix',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('prefix', models.CharField(max_length=40)),
- ('prefixlen', models.SmallIntegerField()),
- ('max_prefixlen', models.SmallIntegerField()),
- ('version', models.SmallIntegerField()),
- ('roa', models.ForeignKey(to='rpkidb.ROA')),
+ ('ca_detail', models.ForeignKey(related_name='roas', to='rpkidb.CADetail')),
],
),
migrations.CreateModel(
@@ -172,47 +163,47 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='roa',
name='self',
- field=models.ForeignKey(to='rpkidb.Self'),
+ field=models.ForeignKey(related_name='roas', to='rpkidb.Self'),
),
migrations.AddField(
model_name='repository',
name='self',
- field=models.ForeignKey(to='rpkidb.Self'),
+ field=models.ForeignKey(related_name='repositories', to='rpkidb.Self'),
),
migrations.AddField(
model_name='parent',
name='repository',
- field=models.ForeignKey(to='rpkidb.Repository'),
+ field=models.ForeignKey(related_name='parents', to='rpkidb.Repository'),
),
migrations.AddField(
model_name='parent',
name='self',
- field=models.ForeignKey(to='rpkidb.Self'),
+ field=models.ForeignKey(related_name='parents', to='rpkidb.Self'),
),
migrations.AddField(
model_name='ghostbuster',
name='self',
- field=models.ForeignKey(to='rpkidb.Self'),
+ field=models.ForeignKey(related_name='ghostbusters', to='rpkidb.Self'),
),
migrations.AddField(
model_name='eecert',
name='self',
- field=models.ForeignKey(to='rpkidb.Self'),
+ field=models.ForeignKey(related_name='ee_certs', to='rpkidb.Self'),
),
migrations.AddField(
model_name='child',
name='self',
- field=models.ForeignKey(to='rpkidb.Self'),
+ field=models.ForeignKey(related_name='children', to='rpkidb.Self'),
),
migrations.AddField(
model_name='ca',
name='parent',
- field=models.ForeignKey(to='rpkidb.Parent'),
+ field=models.ForeignKey(related_name='cas', to='rpkidb.Parent'),
),
migrations.AddField(
model_name='bsc',
name='self',
- field=models.ForeignKey(to='rpkidb.Self'),
+ field=models.ForeignKey(related_name='bscs', to='rpkidb.Self'),
),
migrations.AlterUniqueTogether(
name='repository',
diff --git a/rpki/x509.py b/rpki/x509.py
index 40244e4d..b8a1bfa9 100644
--- a/rpki/x509.py
+++ b/rpki/x509.py
@@ -2034,7 +2034,7 @@ class XML_CMS_object(Wrapped_CMS_object):
class SignedReferral(XML_CMS_object):
encoding = "us-ascii"
- schema = rpki.relaxng.myrpki
+ schema = rpki.relaxng.oob_setup
class Ghostbuster(Wrapped_CMS_object):
"""
diff --git a/schemas/relaxng/oob-setup.rnc b/schemas/relaxng/oob-setup.rnc
new file mode 100644
index 00000000..3bd7a652
--- /dev/null
+++ b/schemas/relaxng/oob-setup.rnc
@@ -0,0 +1,68 @@
+# $Id: rpki-setup.rnc 3429 2015-10-14 23:46:50Z sra $
+
+default namespace = "http://www.hactrn.net/uris/rpki/rpki-setup/"
+
+version = "1"
+
+base64 = xsd:base64Binary { maxLength="512000" }
+handle = xsd:string { maxLength="255" pattern="[\-_A-Za-z0-9/]*" }
+uri = xsd:anyURI { maxLength="4096" }
+any = element * { attribute * { text }*, ( any | text )* }
+
+authorization_token = base64
+bpki_ta = base64
+
+start |= element child_request {
+ attribute version { version },
+ attribute child_handle { handle },
+ element child_bpki_ta { bpki_ta }
+}
+
+start |= element parent_response {
+ attribute version { version },
+ attribute service_uri { uri },
+ attribute child_handle { handle },
+ attribute parent_handle { handle },
+ element parent_bpki_ta { bpki_ta },
+ element offer { empty }?,
+ element referral {
+ attribute referrer { handle },
+ attribute contact_uri { uri }?,
+ authorization_token
+ }*
+}
+
+start |= element publisher_request {
+ attribute version { version },
+ attribute publisher_handle { handle },
+ element publisher_bpki_ta { bpki_ta },
+ element referral {
+ attribute referrer { handle },
+ authorization_token
+ }*
+}
+
+start |= element repository_response {
+ attribute version { version },
+ attribute service_uri { uri },
+ attribute publisher_handle { handle },
+ attribute sia_base { uri },
+ attribute rrdp_notification_uri { uri }?,
+ element repository_bpki_ta { bpki_ta }
+}
+
+start |= element authorization {
+ attribute version { version },
+ attribute authorized_sia_base { uri },
+ bpki_ta
+}
+
+start |= element error {
+ attribute version { version },
+ attribute reason {
+ "syntax-error" |
+ "authentication-failure" |
+ "refused"
+ },
+ any?
+}
diff --git a/schemas/relaxng/oob-setup.rng b/schemas/relaxng/oob-setup.rng
new file mode 100644
index 00000000..00278047
--- /dev/null
+++ b/schemas/relaxng/oob-setup.rng
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- $Id: rpki-setup.rnc 3429 2015-10-14 23:46:50Z sra $ -->
+<grammar ns="http://www.hactrn.net/uris/rpki/rpki-setup/" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+ <define name="version">
+ <value>1</value>
+ </define>
+ <define name="base64">
+ <data type="base64Binary">
+ <param name="maxLength">512000</param>
+ </data>
+ </define>
+ <define name="handle">
+ <data type="string">
+ <param name="maxLength">255</param>
+ <param name="pattern">[\-_A-Za-z0-9/]*</param>
+ </data>
+ </define>
+ <define name="uri">
+ <data type="anyURI">
+ <param name="maxLength">4096</param>
+ </data>
+ </define>
+ <define name="any">
+ <element>
+ <anyName/>
+ <zeroOrMore>
+ <attribute>
+ <anyName/>
+ </attribute>
+ </zeroOrMore>
+ <zeroOrMore>
+ <choice>
+ <ref name="any"/>
+ <text/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+ <define name="authorization_token">
+ <ref name="base64"/>
+ </define>
+ <define name="bpki_ta">
+ <ref name="base64"/>
+ </define>
+ <start combine="choice">
+ <element name="child_request">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="child_handle">
+ <ref name="handle"/>
+ </attribute>
+ <element name="child_bpki_ta">
+ <ref name="bpki_ta"/>
+ </element>
+ </element>
+ </start>
+ <start combine="choice">
+ <element name="parent_response">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="service_uri">
+ <ref name="uri"/>
+ </attribute>
+ <attribute name="child_handle">
+ <ref name="handle"/>
+ </attribute>
+ <attribute name="parent_handle">
+ <ref name="handle"/>
+ </attribute>
+ <element name="parent_bpki_ta">
+ <ref name="bpki_ta"/>
+ </element>
+ <optional>
+ <element name="offer">
+ <empty/>
+ </element>
+ </optional>
+ <zeroOrMore>
+ <element name="referral">
+ <attribute name="referrer">
+ <ref name="handle"/>
+ </attribute>
+ <optional>
+ <attribute name="contact_uri">
+ <ref name="uri"/>
+ </attribute>
+ </optional>
+ <ref name="authorization_token"/>
+ </element>
+ </zeroOrMore>
+ </element>
+ </start>
+ <start combine="choice">
+ <element name="publisher_request">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="publisher_handle">
+ <ref name="handle"/>
+ </attribute>
+ <element name="publisher_bpki_ta">
+ <ref name="bpki_ta"/>
+ </element>
+ <zeroOrMore>
+ <element name="referral">
+ <attribute name="referrer">
+ <ref name="handle"/>
+ </attribute>
+ <ref name="authorization_token"/>
+ </element>
+ </zeroOrMore>
+ </element>
+ </start>
+ <start combine="choice">
+ <element name="repository_response">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="service_uri">
+ <ref name="uri"/>
+ </attribute>
+ <attribute name="publisher_handle">
+ <ref name="handle"/>
+ </attribute>
+ <attribute name="sia_base">
+ <ref name="uri"/>
+ </attribute>
+ <optional>
+ <attribute name="rrdp_notification_uri">
+ <ref name="uri"/>
+ </attribute>
+ </optional>
+ <element name="repository_bpki_ta">
+ <ref name="bpki_ta"/>
+ </element>
+ </element>
+ </start>
+ <start combine="choice">
+ <element name="authorization">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="authorized_sia_base">
+ <ref name="uri"/>
+ </attribute>
+ <ref name="bpki_ta"/>
+ </element>
+ </start>
+ <start combine="choice">
+ <element name="error">
+ <attribute name="version">
+ <ref name="version"/>
+ </attribute>
+ <attribute name="reason">
+ <choice>
+ <value>syntax-error</value>
+ <value>authentication-failure</value>
+ <value>refused</value>
+ </choice>
+ </attribute>
+ <optional>
+ <ref name="any"/>
+ </optional>
+ </element>
+ </start>
+</grammar>