aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/apnic-to-csv.py49
-rw-r--r--scripts/arin-to-csv.py121
-rw-r--r--scripts/convert-from-csv-to-entitydb.py233
-rw-r--r--scripts/ripe-asns-to-csv.py106
-rw-r--r--scripts/ripe-prefixes-to-csv.awk43
-rw-r--r--scripts/test-myrpki-cms.py66
-rw-r--r--scripts/testbed-rootcert.py65
-rw-r--r--scripts/translate-handles.py49
-rwxr-xr-xscripts/verify-bpki.sh43
9 files changed, 775 insertions, 0 deletions
diff --git a/scripts/apnic-to-csv.py b/scripts/apnic-to-csv.py
new file mode 100644
index 00000000..54e9137c
--- /dev/null
+++ b/scripts/apnic-to-csv.py
@@ -0,0 +1,49 @@
+"""
+Parse APNIC "Extended Allocation and Assignment" reports and write
+out (just) the RPKI-relevant fields in myrpki-format CSV syntax.
+
+$Id$
+
+Copyright (C) 2010 Internet Systems Consortium ("ISC")
+
+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 ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL ISC 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 csv, myrpki, rpki.ipaddrs
+
+translations = dict((src, dst) for src, dst in myrpki.csv_reader("translations.csv", columns = 2))
+
+asns = myrpki.csv_writer("asns.csv")
+prefixes = myrpki.csv_writer("prefixes.csv")
+
+for line in open("delegated-apnic-extended-latest"):
+
+ line = line.rstrip()
+
+ if not line.startswith("apnic|") or line.endswith("|summary"):
+ continue
+
+ registry, cc, rectype, start, value, date, status, opaque_id = line.split("|")
+
+ assert registry == "apnic"
+
+ opaque_id = translations.get(opaque_id, opaque_id)
+
+ if rectype == "asn":
+ asns.writerow((opaque_id, "%s-%s" % (start, int(start) + int(value) - 1)))
+
+ elif rectype == "ipv4":
+ prefixes.writerow((opaque_id, "%s-%s" % (start, rpki.ipaddrs.v4addr(rpki.ipaddrs.v4addr(start) + long(value) - 1))))
+
+ elif rectype == "ipv6":
+ prefixes.writerow((opaque_id, "%s/%s" % (start, value)))
diff --git a/scripts/arin-to-csv.py b/scripts/arin-to-csv.py
new file mode 100644
index 00000000..55e5762a
--- /dev/null
+++ b/scripts/arin-to-csv.py
@@ -0,0 +1,121 @@
+"""
+Parse a WHOIS research dump and write out (just) the RPKI-relevant
+fields in myrpki-format CSV syntax.
+
+NB: The input data for this script comes from ARIN under an agreement
+that allows research use but forbids redistribution, so if you think
+you need a copy of the data, please talk to ARIN about it, not us.
+
+$Id$
+
+Copyright (C) 2009 Internet Systems Consortium ("ISC")
+
+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 ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL ISC 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 gzip, csv, myrpki
+
+class Handle(object):
+
+ want_tags = ()
+
+ debug = False
+
+ def set(self, tag, val):
+ if tag in self.want_tags:
+ setattr(self, tag, "".join(val.split(" ")))
+
+ def check(self):
+ for tag in self.want_tags:
+ if not hasattr(self, tag):
+ return False
+ if self.debug:
+ print repr(self)
+ return True
+
+class ASHandle(Handle):
+
+ want_tags = ("ASHandle", "ASNumber", "OrgID")
+
+ def __repr__(self):
+ return "<%s %s.%s %s>" % (self.__class__.__name__,
+ self.OrgID, self.ASHandle, self.ASNumber)
+
+ def finish(self, ctx):
+ if self.check():
+ ctx.asns.writerow((ctx.translations.get(self.OrgID, self.OrgID), self.ASNumber))
+
+class NetHandle(Handle):
+
+ NetType = None
+
+ want_tags = ("NetHandle", "NetRange", "NetType", "OrgID")
+
+ def finish(self, ctx):
+ if self.NetType in ("allocation", "assignment") and self.check():
+ ctx.prefixes.writerow((ctx.translations.get(self.OrgID, self.OrgID), self.NetRange))
+
+ def __repr__(self):
+ return "<%s %s.%s %s %s>" % (self.__class__.__name__,
+ self.OrgID, self.NetHandle,
+ self.NetType, self.NetRange)
+
+class V6NetHandle(NetHandle):
+
+ want_tags = ("V6NetHandle", "NetRange", "NetType", "OrgID")
+
+ def __repr__(self):
+ return "<%s %s.%s %s %s>" % (self.__class__.__name__,
+ ctx.translations.get(self.OrgID, self.OrgID),
+ self.V6NetHandle, self.NetType, self.NetRange)
+
+class main(object):
+
+ types = {
+ "ASHandle" : ASHandle,
+ "NetHandle" : NetHandle,
+ "V6NetHandle" : V6NetHandle }
+
+ translations = {}
+
+ @staticmethod
+ def parseline(line):
+ tag, sep, val = line.partition(":")
+ assert sep, "Couldn't find separator in %r" % line
+ return tag.strip(), val.strip()
+
+ def __init__(self):
+ self.asns = myrpki.csv_writer("asns.csv")
+ self.prefixes = myrpki.csv_writer("prefixes.csv")
+ try:
+ self.translations = dict((src, dst) for src, dst in myrpki.csv_reader("translations.csv", columns = 2))
+ except IOError:
+ pass
+ f = gzip.open("arin_db.txt.gz")
+ cur = None
+ for line in f:
+ line = line.expandtabs().strip()
+ if not line:
+ if cur:
+ cur.finish(self)
+ cur = None
+ elif not line.startswith("#"):
+ tag, val = self.parseline(line)
+ if cur is None:
+ cur = self.types[tag]() if tag in self.types else False
+ if cur:
+ cur.set(tag, val)
+ if cur:
+ cur.finish(self)
+
+main()
diff --git a/scripts/convert-from-csv-to-entitydb.py b/scripts/convert-from-csv-to-entitydb.py
new file mode 100644
index 00000000..282d2e75
--- /dev/null
+++ b/scripts/convert-from-csv-to-entitydb.py
@@ -0,0 +1,233 @@
+"""
+Convert {parents,children,pubclients}.csv into new XML formats.
+
+$Id$
+
+Copyright (C) 2010 Internet Systems Consortium ("ISC")
+
+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 ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL ISC 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 subprocess, csv, re, os, getopt, sys, base64, urlparse
+import rpki.sundial, myrpki, rpki.config
+
+from lxml.etree import Element, SubElement, ElementTree
+
+section_regexp = re.compile("\s*\[\s*(.+?)\s*\]\s*$")
+variable_regexp = re.compile("\s*([-a-zA-Z0-9_]+)(\s*=\s*)(.+?)\s*$")
+
+cfg_file = "myrpki.conf"
+template_file = os.path.join(os.path.dirname(sys.argv[0]), "examples", "myrpki.conf")
+new_cfg_file = None
+preserve_valid_until = False
+
+opts, argv = getopt.getopt(sys.argv[1:], "c:hn:pt:?", ["config=", "new_config=", "preserve_valid_until", "template_config=", "help"])
+for o, a in opts:
+ if o in ("-h", "--help", "-?"):
+ print __doc__
+ sys.exit(0)
+ elif o in ("-c", "--config"):
+ cfg_file = a
+ elif o in ("-n", "--new_config"):
+ new_cfg_file = a
+ elif o in ("-p", "--preserve_valid_until"):
+ preserve_valid_until = True
+ elif o in ("-t", "--template_config"):
+ template_file = a
+if argv:
+ raise RuntimeError, "Unexpected arguments %r" % (argv,)
+if os.path.samefile(cfg_file, template_file):
+ raise RuntimeError, "Old config and template for new config can't be the same file"
+if new_cfg_file is None:
+ new_cfg_file = cfg_file + ".new"
+if os.path.exists(new_cfg_file):
+ raise RuntimeError, "%s already exists, NOT overwriting" % new_cfg_file
+
+cfg = rpki.config.parser(cfg_file)
+
+# These have no counterparts in new config file, just read them from old
+
+repository_bpki_certificate = cfg.get(option = "repository_bpki_certificate", section = "myrpki")
+repository_handle = cfg.get(option = "repository_handle", section = "myrpki")
+parents_csv = cfg.get(option = "parents_csv", section = "myrpki", default = "parents.csv")
+children_csv = cfg.get(option = "children_csv", section = "myrpki", default = "children.csv")
+pubclients_csv = cfg.get(option = "pubclients_csv", section = "myrpki", default = "pubclients.csv")
+pubd_base = cfg.get(option = "pubd_base", section = "myirbe")
+
+# Here we need to construct values for the new config file from the
+# old one. Basic model here is to look at whatever variables need to
+# be set in the template (mostly just the [myrpki], I hope), pull
+# necessary data from old config file any way we can. Stuff that
+# didn't make the jump from old config file to new we can just ignore,
+# stuff that is automated via macro expansions in the new config file
+# should be ok without modification.
+
+r = {}
+
+if cfg.has_section("myrpki"):
+ for i in ("handle", "roa_csv", "prefix_csv", "asn_csv", "xml_filename"):
+ r["myrpki", i] = cfg.get(section = "myrpki", option = i)
+ r["myrpki", "bpki_resources_directory"] = cfg.get(option = "bpki_directory", section = "myrpki")
+
+if cfg.has_section("myirbe"):
+ r["myrpki", "bpki_servers_directory"] = cfg.get(option = "bpki_directory", section = "myirbe")
+ r["myrpki", "run_rpkid"] = True
+ r["myrpki", "run_pubd"] = cfg.getboolean(option = "want_pubd", section = "myirbe", default = False)
+ r["myrpki", "run_rootd"] = cfg.getboolean(option = "want_rootd", section = "myirbe", default = False)
+else:
+ for i in ("run_rpkid", "run_pubd", "run_rootd"):
+ r["myrpki", i] = False
+
+if cfg.has_section("rpkid"):
+ r["myrpki", "rpkid_server_host"] = cfg.get(option = "server-host", section = "rpkid")
+ r["myrpki", "rpkid_server_port"] = cfg.get(option = "server-port", section = "rpkid")
+
+if cfg.has_section("irdbd"):
+ u = urlparse.urlparse(cfg.get(option = "https-url", section = "irdbd"))
+ r["myrpki", "irdbd_server_host"] = u.hostname or "localhost"
+ r["myrpki", "irdbd_server_port"] = u.port or 443
+
+if cfg.has_section("pubd"):
+ r["myrpki", "pubd_server_host"] = cfg.get(option = "server-host", section = "pubd")
+ r["myrpki", "pubd_server_port"] = cfg.get(option = "server-port", section = "pubd")
+ r["myrpki", "publication_base_directory"] = cfg.get(option = "publication-base", section = "pubd")
+
+if cfg.has_section("rootd"):
+ r["myrpki", "rootd_server_port"] = cfg.get(option = "server-port", section = "rootd")
+ u = urlparse.urlparse(cfg.get(option = "rpki-base-uri", section = "rootd"))
+ r["myrpki", "publication_rsync_server"] = u.netloc
+
+for i in ("rpkid", "irdbd", "pubd"):
+ if cfg.has_section(i):
+ for j in ("sql-database", "sql-username", "sql-password"):
+ r[i, j] = cfg.get(section = i, option = j)
+
+f = open(new_cfg_file, "w")
+f.write("# Automatically converted from %s using %s as a template.\n\n" % (cfg_file, template_file))
+section = None
+for line in open(template_file):
+ m = section_regexp.match(line)
+ if m:
+ section = m.group(1)
+ m = variable_regexp.match(line)
+ if m:
+ option, whitespace = m.group(1, 2)
+ else:
+ option = None
+ if (section, option) in r:
+ line = "%s%s%s\n" % (option, whitespace, r[section, option])
+ f.write(line)
+f.close()
+print "Wrote", new_cfg_file
+
+# Get all of these from the new config file; in theory we just set all
+# of them, but we want to use values matching new config in any case.
+
+newcfg = rpki.config.parser(new_cfg_file, "myrpki")
+
+handle = newcfg.get("handle")
+bpki_resources_directory = newcfg.get("bpki_resources_directory")
+bpki_servers_directory = newcfg.get("bpki_servers_directory")
+pubd_server_host = newcfg.get("pubd_server_host")
+pubd_server_port = newcfg.get("pubd_server_port")
+rpkid_server_host = newcfg.get("rpkid_server_host")
+rpkid_server_port = newcfg.get("rpkid_server_port")
+entitydb_dir = newcfg.get("entitydb_dir", "entitydb")
+
+bpki_resources_pemfile = bpki_resources_directory + "/ca.cer"
+bpki_servers_pemfile = bpki_servers_directory + "/ca.cer"
+
+def entitydb(*args):
+ return os.path.join(entitydb_dir, *args)
+
+# Now convert the .csv files. It'd be nice to have XML validation
+# enabled for this, so try to turn it on ourselves if the magic
+# environment variable hasn't already been set.
+
+rng_file = os.path.join(os.path.dirname(sys.argv[0]), "myrpki.rng")
+if not os.getenv("MYRPKI_RNG") and os.path.exists(rng_file):
+ os.putenv("MYRPKI_RNG", rng_file)
+
+for d in map(entitydb, ("children", "parents", "repositories", "pubclients")):
+ if not os.path.exists(d):
+ os.makedirs(d)
+
+one_year_from_now = str(rpki.sundial.now() + rpki.sundial.timedelta(days = 365))
+
+if os.path.exists(children_csv):
+ for child_handle, valid_until, child_resource_pemfile in myrpki.csv_reader(children_csv, columns = 3):
+ try:
+
+ e = Element("parent",
+ valid_until = valid_until if preserve_valid_until else one_year_from_now,
+ service_uri = "https://%s:%s/up-down/%s/%s" % (rpkid_server_host, rpkid_server_port, handle, child_handle),
+ child_handle = child_handle,
+ parent_handle = handle)
+ myrpki.PEMElement(e, "bpki_resource_ta", bpki_resources_pemfile)
+ myrpki.PEMElement(e, "bpki_server_ta", bpki_servers_pemfile)
+ myrpki.PEMElement(e, "bpki_child_ta", child_resource_pemfile)
+ myrpki.etree_write(e, entitydb("children", "%s.xml" % child_handle))
+
+ except IOError:
+ pass
+
+if os.path.exists(parents_csv):
+ for parent_handle, parent_service_uri, parent_cms_pemfile, parent_https_pemfile, parent_myhandle, parent_sia_base in myrpki.csv_reader(parents_csv, columns = 6):
+ try:
+
+ e = Element("parent",
+ valid_until = one_year_from_now,
+ service_uri = parent_service_uri,
+ child_handle = parent_myhandle,
+ parent_handle = parent_handle)
+ myrpki.PEMElement(e, "bpki_resource_ta", parent_cms_pemfile)
+ myrpki.PEMElement(e, "bpki_server_ta", parent_https_pemfile)
+ myrpki.PEMElement(e, "bpki_child_ta", bpki_resources_pemfile)
+ myrpki.etree_write(e, entitydb("parents", "%s.xml" % parent_handle))
+
+ client_handle = "/".join(parent_sia_base.rstrip("/").split("/")[3:])
+ assert client_handle.startswith(repository_handle)
+
+ e = Element("repository",
+ parent_handle = parent_handle,
+ client_handle = client_handle,
+ service_uri = "%s/client/%s" % (pubd_base.rstrip("/"), client_handle),
+ sia_base = parent_sia_base,
+ type = "confirmed")
+ myrpki.PEMElement(e, "bpki_server_ta", repository_bpki_certificate)
+ myrpki.PEMElement(e, "bpki_client_ta", bpki_resources_pemfile)
+ SubElement(e, "contact_info").text = "Automatically generated by convert-csv.py"
+ myrpki.etree_write(e, entitydb("repositories", "%s.xml" % parent_handle))
+
+ except IOError:
+ pass
+
+if os.path.exists(pubclients_csv):
+ for client_handle, client_resource_pemfile, client_sia_base in myrpki.csv_reader(pubclients_csv, columns = 3):
+ try:
+
+ parent_handle = client_handle.split("/")[-2] if "/" in client_handle else handle
+
+ e = Element("repository",
+ parent_handle = parent_handle,
+ client_handle = client_handle,
+ service_uri = "https://%s:%s/client/%s" % (pubd_server_host, pubd_server_port, client_handle),
+ sia_base = client_sia_base,
+ type = "confirmed")
+ myrpki.PEMElement(e, "bpki_server_ta", bpki_servers_pemfile)
+ myrpki.PEMElement(e, "bpki_client_ta", client_resource_pemfile)
+ SubElement(e, "contact_info").text = "Automatically generated by convert-csv.py"
+ myrpki.etree_write(e, entitydb("pubclients", "%s.xml" % client_handle.replace("/", ".")))
+
+ except IOError:
+ pass
diff --git a/scripts/ripe-asns-to-csv.py b/scripts/ripe-asns-to-csv.py
new file mode 100644
index 00000000..04a92627
--- /dev/null
+++ b/scripts/ripe-asns-to-csv.py
@@ -0,0 +1,106 @@
+"""
+Parse a WHOIS research dump and write out (just) the RPKI-relevant
+fields in myrpki-format CSV syntax.
+
+NB: The input data for this script is publicly available via FTP, but
+you'll have to fetch the data from RIPE yourself, and be sure to see
+the terms and conditions referenced by the data file header comments.
+
+$Id$
+
+Copyright (C) 2009 Internet Systems Consortium ("ISC")
+
+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 ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL ISC 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 gzip, csv, myrpki
+
+class Handle(dict):
+
+ want_tags = ()
+
+ debug = False
+
+ def set(self, tag, val):
+ if tag in self.want_tags:
+ self[tag] = "".join(val.split(" "))
+
+ def check(self):
+ for tag in self.want_tags:
+ if not tag in self:
+ return False
+ if self.debug:
+ self.log()
+ return True
+
+ def __repr__(self):
+ return "<%s %s>" % (self.__class__.__name__,
+ " ".join("%s:%s" % (tag, self.get(tag, "?"))
+ for tag in self.want_tags))
+
+ def log(self):
+ print repr(self)
+
+ def finish(self, ctx):
+ self.check()
+
+class aut_num(Handle):
+ want_tags = ("aut-num", "mnt-by", "as-name")
+
+ def set(self, tag, val):
+ if tag == "aut-num" and val.startswith("AS"):
+ val = val[2:]
+ Handle.set(self, tag, val)
+
+ def finish(self, ctx):
+ if self.check():
+ ctx.asns.writerow((self["mnt-by"], self["aut-num"]))
+
+class main(object):
+
+ types = dict((x.want_tags[0], x) for x in (aut_num,))
+
+
+ def finish_statement(self, done):
+ if self.statement:
+ tag, sep, val = self.statement.partition(":")
+ assert sep, "Couldn't find separator in %r" % self.statement
+ tag = tag.strip().lower()
+ val = val.strip().upper()
+ if self.cur is None:
+ self.cur = self.types[tag]() if tag in self.types else False
+ if self.cur is not False:
+ self.cur.set(tag, val)
+ if done and self.cur:
+ self.cur.finish(self)
+ self.cur = None
+
+ filenames = ("ripe.db.aut-num.gz",)
+
+ def __init__(self):
+ self.asns = myrpki.csv_writer("asns.csv")
+ for fn in self.filenames:
+ f = gzip.open(fn)
+ self.statement = ""
+ self.cur = None
+ for line in f:
+ line = line.expandtabs().partition("#")[0].rstrip("\n")
+ if line and not line[0].isalpha():
+ self.statement += line[1:] if line[0] == "+" else line
+ else:
+ self.finish_statement(not line)
+ self.statement = line
+ self.finish_statement(True)
+ f.close()
+
+main()
diff --git a/scripts/ripe-prefixes-to-csv.awk b/scripts/ripe-prefixes-to-csv.awk
new file mode 100644
index 00000000..582d5ce7
--- /dev/null
+++ b/scripts/ripe-prefixes-to-csv.awk
@@ -0,0 +1,43 @@
+#!/usr/bin/awk -f
+# $Id$
+
+# ftp -pa ftp://ftp.ripe.net/pub/stats/ripencc/membership/alloclist.txt
+
+BEGIN {
+ translation["ie.google"] = "GoogleIreland";
+}
+
+function done() {
+ if (handle in translation)
+ handle = translation[handle];
+ for (i = 1; i <= n_allocs; i++)
+ print handle "\t" alloc[i];
+ n_allocs = 0;
+}
+
+/^[a-z]/ {
+ done();
+ handle = $0;
+ nr = NR;
+}
+
+NR == nr + 1 {
+ name = $0;
+}
+
+NR > nr + 2 && NF > 1 && $2 !~ /:/ {
+ split($2, a, "/");
+ len = a[2];
+ split(a[1], a, /[.]/);
+ for (i = length(a); i < 4; i++)
+ a[i+1] = 0;
+ alloc[++n_allocs] = sprintf("%d.%d.%d.%d/%d", a[1], a[2], a[3], a[4], len);
+}
+
+NR > nr + 2 && NF > 1 && $2 ~ /:/ {
+ alloc[++n_allocs] = $2;
+}
+
+END {
+ done();
+}
diff --git a/scripts/test-myrpki-cms.py b/scripts/test-myrpki-cms.py
new file mode 100644
index 00000000..29bea39c
--- /dev/null
+++ b/scripts/test-myrpki-cms.py
@@ -0,0 +1,66 @@
+"""
+Scratch pad for working out what CMS referral code looks like.
+
+This is only in subversion for archival and backup, I don't expect
+users to run this, and will delete it in the near future.
+
+
+$Id$
+
+Copyright (C) 2010 Internet Systems Consortium ("ISC")
+
+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 ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL ISC 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 subprocess, os, sys, myrpki
+
+original_xml = '''\
+<publication_referral xmlns="http://www.hactrn.net/uris/rpki/publication-spec/"
+ sia_base=rsync://repository.example/path/to/me/space-i-give-to-my-child">
+ Base64 encoded BPKI TA of resource holding aspect of my child xxx blah blah blah blah xxx
+</publication_referral>
+'''
+
+f = open("original.xml", "w")
+f.write(original_xml)
+f.close()
+
+myrpki.openssl = "/u/sra/rpki/subvert-rpki.hactrn.net/openssl/openssl/apps/openssl"
+os.putenv("OPENSSL_CONF", "/dev/null")
+
+bpki = myrpki.CA("test/Alice/myrpki.conf", "test/Alice/bpki/resources")
+bpki.ee("/CN=Alice Signed Referral CMS Test EE Certificate", "CMSEE")
+
+# "id-ct-xml" from rpki.oids
+oid = ".".join(map(str, (1, 2, 840, 113549, 1, 9, 16, 1, 28)))
+
+format = "DER" # PEM or DER
+
+subprocess.check_call((myrpki.openssl, "cms", "-sign",
+ "-binary", "-nodetach", "-nosmimecap", "-keyid", "-outform", format,
+ "-econtent_type", oid, "-md", "sha256",
+ "-inkey", "test/Alice/bpki/resources/CMSEE.key",
+ "-signer", "test/Alice/bpki/resources/CMSEE.cer",
+ "-in", "original.xml",
+ "-out", "original.%s" % format.lower()))
+
+if format == "DER":
+ subprocess.call(("dumpasn1", "-a", "original.cms"))
+
+# verifying may not be necessary here, that might be pubd's job. or
+# at least we can make it the job of the code formerly known as irdbd,
+# where we have full libraries available to us. but blunder ahead...
+
+subprocess.check_call((myrpki.openssl, "cms", "-verify", "-inform", format,
+ "-CAfile", "test/Alice/bpki/resources/ca.cer",
+ "-in", "original.%s" % format.lower()))
diff --git a/scripts/testbed-rootcert.py b/scripts/testbed-rootcert.py
new file mode 100644
index 00000000..54d1480c
--- /dev/null
+++ b/scripts/testbed-rootcert.py
@@ -0,0 +1,65 @@
+"""
+Generate config for a test RPKI root certificate for resources
+specified in asns.csv and prefixes.csv.
+
+This script is separate from arin-to-csv.py so that we can convert on
+the fly rather than having to pull the entire database into memory.
+
+$Id$
+
+Copyright (C) 2009-2010 Internet Systems Consortium ("ISC")
+
+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 ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL ISC 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 csv, myrpki, sys
+
+if len(sys.argv) != 2:
+ raise RuntimeError, "Usage: %s [holder]" % sys.argv[0]
+
+print '''\
+[req]
+default_bits = 2048
+default_md = sha256
+distinguished_name = req_dn
+prompt = no
+encrypt_key = no
+
+[req_dn]
+CN = Pseudo-%(HOLDER)s testbed root RPKI certificate
+
+[x509v3_extensions]
+basicConstraints = critical,CA:true
+subjectKeyIdentifier = hash
+keyUsage = critical,keyCertSign,cRLSign
+subjectInfoAccess = 1.3.6.1.5.5.7.48.5;URI:rsync://%(holder)s.rpki.net/rpki/%(holder)s/,1.3.6.1.5.5.7.48.10;URI:rsync://%(holder)s.rpki.net/rpki/%(holder)s/root.mnf
+certificatePolicies = critical,1.3.6.1.5.5.7.14.2
+sbgp-autonomousSysNum = critical,@rfc3779_asns
+sbgp-ipAddrBlock = critical,@rfc3997_addrs
+
+[rfc3779_asns]
+''' % { "holder" : sys.argv[1].lower(),
+ "HOLDER" : sys.argv[1].upper() }
+
+for i, asn in enumerate(asn for handle, asn in myrpki.csv_reader("asns.csv", columns = 2)):
+ print "AS.%d = %s" % (i, asn)
+
+print '''\
+
+[rfc3997_addrs]
+
+'''
+
+for i, prefix in enumerate(prefix for handle, prefix in myrpki.csv_reader("prefixes.csv", columns = 2)):
+ v = 6 if ":" in prefix else 4
+ print "IPv%d.%d = %s" % (v, i, prefix)
diff --git a/scripts/translate-handles.py b/scripts/translate-handles.py
new file mode 100644
index 00000000..308b878e
--- /dev/null
+++ b/scripts/translate-handles.py
@@ -0,0 +1,49 @@
+"""
+Translate handles from the ones provided in a database dump into the
+ones we use in our testbed. This has been broken out into a separate
+program for two reasons:
+
+- Conversion of some of the RIR data is a very slow process, and it's
+ both annoying and unnecessary to run it every time we add a new
+ participant to the testbed.
+
+- This handle translation business now has fingers into half a dozen
+ scripts, so it needs refactoring in any case, either as a common
+ library function or as a separate script.
+
+This program takes a list of .CSV files on its command line, and
+rewrites them as needed after performing the translation.
+
+$Id$
+
+Copyright (C) 2010 Internet Systems Consortium ("ISC")
+
+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 ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL ISC 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 os, sys, myrpki
+
+translations = dict((src, dst) for src, dst in myrpki.csv_reader("translations.csv", columns = 2))
+
+for filename in sys.argv[1:]:
+
+ tmpfile = "%s.%d" % os.getpid()
+ csvout = myrpki.csv_writer(tmpfile)
+
+ for cols in myrpki.csv_reader(filename):
+ if cols[0] in translations:
+ cols[0] = translations[cols[0]]
+ csvout(cols)
+
+ del csvout
+ os.rename(tmpfile, filename)
diff --git a/scripts/verify-bpki.sh b/scripts/verify-bpki.sh
new file mode 100755
index 00000000..0e36d796
--- /dev/null
+++ b/scripts/verify-bpki.sh
@@ -0,0 +1,43 @@
+#!/bin/sh -
+# $Id$
+#
+# Copyright (C) 2009-2010 Internet Systems Consortium ("ISC")
+#
+# 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 ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC 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.
+
+# Tests of generated BPKI certificates. Kind of cheesy, but does test
+# the basic stuff.
+
+exec 2>&1
+
+for bpki in bpki/*
+do
+ crls=$(find $bpki -name '*.crl')
+
+ # Check that CRLs verify properly
+ for crl in $crls
+ do
+ echo -n "$crl: "
+ openssl crl -CAfile $bpki/ca.cer -noout -in $crl
+ done
+
+ # Check that issued certificates verify properly
+ cat $bpki/ca.cer $crls | openssl verify -crl_check -CAfile /dev/stdin $(find $bpki -name '*.cer' ! -name 'ca.cer' ! -name '*.cacert.cer')
+
+done
+
+# Check that cross-certified BSC certificates verify properly
+if test -d bpki/servers
+then
+ cat bpki/servers/xcert.*.cer | openssl verify -verbose -CAfile bpki/servers/ca.cer -untrusted /dev/stdin bpki/resources/bsc.*.cer
+fi