aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2011-12-25 18:36:49 +0000
committerRob Austein <sra@hactrn.net>2011-12-25 18:36:49 +0000
commit523a1f269dc1c19e3537fc0d1dc9b96a1e7fb8dc (patch)
tree69159fc376fc35ad525600d184c3598d3532f6f6
parent75c16c86b64dc47bc8559946d4e133586b9a2919 (diff)
Clean up rootd cross-certification nastiness (another TLS relic).
svn path=/branches/tk100/; revision=4134
-rw-r--r--rpkid/rpki/irdb/models.py45
-rw-r--r--rpkid/rpki/rpkic.py93
-rw-r--r--scripts/convert-from-entitydb-to-sql.py59
3 files changed, 123 insertions, 74 deletions
diff --git a/rpkid/rpki/irdb/models.py b/rpkid/rpki/irdb/models.py
index 2cc3f5aa..fad3b31a 100644
--- a/rpkid/rpki/irdb/models.py
+++ b/rpkid/rpki/irdb/models.py
@@ -27,13 +27,22 @@ import rpki.x509
import rpki.sundial
import socket
+## @var ip_version_choices
+# Choice argument for fields implementing IP version numbers.
+
+ip_version_choices = ((4, "IPv4"), (6, "IPv6"))
+
###
+# Field types
+
class HandleField(django.db.models.CharField):
"""
A handle field type.
"""
+ description = 'A "handle" in one of the RPKI protocols'
+
def __init__(self, *args, **kwargs):
kwargs["max_length"] = 120
django.db.models.CharField.__init__(self, *args, **kwargs)
@@ -44,6 +53,8 @@ class EnumField(django.db.models.PositiveSmallIntegerField):
in SQL.
"""
+ description = "An enumeration type"
+
__metaclass__ = django.db.models.SubfieldBase
def __init__(self, *args, **kwargs):
@@ -64,6 +75,8 @@ class SundialField(django.db.models.DateTimeField):
A field type for our customized datetime objects.
"""
+ description = "A datetime type using our customized datetime objects"
+
def to_python(self, value):
return rpki.sundial.datetime.fromdatetime(
django.db.models.DateTimeField.to_python(self, value))
@@ -76,7 +89,7 @@ class SundialField(django.db.models.DateTimeField):
class DERField(django.db.models.Field):
"""
- A field type for DER objects.
+ A field type to represent ASN.1 DER objects as SQL BLOBs.
This is an abstract class, subclasses need to define rpki_type.
"""
@@ -131,10 +144,9 @@ class SignedReferralField(DERField):
description = "CMS signed object containing XML"
rpki_type = rpki.x509.SignedReferral
-## @var ip_version_choices
-# Choice argument for fields implementing IP version numbers.
+###
-ip_version_choices = ((4, "IPv4"), (6, "IPv6"))
+# Custom managers
class CertificateManager(django.db.models.Manager):
@@ -183,7 +195,7 @@ class ServerCAManager(CertificateManager):
def _get_or_certify_keys(self, kwargs):
return { "pk" : 1 }
-class ReferralCertificateManager(CertificateManager):
+class ResourceHolderEEManager(CertificateManager):
def _get_or_certify_keys(self, kwargs):
return { "issuer" : kwargs["issuer"] }
@@ -366,9 +378,9 @@ class EECertificate(Certificate):
validity_interval = self.default_interval,
is_ca = False)
-class ServerCertificate(EECertificate):
+class ServerEE(EECertificate):
issuer = django.db.models.ForeignKey(ServerCA, related_name = "ee_certificates")
- purpose = EnumField(choices = ("rpkid", "pubd", "irdbd", "irbe", "rootd"))
+ purpose = EnumField(choices = ("rpkid", "pubd", "irdbd", "irbe"))
class Meta:
unique_together = ("issuer", "purpose")
@@ -377,14 +389,24 @@ class ServerCertificate(EECertificate):
def subject_name(self):
return rpki.x509.X501DN("%s BPKI %s EE" % (socket.gethostname(), self.get_purpose_display()))
-class ReferralCertificate(EECertificate):
+class Referral(EECertificate):
issuer = django.db.models.OneToOneField(ResourceHolderCA, related_name = "referral_certificate")
- objects = ReferralCertificateManager()
+ objects = ResourceHolderEEManager()
@property
def subject_name(self):
return rpki.x509.X501DN("%s BPKI Referral EE" % self.issuer.handle)
+class Turtle(django.db.models.Model):
+ service_uri = django.db.models.CharField(max_length = 255)
+
+class Rootd(EECertificate, Turtle):
+ issuer = django.db.models.OneToOneField(ResourceHolderCA, related_name = "rootd")
+ objects = ResourceHolderEEManager()
+
+ @property
+ def subject_name(self):
+ return rpki.x509.X501DN("%s BPKI rootd EE" % self.issuer.handle)
class BSC(Certificate):
issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "bscs")
@@ -423,11 +445,10 @@ class ChildNet(django.db.models.Model):
class Meta:
unique_together = ("child", "start_ip", "end_ip", "version")
-class Parent(CrossCertification):
+class Parent(CrossCertification, Turtle):
issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "parents")
parent_handle = HandleField()
child_handle = HandleField()
- service_uri = django.db.models.CharField(max_length = 255)
repository_type = EnumField(choices = ("none", "offer", "referral"))
referrer = HandleField(null = True, blank = True)
referral_authorization = SignedReferralField(null = True, blank = True)
@@ -456,7 +477,7 @@ class Repository(CrossCertification):
client_handle = HandleField()
service_uri = django.db.models.CharField(max_length = 255)
sia_base = django.db.models.TextField()
- parent = django.db.models.OneToOneField(Parent, related_name = "repository")
+ turtle = django.db.models.OneToOneField(Turtle, related_name = "repository")
class Client(CrossCertification):
issuer = django.db.models.ForeignKey(ServerCA, related_name = "clients")
diff --git a/rpkid/rpki/rpkic.py b/rpkid/rpki/rpkic.py
index 88e3f26b..48749a15 100644
--- a/rpkid/rpki/rpkic.py
+++ b/rpkid/rpki/rpkic.py
@@ -270,29 +270,18 @@ class main(rpki.cli.Cmd):
if created:
print "Created new BPKI resource CA for identity %s" % self.handle
- if self.run_rpkid or self.run_pubd or self.run_rootd:
+ if self.run_rpkid or self.run_pubd:
self.server_ca, created = rpki.irdb.ServerCA.objects.get_or_certify()
if created:
print "Created new BPKI server CA"
- if self.run_rpkid:
- rpki.irdb.ServerCertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "rpkid")
- rpki.irdb.ServerCertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "irdbd")
- if self.run_pubd:
- rpki.irdb.ServerCertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "pubd")
- if self.run_rpkid or self.run_pubd:
- rpki.irdb.ServerCertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "irbe")
- if self.run_rootd:
- rpki.irdb.ServerCertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "rootd")
-
- ## @todo
- # Why do we issue root's EE certificate under our server CA?
- # We've "always" done this, but does it make sense now? rootd
- # only speaks up-down, so it's really just another resource
- # holder. If we just issued it under our resource CA, we
- # wouldn't have to cross certify anything to talk to it. Which
- # might in itself break something, as it'd be the only parent we
- # -didn't- have to cross-certify. Leave alone for now, but
- # think about this later.
+ rpki.irdb.ServerEE.objects.get_or_certify(issuer = self.server_ca, purpose = "irbe")
+
+ if self.run_rpkid:
+ rpki.irdb.ServerEE.objects.get_or_certify(issuer = self.server_ca, purpose = "rpkid")
+ rpki.irdb.ServerEE.objects.get_or_certify(issuer = self.server_ca, purpose = "irdbd")
+
+ if self.run_pubd:
+ rpki.irdb.ServerEE.objects.get_or_certify(issuer = self.server_ca, purpose = "pubd")
# Build the identity.xml file. Need to check for existing file so we don't
# overwrite? Worry about that later.
@@ -302,25 +291,16 @@ class main(rpki.cli.Cmd):
etree_write(e, "identity.xml",
msg = None if self.run_rootd else 'This is the "identity" file you will need to send to your parent')
- # If we're running rootd, construct a fake parent to go with it,
- # and cross-certify in both directions so we can talk to rootd.
-
if self.run_rootd:
+ assert self.run_rpkid and self.run_pubd
- rpki.irdb.Parent.objects.get_or_certify(
- issuer = self.resource_ca,
- handle = self.handle,
- parent_handle = self.handle,
- child_handle = self.handle,
- ta = self.server_ca.certificate,
- service_uri = "http://localhost:%s/" % self.cfg.get("rootd_server_port"),
- repository_type = "offer")
-
- rpki.irdb.Child.objects.get_or_certify(
- issuer = self.server_ca,
- handle = self.handle,
- ta = self.resource_ca.certificate,
- valid_until = self.resource_ca.certificate.getNotAfter())
+ rpki.irdb.Rootd.objects.get_or_certify(
+ issuer = self.resource_ca,
+ service_uri = "http://localhost:%s/" % self.cfg.get("rootd_server_port"))
+
+ # 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)
@@ -347,9 +327,10 @@ class main(rpki.cli.Cmd):
for model in (rpki.irdb.ServerCA,
rpki.irdb.ResourceHolderCA,
- rpki.irdb.ServerCertificate,
+ rpki.irdb.ServerEE,
+ rpki.irdb.Referral,
+ rpki.irdb.Rootd,
rpki.irdb.HostedCA,
- rpki.irdb.ReferralCertificate,
rpki.irdb.BSC,
rpki.irdb.Child,
rpki.irdb.Parent,
@@ -661,9 +642,12 @@ class main(rpki.cli.Cmd):
print "Repository response associated with parent_handle %r" % parent_handle
try:
- parent = self.resource_ca.parents.get(handle = parent_handle)
+ if parent_handle == self.handle:
+ turtle = self.resource_ca.rootd
+ else:
+ turtle = self.resource_ca.parents.get(handle = parent_handle)
- except rpki.irdb.Parent.DoesNotExist:
+ except (rpki.irdb.Parent.DoesNotExist, rpki.irdb.Rootd.DoesNotExist):
print "Could not find parent %r in our database" % parent_handle
else:
@@ -674,7 +658,7 @@ class main(rpki.cli.Cmd):
service_uri = r.get("service_uri"),
sia_base = r.get("sia_base"),
ta = rpki.x509.X509(Base64 = r.findtext("bpki_server_ta")),
- parent = parent)
+ turtle = turtle)
def do_delete_repository(self, arg):
"""
@@ -1032,6 +1016,31 @@ class main(rpki.cli.Cmd):
recipient_name = parent.parent_handle,
bpki_cms_cert = parent.certificate))
+ if ca.rootd:
+
+ parent_pdu = parent_pdus.pop(ca.handle, None)
+
+ if (parent_pdu is None or
+ parent_pdu.bsc_handle != bsc_handle or
+ parent_pdu.repository_handle != ca.handle or
+ parent_pdu.peer_contact_uri != ca.rootd.service_uri or
+ parent_pdu.sia_base != ca.rootd.repository.sia_base or
+ parent_pdu.sender_name != ca.handle or
+ parent_pdu.recipient_name != ca.handle or
+ parent_pdu.bpki_cms_cert != ca.rootd.certificate):
+ rpkid_query.append(rpki.left_right.parent_elt.make_pdu(
+ action = "create" if parent_pdu is None else "set",
+ tag = ca.handle,
+ self_handle = ca.handle,
+ parent_handle = ca.handle,
+ bsc_handle = bsc_handle,
+ repository_handle = ca.handle,
+ peer_contact_uri = ca.rootd.service_uri,
+ sia_base = ca.rootd.repository.sia_base,
+ sender_name = ca.handle,
+ recipient_name = ca.handle,
+ bpki_cms_cert = ca.rootd.certificate))
+
rpkid_query.extend(rpki.left_right.parent_elt.make_pdu(
action = "destroy", self_handle = ca.handle, parent_handle = p) for p in parent_pdus)
diff --git a/scripts/convert-from-entitydb-to-sql.py b/scripts/convert-from-entitydb-to-sql.py
index 64f0d31a..3ba5241a 100644
--- a/scripts/convert-from-entitydb-to-sql.py
+++ b/scripts/convert-from-entitydb-to-sql.py
@@ -109,16 +109,16 @@ def read_openssl_serial(filename):
f.close()
return int(text.strip(), 16)
-def get_or_create_ServerCertificate(issuer, purpose):
+def get_or_create_ServerEE(issuer, purpose):
cer = rpki.x509.X509(Auto_file = os.path.join(bpki, "servers", purpose + ".cer"))
key = rpki.x509.RSA(Auto_file = os.path.join(bpki, "servers", purpose + ".key"))
- rpki.irdb.ServerCertificate.objects.get_or_create(
+ rpki.irdb.ServerEE.objects.get_or_create(
issuer = issuer,
purpose = purpose,
certificate = cer,
private_key = key)
-# Load BPKI CA data
+# Load BPKI CAs and directly certified EEs
cer = rpki.x509.X509(Auto_file = os.path.join(bpki, "resources", "ca.cer"))
key = rpki.x509.RSA(Auto_file = os.path.join(bpki, "resources", "ca.key"))
@@ -139,23 +139,21 @@ resource_ca = rpki.irdb.ResourceHolderCA.objects.get_or_create(
if os.path.exists(os.path.join(bpki, "resources", "referral.cer")):
cer = rpki.x509.X509(Auto_file = os.path.join(bpki, "resources", "referral.cer"))
key = rpki.x509.RSA(Auto_file = os.path.join(bpki, "resources", "referral.key"))
- rpki.irdb.ReferralCertificate.objects.get_or_create(
+ rpki.irdb.Referral.objects.get_or_create(
issuer = resource_ca,
certificate = cer,
private_key = key)
-# Load BPKI server EE certificates and keys
+run_rpkid = cfg.getboolean("run_rpkid", section = "myrpki")
+run_pubd = cfg.getboolean("run_pubd", section = "myrpki")
+run_rootd = cfg.getboolean("run_rootd", section = "myrpki")
-run_flags = dict((i, cfg.getboolean(i, section = "myrpki"))
- for i in ("run_rpkid", "run_pubd", "run_rootd"))
-
-if any(run_flags.itervalues()):
+if run_rpkid or run_pubd:
cer = rpki.x509.X509(Auto_file = os.path.join(bpki, "servers", "ca.cer"))
key = rpki.x509.RSA(Auto_file = os.path.join(bpki, "servers", "ca.key"))
crl = rpki.x509.CRL(Auto_file = os.path.join(bpki, "servers", "ca.crl"))
serial = read_openssl_serial(os.path.join(bpki, "servers", "serial"))
crl_number = read_openssl_serial(os.path.join(bpki, "servers", "crl_number"))
-
server_ca = rpki.irdb.ServerCA.objects.get_or_create(
certificate = cer,
private_key = key,
@@ -164,18 +162,29 @@ if any(run_flags.itervalues()):
next_crl_number = crl_number,
last_crl_update = crl.getThisUpdate().to_sql(),
next_crl_update = crl.getNextUpdate().to_sql())[0]
+ get_or_create_ServerEE(server_ca, "irbe")
- get_or_create_ServerCertificate(server_ca, "irbe")
- if run_flags["run_rpkid"]:
- get_or_create_ServerCertificate(server_ca, "rpkid")
- get_or_create_ServerCertificate(server_ca, "irdbd")
- if run_flags["run_pubd"]:
- get_or_create_ServerCertificate(server_ca, "pubd")
- if run_flags["run_rootd"]:
- get_or_create_ServerCertificate(server_ca, "rootd")
else:
server_ca = None
+if run_rpkid:
+ get_or_create_ServerEE(server_ca, "rpkid")
+ get_or_create_ServerEE(server_ca, "irdbd")
+
+if run_pubd:
+ get_or_create_ServerEE(server_ca, "pubd")
+
+# Certification model for rootd has changed. We can reuse the old
+# key, but we have to recertify under a different CA than previously.
+# Yes, we're pulling a key from the servers BPKI tree and certifying
+# it under the resource holder CA, that's part of the change.
+
+if run_rootd:
+ rpki.irdb.Rootd.objects.get_or_certify(
+ issuer = resource_ca,
+ service_uri = "http://localhost:%s/" % cfg.get("rootd_server_port", section = "myrpki"),
+ private_key = rpki.x509.RSA(Auto_file = os.path.join(bpki, "servers", "rootd.key")))
+
# Load BSC certificates and requests. Yes, this currently wires in
# exactly one BSC handle, "bsc". So does the old myrpki code. Ick.
@@ -277,6 +286,11 @@ for filename in glob.iglob(os.path.join(entitydb, "parents", "*.xml")):
rpki.relaxng.myrpki.assertValid(e)
assert e.tag == tag_parent
+ if parent_handle == self_handle:
+ assert run_rootd
+ assert e.get("service_uri") == "http://localhost:%s/" % cfg.get("rootd_server_port", section = "myrpki")
+ continue
+
ta = rpki.x509.X509(Base64 = e.findtext(tag_bpki_resource_ta))
xcfn = os.path.join(bpki, "resources", "xcert.%s.cer" % xcert_hash(ta))
xcert_filenames.discard(xcfn)
@@ -298,6 +312,7 @@ for filename in glob.iglob(os.path.join(entitydb, "parents", "*.xml")):
child_handle = e.get("child_handle"),
ta = ta,
certificate = xcert,
+ service_uri = e.get("service_uri"),
repository_type = repository_type,
referrer = referrer,
referral_authorization = referral_authorization,
@@ -334,7 +349,11 @@ for filename in glob.iglob(os.path.join(entitydb, "repositories", "*.xml")):
xcert_filenames.discard(xcfn)
xcert = rpki.x509.X509(Auto_file = xcfn)
- parent = rpki.irdb.Parent.objects.get(handle = e.get("parent_handle"))
+ parent_handle = e.get("parent_handle")
+ if parent_handle == self_handle:
+ turtle = resource_ca.rootd
+ else:
+ turtle = rpki.irdb.Parent.objects.get(handle = parent_handle)
rpki.irdb.Repository.objects.get_or_create(
handle = repository_handle,
@@ -343,7 +362,7 @@ for filename in glob.iglob(os.path.join(entitydb, "repositories", "*.xml")):
certificate = xcert,
service_uri = e.get("service_uri"),
sia_base = e.get("sia_base"),
- parent = parent,
+ turtle = turtle,
issuer = resource_ca)
# Scrape client data out of the entitydb.