aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--myrpki.rototill/Makefile20
-rw-r--r--myrpki.rototill/examples/myrpki.conf13
-rw-r--r--myrpki.rototill/myirbe.py37
-rw-r--r--myrpki.rototill/myrpki.py121
-rw-r--r--myrpki.rototill/myrpki.rnc (renamed from myrpki.rototill/schema.rnc)13
-rw-r--r--myrpki.rototill/myrpki.rng (renamed from myrpki.rototill/schema.rng)37
-rw-r--r--myrpki.rototill/schema.py199
-rw-r--r--myrpki.rototill/xml-parse-test.py5
-rw-r--r--myrpki.rototill/yamltest.py2
9 files changed, 157 insertions, 290 deletions
diff --git a/myrpki.rototill/Makefile b/myrpki.rototill/Makefile
index 73794508..a8306e30 100644
--- a/myrpki.rototill/Makefile
+++ b/myrpki.rototill/Makefile
@@ -1,20 +1,14 @@
# $Id$
-all: schema.py
+all: myrpki.rng
-lint: myrpki.xml schema.rng
- xmllint --noout --relaxng schema.rng myrpki.xml
+lint: myrpki.xml myrpki.rng
+ xmllint --noout --relaxng myrpki.rng myrpki.xml
-schema.rng: schema.rnc
- trang schema.rnc schema.rng
+myrpki.rng: myrpki.rnc
+ trang myrpki.rnc myrpki.rng
-schema.py: schema.rng
- echo >$@ 'import lxml.etree'
- echo >>$@ -n "myrpki = lxml.etree.RelaxNG(lxml.etree.fromstring('''"
- cat >>$@ schema.rng
- echo >>$@ "'''))"
-
-parse: myrpki.xml schema.py
+parse: myrpki.xml all
python xml-parse-test.py
clean:
@@ -35,5 +29,5 @@ backup:
tar cvvzf test.$$(TZ='' date +%Y.%m.%d.%H.%M.%S).tgz screenlog.* test backup.*.sql
rm backup.*.sql
-test: schema.py
+test: all
python yamltest.py
diff --git a/myrpki.rototill/examples/myrpki.conf b/myrpki.rototill/examples/myrpki.conf
index 7cf80eb6..79f1d229 100644
--- a/myrpki.rototill/examples/myrpki.conf
+++ b/myrpki.rototill/examples/myrpki.conf
@@ -26,19 +26,6 @@
handle = Me
-# BPKI trust anchor for the repository in which this <self/> will be
-# publishing its outputs. You need to set this.
-
-repository_bpki_certificate = repository-ta.cer
-
-# Name by which repository will know this <self/>. This may be a
-# structured handle, eg, "Grandma/Mom/Me" or might be a simple handle,
-# depending on how the repository is set up. Syntax is same as
-# "handle", with the addition of "/" characters as an allowed
-# delimiter. You need to set this.
-
-repository_handle = ${myrpki::handle}
-
# Names of various files and directories. Don't change these without
# a good reason.
diff --git a/myrpki.rototill/myirbe.py b/myrpki.rototill/myirbe.py
index 35de6ff1..d9c75ddc 100644
--- a/myrpki.rototill/myirbe.py
+++ b/myrpki.rototill/myirbe.py
@@ -65,11 +65,10 @@ def findbase64(tree, name, b64type = rpki.x509.X509):
x = tree.findtext(name)
return b64type(Base64 = x) if x else None
-# For simple cases we don't really care what these value are, so long
-# as we're consistant about them, so wiring them in is fine.
+# For simple cases we don't really care what this value is, so long as
+# we're consistant about it, so wiring this in is fine.
bsc_handle = "bsc"
-repository_handle = "repository"
os.environ["TZ"] = "UTC"
time.tzset()
@@ -315,18 +314,18 @@ for xmlfile in xmlfiles:
if bsc_pdu and bsc_pdu.pkcs10_request:
bsc_req = bsc_pdu.pkcs10_request
- # In general we need one <repository/> per publication daemon with
- # whom this <self/> has a relationship. In practice there is rarely
- # (never?) a good reason for a single <self/> to use multiple
- # publication services, so in normal use we only need one
- # <repository/> object. If for some reason you really need more
- # than this, you'll have to hack.
+ # At present we need one <repository/> per <parent/>, not because
+ # rpkid requires that, but because pubd does. pubd probably should
+ # be fixed to support a single client allowed to update multiple
+ # trees, but for the moment the easiest way forward is just to
+ # enforce a 1:1 mapping between <parent/> and <repository/> objects
- repository_cert = findbase64(tree, "bpki_repository_certificate")
- if repository_cert:
+ for repository in tree.getiterator("repository"):
+ repository_handle = repository.get("handle")
repository_pdu = repository_pdus.pop(repository_handle, None)
- repository_uri = pubd_base + "client/" + tree.get("repository_handle")
+ repository_uri = repository.get("service_uri")
+ repository_cert = findbase64(repository, "bpki_certificate")
if (repository_pdu is None or
repository_pdu.bsc_handle != bsc_handle or
@@ -344,12 +343,10 @@ for xmlfile in xmlfiles:
rpkid_query.extend(rpki.left_right.repository_elt.make_pdu(
action = "destroy", self_handle = handle, repository_handle = r) for r in repository_pdus)
- # <parent/> setup code here used to be ridiculously complex. Most
- # of the insanity was due to a misguided attempt to deduce pubd
- # setup from other data; now that pubd setup is driven by
- # pubclients.csv, parent setup should be relatively straightforward,
- # but beware of lingering excessive cleverness in anything dealing
- # with parent objects in this script.
+ # <parent/> setup code currently assumes 1:1 mapping between
+ # <repository/> and <parent/>, and further assumes that the handles
+ # for an associated pair are the identical (that is:
+ # parent.repository_handle == parent.parent_handle).
for parent in tree.getiterator("parent"):
@@ -363,7 +360,7 @@ for xmlfile in xmlfiles:
if (parent_pdu is None or
parent_pdu.bsc_handle != bsc_handle or
- parent_pdu.repository_handle != repository_handle or
+ parent_pdu.repository_handle != parent_handle or
parent_pdu.peer_contact_uri != parent_uri or
parent_pdu.sia_base != parent_sia_base or
parent_pdu.sender_name != parent_myhandle or
@@ -376,7 +373,7 @@ for xmlfile in xmlfiles:
self_handle = handle,
parent_handle = parent_handle,
bsc_handle = bsc_handle,
- repository_handle = repository_handle,
+ repository_handle = parent_handle,
peer_contact_uri = parent_uri,
sia_base = parent_sia_base,
sender_name = parent_myhandle,
diff --git a/myrpki.rototill/myrpki.py b/myrpki.rototill/myrpki.py
index 85546663..5ffbd963 100644
--- a/myrpki.rototill/myrpki.py
+++ b/myrpki.rototill/myrpki.py
@@ -60,7 +60,7 @@ except ImportError:
# Our XML namespace and protocol version.
namespace = "http://www.hactrn.net/uris/rpki/myrpki/"
-version = "1"
+version = "2"
namespaceQName = "{" + namespace + "}"
# Dialect for our use of CSV files, here to make it easy to change if
@@ -374,9 +374,9 @@ class parents(dict):
c.xml(e)
@classmethod
- def from_csv(cls, parents_csv_file, fxcert, entitydb):
+ def from_csv(cls, fxcert, entitydb):
"""
- Parse parent data from CSV file.
+ Parse parent data from entitydb.
"""
self = cls()
for f in entitydb.iterate("parents", "*.xml"):
@@ -393,6 +393,83 @@ class parents(dict):
sia_base = r.get("sia_base"))
return self
+class repository(object):
+ """
+ Representation of one repository entity.
+ """
+
+ def __init__(self, handle):
+ self.handle = handle
+ self.service_uri = None
+ self.bpki_certificate = None
+
+ def __repr__(self):
+ s = "<%s %s" % (self.__class__.__name__, self.handle)
+ if self.service_uri:
+ s += " uri %s" % self.service_uri
+ if self.bpki_certificate:
+ s += " cert %s" % self.bpki_certificate
+ return s + ">"
+
+ def add(self, service_uri = None, bpki_certificate = None):
+ """
+ Add service URI or BPKI certificates to this repository object.
+ """
+ if service_uri is not None:
+ self.service_uri = service_uri
+ if bpki_certificate is not None:
+ self.bpki_certificate = bpki_certificate
+
+ def xml(self, e):
+ """
+ Render this repository object to XML.
+ """
+ complete = self.bpki_certificate and self.service_uri
+ if whine and not complete:
+ print "Incomplete repository entry %s" % self
+ if complete or allow_incomplete:
+ e = SubElement(e, "repository",
+ handle = self.handle,
+ service_uri = self.service_uri)
+ e.tail = "\n"
+ if self.bpki_certificate:
+ PEMElement(e, "bpki_certificate", self.bpki_certificate)
+
+class repositories(dict):
+ """
+ Database of repository objects.
+ """
+
+ def add(self, handle,
+ service_uri = None,
+ bpki_certificate = None):
+ """
+ Add service URI or certificate to repository object, creating it if necessary.
+ """
+ if handle not in self:
+ self[handle] = repository(handle)
+ self[handle].add(service_uri = service_uri,
+ bpki_certificate = bpki_certificate)
+
+ def xml(self, e):
+ for c in self.itervalues():
+ c.xml(e)
+
+ @classmethod
+ def from_csv(cls, fxcert, entitydb):
+ """
+ Parse repository data from entitydb.
+ """
+ self = cls()
+ for f in entitydb.iterate("repositories", "*.xml"):
+ h = os.path.splitext(os.path.split(f)[-1])[0]
+ r = etree_read(f)
+ assert r.get("type") == "confirmed"
+ self.add(handle = h,
+ service_uri = r.get("service_uri"),
+ bpki_certificate = fxcert(r.findtext("bpki_server_ta")))
+ return self
+
def csv_open(filename):
"""
Open a CSV file, with settings that make it a tab-delimited file.
@@ -611,14 +688,21 @@ class CA(object):
return xcert
def etree_validate(e):
- try:
- import schema
- schema.myrpki.assertValid(e)
- except lxml.etree.DocumentInvalid:
- print lxml.etree.tostring(e, pretty_print = True)
- raise
- except ImportError:
- print "Couldn't import RelaxNG schema, validation disabled"
+ # This is a kludge, schema should be loaded as module or configured
+ # in .conf, but it will do as a temporary debugging hack.
+ schema = os.getenv("MYRPKI_RNG")
+ if schema:
+ try:
+ import lxml.etree
+ except ImportError:
+ return
+ try:
+ lxml.etree.RelaxNG(file = schema).assertValid(e)
+ except lxml.etree.RelaxNGParseError:
+ return
+ except lxml.etree.DocumentInvalid:
+ print lxml.etree.tostring(e, pretty_print = True)
+ raise
def etree_write(e, filename, verbose = True, validate = False):
"""
@@ -680,13 +764,10 @@ def main(argv = ()):
my_handle = cfg.get("handle")
roa_csv_file = cfg.get("roa_csv")
children_csv_file = cfg.get("children_csv")
- parents_csv_file = cfg.get("parents_csv")
prefix_csv_file = cfg.get("prefix_csv")
asn_csv_file = cfg.get("asn_csv")
bpki_dir = cfg.get("bpki_resources_directory")
xml_filename = cfg.get("xml_filename")
- repository_bpki_certificate = cfg.get("repository_bpki_certificate")
- repository_handle = cfg.get("repository_handle")
global openssl
openssl = cfg.get("openssl", "openssl")
@@ -700,7 +781,7 @@ def main(argv = ()):
except IOError:
bsc_req, bsc_cer = None, None
- e = Element("myrpki", handle = my_handle, repository_handle = repository_handle)
+ e = Element("myrpki", handle = my_handle)
roa_requests.from_csv(roa_csv_file).xml(e)
@@ -711,17 +792,13 @@ def main(argv = ()):
fxcert = bpki.fxcert,
entitydb = entitydb).xml(e)
- parents.from_csv(
- parents_csv_file = parents_csv_file,
- fxcert = bpki.fxcert,
- entitydb = entitydb).xml(e)
+ parents.from_csv(fxcert = bpki.fxcert,entitydb = entitydb).xml(e)
+
+ repositories.from_csv(fxcert = bpki.fxcert,entitydb = entitydb).xml(e)
PEMElement(e, "bpki_ca_certificate", bpki.cer)
PEMElement(e, "bpki_crl", bpki.crl)
- if os.path.exists(repository_bpki_certificate):
- PEMElement(e, "bpki_repository_certificate", bpki.xcert(repository_bpki_certificate))
-
if bsc_cer:
PEMElement(e, "bpki_bsc_certificate", bsc_cer)
diff --git a/myrpki.rototill/schema.rnc b/myrpki.rototill/myrpki.rnc
index 8ec48195..29db7a67 100644
--- a/myrpki.rototill/schema.rnc
+++ b/myrpki.rototill/myrpki.rnc
@@ -16,15 +16,14 @@ ipv4_list = xsd:string { maxLength="512000" pattern="[\-,0-9/.]*" }
ipv6_list = xsd:string { maxLength="512000" pattern="[\-,0-9/:a-fA-F]*" }
start = element myrpki {
- attribute version { xsd:positiveInteger { maxInclusive="1" } },
+ attribute version { "2" },
attribute handle { object_handle },
- attribute repository_handle { pubd_handle },
roa_request_elt*,
child_elt*,
parent_elt*,
+ repository_elt*,
bpki_ca_certificate_elt?,
bpki_crl_elt?,
- bpki_repository_certificate_elt?,
bpki_bsc_certificate_elt?,
bpki_bsc_pkcs10_elt?
}
@@ -53,9 +52,15 @@ parent_elt = element parent {
element bpki_https_certificate { base64 }?
}
+repository_elt = element repository {
+ attribute handle { object_handle },
+ attribute service_uri { uri }?,
+ element bpki_certificate { base64 }?
+}
+
bpki_ca_certificate_elt = element bpki_ca_certificate { base64 }
bpki_crl_elt = element bpki_crl { base64 }
-bpki_repository_certificate_elt = element bpki_repository_certificate { base64 }
+
bpki_bsc_certificate_elt = element bpki_bsc_certificate { base64 }
bpki_bsc_pkcs10_elt = element bpki_bsc_pkcs10 { base64 }
diff --git a/myrpki.rototill/schema.rng b/myrpki.rototill/myrpki.rng
index 0d71e0b7..0ed4123a 100644
--- a/myrpki.rototill/schema.rng
+++ b/myrpki.rototill/myrpki.rng
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- $Id: schema.rnc 2958 2010-01-22 21:55:09Z sra $
+ $Id: myrpki.rnc -1 $
RelaxNG Schema for MyRPKI XML messages
@@ -51,16 +51,11 @@
<start>
<element name="myrpki">
<attribute name="version">
- <data type="positiveInteger">
- <param name="maxInclusive">1</param>
- </data>
+ <value>2</value>
</attribute>
<attribute name="handle">
<ref name="object_handle"/>
</attribute>
- <attribute name="repository_handle">
- <ref name="pubd_handle"/>
- </attribute>
<zeroOrMore>
<ref name="roa_request_elt"/>
</zeroOrMore>
@@ -70,6 +65,9 @@
<zeroOrMore>
<ref name="parent_elt"/>
</zeroOrMore>
+ <zeroOrMore>
+ <ref name="repository_elt"/>
+ </zeroOrMore>
<optional>
<ref name="bpki_ca_certificate_elt"/>
</optional>
@@ -77,9 +75,6 @@
<ref name="bpki_crl_elt"/>
</optional>
<optional>
- <ref name="bpki_repository_certificate_elt"/>
- </optional>
- <optional>
<ref name="bpki_bsc_certificate_elt"/>
</optional>
<optional>
@@ -164,6 +159,23 @@
</optional>
</element>
</define>
+ <define name="repository_elt">
+ <element name="repository">
+ <attribute name="handle">
+ <ref name="object_handle"/>
+ </attribute>
+ <optional>
+ <attribute name="service_uri">
+ <ref name="uri"/>
+ </attribute>
+ </optional>
+ <optional>
+ <element name="bpki_certificate">
+ <ref name="base64"/>
+ </element>
+ </optional>
+ </element>
+ </define>
<define name="bpki_ca_certificate_elt">
<element name="bpki_ca_certificate">
<ref name="base64"/>
@@ -174,11 +186,6 @@
<ref name="base64"/>
</element>
</define>
- <define name="bpki_repository_certificate_elt">
- <element name="bpki_repository_certificate">
- <ref name="base64"/>
- </element>
- </define>
<define name="bpki_bsc_certificate_elt">
<element name="bpki_bsc_certificate">
<ref name="base64"/>
diff --git a/myrpki.rototill/schema.py b/myrpki.rototill/schema.py
deleted file mode 100644
index 651f1938..00000000
--- a/myrpki.rototill/schema.py
+++ /dev/null
@@ -1,199 +0,0 @@
-import lxml.etree
-myrpki = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" encoding="UTF-8"?>
-<!--
- $Id: schema.rnc 2958 2010-01-22 21:55:09Z sra $
-
- RelaxNG Schema for MyRPKI XML messages
-
- libxml2 (including xmllint) only groks the XML syntax of RelaxNG, so
- run the compact syntax through trang to get XML syntax.
--->
-<grammar ns="http://www.hactrn.net/uris/rpki/myrpki/" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
- <define name="base64">
- <data type="base64Binary">
- <param name="maxLength">512000</param>
- </data>
- </define>
- <define name="object_handle">
- <data type="string">
- <param name="maxLength">255</param>
- <param name="pattern">[\-_A-Za-z0-9]*</param>
- </data>
- </define>
- <define name="pubd_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="asn_list">
- <data type="string">
- <param name="maxLength">512000</param>
- <param name="pattern">[\-,0-9]*</param>
- </data>
- </define>
- <define name="ipv4_list">
- <data type="string">
- <param name="maxLength">512000</param>
- <param name="pattern">[\-,0-9/.]*</param>
- </data>
- </define>
- <define name="ipv6_list">
- <data type="string">
- <param name="maxLength">512000</param>
- <param name="pattern">[\-,0-9/:a-fA-F]*</param>
- </data>
- </define>
- <start>
- <element name="myrpki">
- <attribute name="version">
- <data type="positiveInteger">
- <param name="maxInclusive">1</param>
- </data>
- </attribute>
- <attribute name="handle">
- <ref name="object_handle"/>
- </attribute>
- <attribute name="repository_handle">
- <ref name="pubd_handle"/>
- </attribute>
- <zeroOrMore>
- <ref name="roa_request_elt"/>
- </zeroOrMore>
- <zeroOrMore>
- <ref name="child_elt"/>
- </zeroOrMore>
- <zeroOrMore>
- <ref name="parent_elt"/>
- </zeroOrMore>
- <optional>
- <ref name="bpki_ca_certificate_elt"/>
- </optional>
- <optional>
- <ref name="bpki_crl_elt"/>
- </optional>
- <optional>
- <ref name="bpki_repository_certificate_elt"/>
- </optional>
- <optional>
- <ref name="bpki_bsc_certificate_elt"/>
- </optional>
- <optional>
- <ref name="bpki_bsc_pkcs10_elt"/>
- </optional>
- </element>
- </start>
- <define name="roa_request_elt">
- <element name="roa_request">
- <attribute name="asn">
- <data type="positiveInteger"/>
- </attribute>
- <attribute name="v4">
- <ref name="ipv4_list"/>
- </attribute>
- <attribute name="v6">
- <ref name="ipv6_list"/>
- </attribute>
- </element>
- </define>
- <define name="child_elt">
- <element name="child">
- <attribute name="handle">
- <ref name="object_handle"/>
- </attribute>
- <attribute name="valid_until">
- <data type="dateTime">
- <param name="pattern">.*Z</param>
- </data>
- </attribute>
- <optional>
- <attribute name="asns">
- <ref name="asn_list"/>
- </attribute>
- </optional>
- <optional>
- <attribute name="v4">
- <ref name="ipv4_list"/>
- </attribute>
- </optional>
- <optional>
- <attribute name="v6">
- <ref name="ipv6_list"/>
- </attribute>
- </optional>
- <optional>
- <element name="bpki_certificate">
- <ref name="base64"/>
- </element>
- </optional>
- </element>
- </define>
- <define name="parent_elt">
- <element name="parent">
- <attribute name="handle">
- <ref name="object_handle"/>
- </attribute>
- <optional>
- <attribute name="service_uri">
- <ref name="uri"/>
- </attribute>
- </optional>
- <optional>
- <attribute name="myhandle">
- <ref name="object_handle"/>
- </attribute>
- </optional>
- <optional>
- <attribute name="sia_base">
- <ref name="uri"/>
- </attribute>
- </optional>
- <optional>
- <element name="bpki_cms_certificate">
- <ref name="base64"/>
- </element>
- </optional>
- <optional>
- <element name="bpki_https_certificate">
- <ref name="base64"/>
- </element>
- </optional>
- </element>
- </define>
- <define name="bpki_ca_certificate_elt">
- <element name="bpki_ca_certificate">
- <ref name="base64"/>
- </element>
- </define>
- <define name="bpki_crl_elt">
- <element name="bpki_crl">
- <ref name="base64"/>
- </element>
- </define>
- <define name="bpki_repository_certificate_elt">
- <element name="bpki_repository_certificate">
- <ref name="base64"/>
- </element>
- </define>
- <define name="bpki_bsc_certificate_elt">
- <element name="bpki_bsc_certificate">
- <ref name="base64"/>
- </element>
- </define>
- <define name="bpki_bsc_pkcs10_elt">
- <element name="bpki_bsc_pkcs10">
- <ref name="base64"/>
- </element>
- </define>
-</grammar>
-<!--
- Local Variables:
- indent-tabs-mode: nil
- End:
--->
-'''))
diff --git a/myrpki.rototill/xml-parse-test.py b/myrpki.rototill/xml-parse-test.py
index d5f8e007..e32241ed 100644
--- a/myrpki.rototill/xml-parse-test.py
+++ b/myrpki.rototill/xml-parse-test.py
@@ -19,14 +19,15 @@ PERFORMANCE OF THIS SOFTWARE.
"""
import lxml.etree, rpki.resource_set, base64, subprocess
-import schema
+
+relaxng = lxml.etree.RelaxNG(file = "myrpki.rng")
tree = lxml.etree.parse("myrpki.xml").getroot()
if False:
print lxml.etree.tostring(tree, pretty_print = True, encoding = "us-ascii", xml_declaration = True)
-schema.myrpki.assertValid(tree)
+relaxng.assertValid(tree)
def showitems(x):
if False:
diff --git a/myrpki.rototill/yamltest.py b/myrpki.rototill/yamltest.py
index e909053d..7fb7b169 100644
--- a/myrpki.rototill/yamltest.py
+++ b/myrpki.rototill/yamltest.py
@@ -415,8 +415,6 @@ class allocation(object):
s = self.find_pubd()
r["myrpki", "pubd_server_host"] = "localhost"
r["myrpki", "pubd_server_port"] = str(s.pubd_port)
- r["myrpki", "repository_bpki_certificate"] = s.path("bpki/servers/ca.cer")
- r["myrpki", "repository_handle"] = self.client_handle
r["myrpki", "publication_rsync_server"] = "localhost:%s" % s.rsync_port
if rpkid_password: