aboutsummaryrefslogtreecommitdiff
path: root/rpkid/testbed.py
diff options
context:
space:
mode:
Diffstat (limited to 'rpkid/testbed.py')
-rw-r--r--rpkid/testbed.py179
1 files changed, 103 insertions, 76 deletions
diff --git a/rpkid/testbed.py b/rpkid/testbed.py
index dda8a6c4..40fa1455 100644
--- a/rpkid/testbed.py
+++ b/rpkid/testbed.py
@@ -140,11 +140,11 @@ def main():
rpki.log.info("Reading master YAML configuration")
db = allocation_db(yaml_script.pop(0))
- rpki.log.info("Constructing biz keys and certs for rootd")
- setup_biz_cert_chain(rootd_name, ee = ("RPKI",))
+ rpki.log.info("Constructing BPKI keys and certs for rootd")
+ setup_bpki_cert_chain(rootd_name, ee = ("RPKI",))
for a in db:
- a.setup_biz_certs()
+ a.setup_bpki_certs()
setup_publication()
setup_rootd(db.root.name, "SELF-1")
@@ -175,9 +175,9 @@ def main():
for a in db.engines:
a.create_rpki_objects()
- # Write YAML files for leaves
+ # Setup keys and certs and write YAML files for leaves
for a in db.leaves:
- a.write_leaf_yaml()
+ a.setup_yaml_leaf()
# Loop until we run out of control YAML
while True:
@@ -471,13 +471,16 @@ class allocation(object):
self.rpki_db_name = "rpki%d" % n
self.rpki_port = allocate_port()
- def setup_biz_certs(self):
- """Create business certs for this entity."""
- rpki.log.info("Constructing biz keys and certs for %s" % self.name)
- setup_biz_cert_chain(self.name, ee = ("RPKI", "IRDB", "IRBE"), ca = ("SELF-1",))
- self.rpkid_ta = rpki.x509.X509(PEM_file = self.name + "-TA.cer")
- self.irbe_cer = rpki.x509.X509(PEM_file = self.name + "-IRBE.cer")
- self.irbe_key = rpki.x509.RSA( PEM_file = self.name + "-IRBE.key")
+ def setup_bpki_certs(self):
+ """Create BPKI certificates for this entity."""
+ rpki.log.info("Constructing BPKI keys and certs for %s" % self.name)
+ if self.is_leaf():
+ setup_bpki_cert_chain(self.name, ee = ("RPKI",))
+ else:
+ setup_bpki_cert_chain(self.name, ee = ("RPKI", "IRDB", "IRBE"), ca = ("SELF-1",))
+ self.rpkid_ta = rpki.x509.X509(PEM_file = self.name + "-TA.cer")
+ self.irbe_key = rpki.x509.RSA( PEM_file = self.name + "-IRBE.key")
+ self.irbe_cert = rpki.x509.X509(PEM_file = self.name + "-IRBE.cer")
def setup_conf_file(self):
"""Write config files for this entity."""
@@ -557,13 +560,13 @@ class allocation(object):
rpki.log.info("Calling rpkid for %s" % self.name)
pdu.type = "query"
msg = rpki.left_right.msg((pdu,))
- cms, xml = rpki.left_right.cms_msg.wrap(msg, self.irbe_key, self.irbe_cer, pretty_print = True)
+ cms, xml = rpki.left_right.cms_msg.wrap(msg, self.irbe_key, self.irbe_cert, pretty_print = True)
rpki.log.debug(xml)
url = "https://localhost:%d/left-right" % self.rpki_port
rpki.log.debug("Attempting to connect to %s" % url)
der = rpki.https.client(
client_key = self.irbe_key,
- client_cert = self.irbe_cer,
+ client_cert = self.irbe_cert,
server_ta = self.rpkid_ta,
url = url,
msg = cms)
@@ -573,6 +576,32 @@ class allocation(object):
assert pdu.type == "reply" and not isinstance(pdu, rpki.left_right.report_error_elt)
return pdu
+ def cross_certify(self, certificant):
+ """Cross-certify and return the resulting certificate."""
+
+ if self.is_leaf():
+ certifier = self.name + "-TA"
+ else:
+ certifier = self.name + "-SELF-1"
+ certfile = certifier + "-" + certificant + ".cer"
+ rpki.log.trace()
+ rpki.log.info("Cross certifying %s into %s's BPKI (%s)" % (certificant, certifier, certfile))
+ signer = subprocess.Popen((prog_openssl, "x509", "-req", "-sha256", "-text",
+ "-extensions", "req_x509_ext", "-CAcreateserial",
+ "-in", certificant + ".req",
+ "-out", certfile,
+ "-extfile", certifier + ".conf",
+ "-CA", certifier + ".cer",
+ "-CAkey", certifier + ".key"),
+ stdout = subprocess.PIPE,
+ stderr = subprocess.PIPE)
+ errors = signer.communicate()[1]
+ if signer.returncode != 0:
+ msg = "Couldn't cross-certify %s into %s's BPKI: %s" % (certificant, certifier, errors)
+ rpki.log.error(msg)
+ raise RuntimeError, msg
+ return rpki.x509.X509(Auto_file = certfile)
+
def create_rpki_objects(self):
"""Create RPKI engine objects for this engine.
@@ -619,14 +648,14 @@ class allocation(object):
rpki.log.info("Creating rpkid parent object for %s" % self.name)
if self.is_root():
- rootd_cert = cross_certify(self.name + "-SELF-1", rootd_name + "-TA")
+ rootd_cert = self.cross_certify(rootd_name + "-TA")
self.parent_id = self.call_rpkid(rpki.left_right.parent_elt.make_pdu(
action = "create", self_id = self.self_id, bsc_id = self.bsc_id, repository_id = self.repository_id, sia_base = self.sia_base,
bpki_cms_cert = rootd_cert, bpki_https_cert = rootd_cert, sender_name = self.name, recipient_name = "Walrus",
peer_contact_uri = "https://localhost:%s/" % rootd_port)).parent_id
else:
- parent_cms_cert = cross_certify(self.name + "-SELF-1", self.parent.name + "-SELF-1")
- parent_https_cert = cross_certify(self.name + "-SELF-1", self.parent.name + "-TA")
+ parent_cms_cert = self.cross_certify(self.parent.name + "-SELF-1")
+ parent_https_cert = self.cross_certify(self.parent.name + "-TA")
self.parent_id = self.call_rpkid(rpki.left_right.parent_elt.make_pdu(
action = "create", self_id = self.self_id, bsc_id = self.bsc_id, repository_id = self.repository_id, sia_base = self.sia_base,
bpki_cms_cert = parent_cms_cert, bpki_https_cert = parent_https_cert, sender_name = self.name, recipient_name = self.parent.name,
@@ -636,7 +665,10 @@ class allocation(object):
db = MySQLdb.connect(user = "irdb", db = self.irdb_db_name, passwd = irdb_db_pass)
cur = db.cursor()
for kid in self.kids:
- bpki_cert = cross_certify(self.name + "-SELF-1", kid.name + "-SELF-1")
+ if kid.is_leaf():
+ bpki_cert = self.cross_certify(kid.name + "-TA")
+ else:
+ bpki_cert = self.cross_certify(kid.name + "-SELF-1")
rpki.log.info("Creating rpkid child object for %s as child of %s" % (kid.name, self.name))
kid.child_id = self.call_rpkid(rpki.left_right.child_elt.make_pdu(
action = "create", self_id = self.self_id, bsc_id = self.bsc_id, bpki_cert = bpki_cert)).child_id
@@ -649,16 +681,24 @@ class allocation(object):
action = "create", self_id = self.self_id, as_number = ro.asn,
exact_match = ro.exact_match, ipv4 = ro.v4, ipv6 = ro.v6)).route_origin_id
- def write_leaf_yaml(self):
- """Write YAML scripts for leaf nodes. Only supports list requests
- at the moment: issue requests would require class and SIA values,
- revoke requests would require class and SKI values.
-
- ...Except that we can cheat and assume class 1 because we just
- know that rpkid will assign that with the current setup. So we
- also support issue, kludge though this is.
+ def setup_yaml_leaf(self):
+ """Generate certificates and write YAML scripts for leaf nodes.
+ We're cheating a bit here: properly speaking, we can't generate
+ issue or revoke requests without knowing the class, which is
+ generated on the fly, but at the moment the test case is
+ simplistic enough that the class will always be "1", so we just
+ wire in that value for now.
"""
+ if not os.path.exists(self.name + ".key"):
+ rpki.log.info("Generating RPKI key for %s" % self.name)
+ subprocess.check_call((prog_openssl, "genrsa", "-out", self.name + ".key", "2048" ),
+ stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
+ ski = rpki.x509.RSA(PEM_file = self.name + ".key").gSKI()
+
+ self.cross_certify(self.parent.name + "-TA")
+ self.cross_certify(self.parent.name + "-SELF-1")
+
rpki.log.info("Writing leaf YAML for %s" % self.name)
f = open(self.name + ".yaml", "w")
f.write(yaml_fmt_1 % {
@@ -666,7 +706,8 @@ class allocation(object):
"parent_name" : self.parent.name,
"my_name" : self.name,
"https_port" : self.parent.rpki_port,
- "sia" : self.sia_base })
+ "sia" : self.sia_base,
+ "ski" : ski })
f.close()
def run_cron(self):
@@ -674,7 +715,7 @@ class allocation(object):
rpki.log.info("Running cron for %s" % self.name)
rpki.https.client(client_key = self.irbe_key,
- client_cert = self.irbe_cer,
+ client_cert = self.irbe_cert,
server_ta = self.rpkid_ta,
url = "https://localhost:%d/cronjob" % self.rpki_port,
msg = "Run cron now, please")
@@ -685,8 +726,8 @@ class allocation(object):
subprocess.check_call((prog_python, prog_poke, "-y", self.name + ".yaml", "-r", "list", "-d"))
subprocess.check_call((prog_python, prog_poke, "-y", self.name + ".yaml", "-r", "issue", "-d"))
-def setup_biz_cert_chain(name, ee = (), ca = ()):
- """Build a set of business certs."""
+def setup_bpki_cert_chain(name, ee = (), ca = ()):
+ """Build a set of BPKI certificates."""
s = "exec >/dev/null 2>&1\n"
for kind in ("TA",) + ee + ca:
d = { "name" : name,
@@ -694,39 +735,18 @@ def setup_biz_cert_chain(name, ee = (), ca = ()):
"ca" : "false" if kind in ee else "true",
"openssl" : prog_openssl }
f = open("%(name)s-%(kind)s.conf" % d, "w")
- f.write(biz_cert_fmt_1 % d)
+ f.write(bpki_cert_fmt_1 % d)
f.close()
if not os.path.exists("%(name)s-%(kind)s.key" % d):
- s += biz_cert_fmt_2 % d
- s += biz_cert_fmt_3 % d
+ s += bpki_cert_fmt_2 % d
+ s += bpki_cert_fmt_3 % d
d = { "name" : name, "openssl" : prog_openssl }
- s += biz_cert_fmt_4 % d
+ s += bpki_cert_fmt_4 % d
for kind in ee + ca:
d["kind"] = kind
- s += biz_cert_fmt_5 % d
+ s += bpki_cert_fmt_5 % d
subprocess.check_call(s, shell = True)
-def cross_certify(certifier, certificant):
- """Cross-certify and return the resulting certificate."""
- certfile = certifier + "-" + certificant + ".cer"
- rpki.log.trace()
- rpki.log.info("Cross certifying %s into %s's BPKI (%s)" % (certificant, certifier, certfile))
- signer = subprocess.Popen((prog_openssl, "x509", "-req", "-sha256", "-text",
- "-extensions", "req_x509_ext", "-CAcreateserial",
- "-in", certificant + ".req",
- "-out", certfile,
- "-extfile", certifier + ".conf",
- "-CA", certifier + ".cer",
- "-CAkey", certifier + ".key"),
- stdout = subprocess.PIPE,
- stderr = subprocess.PIPE)
- errors = signer.communicate()[1]
- if signer.returncode != 0:
- msg = "Couldn't cross-certify %s into %s's BPKI: %s" % (certificant, certifier, errors)
- rpki.log.error(msg)
- raise RuntimeError, msg
- return rpki.x509.X509(Auto_file = certfile)
-
def setup_rootd(rpkid_name, rpkid_tag):
"""Write the config files for rootd."""
rpki.log.info("Writing config files for %s" % rootd_name)
@@ -794,7 +814,7 @@ def mangle_sql(filename):
f.close()
return [stmt.strip() for stmt in statements]
-biz_cert_fmt_1 = '''\
+bpki_cert_fmt_1 = '''\
[ req ]
distinguished_name = req_dn
x509_extensions = req_x509_ext
@@ -810,19 +830,19 @@ subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
'''
-biz_cert_fmt_2 = '''\
+bpki_cert_fmt_2 = '''\
%(openssl)s genrsa -out %(name)s-%(kind)s.key 2048 &&
'''
-biz_cert_fmt_3 = '''\
+bpki_cert_fmt_3 = '''\
%(openssl)s req -new -sha256 -key %(name)s-%(kind)s.key -out %(name)s-%(kind)s.req -config %(name)s-%(kind)s.conf &&
'''
-biz_cert_fmt_4 = '''\
+bpki_cert_fmt_4 = '''\
%(openssl)s x509 -req -sha256 -in %(name)s-TA.req -out %(name)s-TA.cer -extfile %(name)s-TA.conf -extensions req_x509_ext -signkey %(name)s-TA.key -days 60 -text \
'''
-biz_cert_fmt_5 = ''' && \
+bpki_cert_fmt_5 = ''' && \
%(openssl)s x509 -req -sha256 -in %(name)s-%(kind)s.req -out %(name)s-%(kind)s.cer -extfile %(name)s-%(kind)s.conf -extensions req_x509_ext -days 30 -text \
-CA %(name)s-TA.cer -CAkey %(name)s-TA.key -CAcreateserial \
'''
@@ -833,27 +853,34 @@ posturl: https://localhost:%(https_port)s/up-down/%(child_id)s
recipient-id: "%(parent_name)s"
sender-id: "%(my_name)s"
-cms-cert-file: %(my_name)s-RPKI-EE.cer
-cms-key-file: %(my_name)s-RPKI-EE.key
-cms-ca-cert-file: %(parent_name)s-RPKI-TA.cer
-cms-cert-chain-file: [ %(my_name)s-RPKI-CA.cer ]
+cms-cert-file: %(my_name)s-RPKI.cer
+cms-key-file: %(my_name)s-RPKI.key
+cms-ca-cert-file: %(my_name)s-TA.cer
+cms-ca-certs-file:
+ - %(my_name)s-TA-%(parent_name)s-TA.cer
+ - %(my_name)s-TA-%(parent_name)s-SELF-1.cer
+
+ssl-cert-file: %(my_name)s-RPKI.cer
+ssl-key-file: %(my_name)s-RPKI.key
+ssl-ca-cert-file: %(my_name)s-TA.cer
+ssl-ca-certs-file:
+ - %(my_name)s-TA-%(parent_name)s-TA.cer
-ssl-cert-file: %(my_name)s-RPKI-EE.cer
-ssl-key-file: %(my_name)s-RPKI-EE.key
-ssl-ca-cert-file: %(parent_name)s-RPKI-TA.cer
-ssl-cert-chain-file: [ %(my_name)s-RPKI-CA.cer ]
+# We're cheating here by hardwiring the class name
requests:
list:
- type: list
+ type: list
issue:
- type: issue
- #
- # This is cheating, we know a priori that the class will be "1"
- #
- class: 1
+ type: issue
+ class: 1
sia:
- - %(sia)s
+ - %(sia)s
+ cert-request-key-file: %(my_name)s.key
+ revoke:
+ type: revoke
+ class: 1
+ ski: %(ski)s
'''
conf_fmt_1 = '''\