aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2011-12-23 06:20:41 +0000
committerRob Austein <sra@hactrn.net>2011-12-23 06:20:41 +0000
commit75c16c86b64dc47bc8559946d4e133586b9a2919 (patch)
tree8348cf0ddd300a2f448912c9dce0d13876dec299
parent081d4284a989485236514ff80c9cce6676f35102 (diff)
Rework schema using abstract models rather than stuffing everything
with the same syntax into the same SQL table. svn path=/branches/tk100/; revision=4133
-rw-r--r--rpkid/rpki/irdb/models.py136
-rw-r--r--rpkid/rpki/rpkic.py44
-rw-r--r--scripts/convert-from-entitydb-to-sql.py95
3 files changed, 162 insertions, 113 deletions
diff --git a/rpkid/rpki/irdb/models.py b/rpkid/rpki/irdb/models.py
index 9ab50de5..2cc3f5aa 100644
--- a/rpkid/rpki/irdb/models.py
+++ b/rpkid/rpki/irdb/models.py
@@ -154,13 +154,7 @@ class CertificateManager(django.db.models.Manager):
changed = False
try:
- # Seriously icky, but does what we need. Rewrite using some
- # kind of method routine that returns the key names.
- try:
- keys = self.model._meta.unique_together[0] or ("handle",)
- except (AttributeError, IndexError):
- keys = ("handle",)
- obj = self.get(**dict((k, kwargs[k]) for k in keys))
+ obj = self.get(**self._get_or_certify_keys(kwargs))
except self.model.DoesNotExist:
obj = self.model(**kwargs)
@@ -178,10 +172,24 @@ class CertificateManager(django.db.models.Manager):
return obj, changed
+ def _get_or_certify_keys(self, kwargs):
+ return dict((k, kwargs[k]) for k in self.model._meta.unique_together[0])
+
+class ResourceHolderCAManager(CertificateManager):
+ def _get_or_certify_keys(self, kwargs):
+ return { "handle" : kwargs["handle"] }
+
+class ServerCAManager(CertificateManager):
+ def _get_or_certify_keys(self, kwargs):
+ return { "pk" : 1 }
+
+class ReferralCertificateManager(CertificateManager):
+ def _get_or_certify_keys(self, kwargs):
+ return { "issuer" : kwargs["issuer"] }
+
###
class CA(django.db.models.Model):
- handle = HandleField(unique = True)
certificate = CertificateField()
private_key = RSAKeyField()
latest_crl = CRLField()
@@ -195,27 +203,21 @@ class CA(django.db.models.Model):
last_crl_update = SundialField()
next_crl_update = SundialField()
- objects = CertificateManager()
-
# These should come from somewhere, but I don't yet know where
ca_certificate_lifetime = rpki.sundial.timedelta(days = 3652)
crl_interval = rpki.sundial.timedelta(days = 1)
- def __unicode__(self):
- return self.handle
+ class Meta:
+ abstract = True
def avow(self):
if self.private_key is None:
self.private_key = rpki.x509.RSA.generate()
- if self.handle:
- subject_name = rpki.x509.X501DN("%s BPKI resource CA" % self.handle)
- else:
- subject_name = rpki.x509.X501DN("%s BPKI server CA" % socket.gethostname())
now = rpki.sundial.now()
notAfter = now + self.ca_certificate_lifetime
self.certificate = rpki.x509.X509.bpki_self_certify(
keypair = self.private_key,
- subject_name = subject_name,
+ subject_name = self.subject_name,
serial = self.next_serial,
now = now,
notAfter = notAfter)
@@ -263,6 +265,27 @@ class CA(django.db.models.Model):
self.next_crl_update = now + self.crl_interval
self.next_crl_number += 1
+class ServerCA(CA):
+ objects = ServerCAManager()
+
+ def __unicode__(self):
+ return ""
+
+ @property
+ def subject_name(self):
+ return rpki.x509.X501DN("%s BPKI server CA" % socket.gethostname())
+
+class ResourceHolderCA(CA):
+ handle = HandleField(unique = True)
+ objects = ResourceHolderCAManager()
+
+ def __unicode__(self):
+ return self.handle
+
+ @property
+ def subject_name(self):
+ return rpki.x509.X501DN("%s BPKI resource CA" % self.handle)
+
class Certificate(django.db.models.Model):
certificate = CertificateField()
@@ -286,25 +309,25 @@ class CrossCertification(Certificate):
def avow(self):
self.certificate = self.issuer.certify(
- subject_name = self.ta.getSubject(),
- subject_key = self.ta.getPublicKey(),
- interval = self.default_interval,
- is_ca = True,
+ subject_name = self.ta.getSubject(),
+ subject_key = self.ta.getPublicKey(),
+ validity_interval = self.default_interval,
+ is_ca = True,
pathLenConstraint = 0)
def __unicode__(self):
return self.handle
class HostedCA(Certificate):
- issuer = django.db.models.ForeignKey(CA)
- hosted = django.db.models.OneToOneField(CA, related_name = "hosted_by")
+ issuer = django.db.models.ForeignKey(ServerCA)
+ hosted = django.db.models.OneToOneField(ResourceHolderCA, related_name = "hosted_by")
def avow(self):
self.certificate = self.issuer.certify(
- subject_name = self.hosted_ca.getSubject(),
- subject_key = self.hosted_ca.getPublicKey(),
- interval = self.default_interval,
- is_ca = True,
+ subject_name = self.hosted_ca.getSubject(),
+ subject_key = self.hosted_ca.getPublicKey(),
+ validity_interval = self.default_interval,
+ is_ca = True,
pathLenConstraint = 1)
class Meta:
@@ -314,51 +337,72 @@ class HostedCA(Certificate):
return self.hosted_ca.handle
class Revocation(django.db.models.Model):
- issuer = django.db.models.ForeignKey(CA, related_name = "revocations")
serial = django.db.models.BigIntegerField()
revoked = SundialField()
expires = SundialField()
class Meta:
+ abstract = True
unique_together = ("issuer", "serial")
+class ServerRevocation(Revocation):
+ issuer = django.db.models.ForeignKey(ServerCA, related_name = "revocations")
+
+class ResourceHolderRevocation(Revocation):
+ issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "revocations")
+
class EECertificate(Certificate):
- issuer = django.db.models.ForeignKey(CA, related_name = "ee_certificates")
- purpose = EnumField(choices = ("rpkid", "pubd", "irdbd", "irbe", "rootd", "referral"))
private_key = RSAKeyField()
class Meta:
- unique_together = ("issuer", "purpose")
+ abstract = True
def avow(self):
if self.private_key is None:
self.private_key = rpki.x509.RSA.generate()
- subject_name = rpki.x509.X501DN("%s BPKI %s EE" % (
- self.issuer.handle if self.issuer.handle else socket.gethostname(),
- self.get_purpose_display()))
self.certificate = self.issuer.certify(
- subject_name = subject_name,
+ subject_name = self.subject_name,
subject_key = self.private_key.get_RSApublic(),
validity_interval = self.default_interval,
is_ca = False)
+class ServerCertificate(EECertificate):
+ issuer = django.db.models.ForeignKey(ServerCA, related_name = "ee_certificates")
+ purpose = EnumField(choices = ("rpkid", "pubd", "irdbd", "irbe", "rootd"))
+
+ class Meta:
+ unique_together = ("issuer", "purpose")
+
+ @property
+ def subject_name(self):
+ return rpki.x509.X501DN("%s BPKI %s EE" % (socket.gethostname(), self.get_purpose_display()))
+
+class ReferralCertificate(EECertificate):
+ issuer = django.db.models.OneToOneField(ResourceHolderCA, related_name = "referral_certificate")
+ objects = ReferralCertificateManager()
+
+ @property
+ def subject_name(self):
+ return rpki.x509.X501DN("%s BPKI Referral EE" % self.issuer.handle)
+
+
class BSC(Certificate):
- issuer = django.db.models.ForeignKey(CA, related_name = "bscs")
+ issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "bscs")
handle = HandleField()
pkcs10 = PKCS10Field()
def avow(self):
self.certificate = self.issuer.certify(
- subject_name = self.pkcs10.getSubject(),
- subject_key = self.pkcs10.getPublicKey(),
- interval = self.default_interval,
- is_ca = False)
+ subject_name = self.pkcs10.getSubject(),
+ subject_key = self.pkcs10.getPublicKey(),
+ validity_interval = self.default_interval,
+ is_ca = False)
def __unicode__(self):
return self.handle
class Child(CrossCertification):
- issuer = django.db.models.ForeignKey(CA, related_name = "children")
+ issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "children")
name = django.db.models.TextField(null = True, blank = True)
valid_until = SundialField()
@@ -380,7 +424,7 @@ class ChildNet(django.db.models.Model):
unique_together = ("child", "start_ip", "end_ip", "version")
class Parent(CrossCertification):
- issuer = django.db.models.ForeignKey(CA, related_name = "parents")
+ issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "parents")
parent_handle = HandleField()
child_handle = HandleField()
service_uri = django.db.models.CharField(max_length = 255)
@@ -389,7 +433,7 @@ class Parent(CrossCertification):
referral_authorization = SignedReferralField(null = True, blank = True)
class ROARequest(django.db.models.Model):
- issuer = django.db.models.ForeignKey(CA, related_name = "roa_requests")
+ issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "roa_requests")
asn = django.db.models.BigIntegerField()
class ROARequestPrefix(django.db.models.Model):
@@ -403,18 +447,18 @@ class ROARequestPrefix(django.db.models.Model):
unique_together = ("roa_request", "version", "prefix", "prefixlen", "max_prefixlen")
class GhostbusterRequest(django.db.models.Model):
- issuer = django.db.models.ForeignKey(CA, related_name = "ghostbuster_requests")
+ issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "ghostbuster_requests")
parent = django.db.models.ForeignKey(Parent, related_name = "ghostbuster_requests", null = True)
vcard = django.db.models.TextField()
class Repository(CrossCertification):
- issuer = django.db.models.ForeignKey(CA, related_name = "repositories")
+ issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "repositories")
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")
class Client(CrossCertification):
- issuer = django.db.models.ForeignKey(CA, related_name = "clients")
+ issuer = django.db.models.ForeignKey(ServerCA, related_name = "clients")
sia_base = django.db.models.TextField()
diff --git a/rpkid/rpki/rpkic.py b/rpkid/rpki/rpkic.py
index ea2b7b2a..88e3f26b 100644
--- a/rpkid/rpki/rpkic.py
+++ b/rpkid/rpki/rpkic.py
@@ -218,12 +218,12 @@ class main(rpki.cli.Cmd):
def reset_identity(self):
try:
- self.resource_ca = rpki.irdb.CA.objects.get(handle = self.handle)
- except rpki.irdb.CA.DoesNotExist:
+ self.resource_ca = rpki.irdb.ResourceHolderCA.objects.get(handle = self.handle)
+ except rpki.irdb.ResourceHolderCA.DoesNotExist:
self.resource_ca = None
try:
- self.server_ca = rpki.irdb.CA.objects.get(handle = "*")
- except rpki.irdb.CA.DoesNotExist:
+ self.server_ca = rpki.irdb.ServerCA.objects.get()
+ except rpki.irdb.ServerCA.DoesNotExist:
self.server_ca = None
def help_overview(self):
@@ -252,7 +252,7 @@ class main(rpki.cli.Cmd):
self.reset_identity()
def complete_select_identity(self, *args):
- return self.irdb_handle_complete(rpki.irdb.CA, *args)
+ return self.irdb_handle_complete(rpki.irdb.ResourceHolderCA, *args)
def do_initialize(self, arg):
@@ -266,23 +266,23 @@ class main(rpki.cli.Cmd):
if arg:
raise BadCommandSyntax, "This command takes no arguments"
- self.resource_ca, created = rpki.irdb.CA.objects.get_or_certify(handle = self.handle)
+ self.resource_ca, created = rpki.irdb.ResourceHolderCA.objects.get_or_certify(handle = self.handle)
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:
- self.server_ca, created = rpki.irdb.CA.objects.get_or_certify(handle = "*")
+ 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.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "rpkid")
- rpki.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "irdbd")
+ 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.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "pubd")
+ rpki.irdb.ServerCertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "pubd")
if self.run_rpkid or self.run_pubd:
- rpki.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "irbe")
+ rpki.irdb.ServerCertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "irbe")
if self.run_rootd:
- rpki.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "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?
@@ -345,19 +345,25 @@ class main(rpki.cli.Cmd):
Most likely this should be run under cron.
"""
- for model in (rpki.irdb.CA,
- rpki.irdb.EECertificate,
+ for model in (rpki.irdb.ServerCA,
+ rpki.irdb.ResourceHolderCA,
+ rpki.irdb.ServerCertificate,
+ rpki.irdb.HostedCA,
+ rpki.irdb.ReferralCertificate,
rpki.irdb.BSC,
rpki.irdb.Child,
rpki.irdb.Parent,
rpki.irdb.Client,
rpki.irdb.Repository):
- for obj in model.all():
+ for obj in model.objects.all():
print "Regenerating certificate", obj.certificate.getSubject()
obj.avow()
- for ca in rpki.irdb.CA.all():
- print "Regenerating CRL for", ca.handle if ca.handle else "[servers]"
+ print "Regenerating Server CRL"
+ self.server_ca.generate_crl()
+
+ for ca in rpki.irdb.ResourceHolderCA.objects.all():
+ print "Regenerating CRL for", ca.handle
ca.generate_crl()
def do_configure_child(self, arg):
@@ -547,7 +553,7 @@ class main(rpki.cli.Cmd):
client_ta = rpki.x509.X509(Base64 = client.findtext("bpki_client_ta"))
- if sia_base is None and client.get("handle") == self.handle and self.bpki_resources.ca.certificate == client_ta:
+ if sia_base is None and client.get("handle") == self.handle and self.resource_ca.certificate == client_ta:
print "This looks like self-hosted publication"
sia_base = "rsync://%s/%s/%s/" % (self.rsync_server, self.rsync_module, self.handle)
@@ -869,7 +875,7 @@ class main(rpki.cli.Cmd):
action = "set",
bpki_crl = self.server_ca.latest_crl))
- for ca in rpki.irdb.CA.objects.exclude(handle = "*"):
+ for ca in rpki.irdb.ResourceHolderCA.objects.all():
# See what rpkid and pubd already have on file for this entity.
diff --git a/scripts/convert-from-entitydb-to-sql.py b/scripts/convert-from-entitydb-to-sql.py
index dbdde34c..64f0d31a 100644
--- a/scripts/convert-from-entitydb-to-sql.py
+++ b/scripts/convert-from-entitydb-to-sql.py
@@ -109,37 +109,40 @@ def read_openssl_serial(filename):
f.close()
return int(text.strip(), 16)
-def get_or_create_CA(purpose):
- cer = rpki.x509.X509(Auto_file = os.path.join(bpki, purpose, "ca.cer"))
- key = rpki.x509.RSA(Auto_file = os.path.join(bpki, purpose, "ca.key"))
- crl = rpki.x509.CRL(Auto_file = os.path.join(bpki, purpose, "ca.crl"))
- serial = read_openssl_serial(os.path.join(bpki, purpose, "serial"))
- crl_number = read_openssl_serial(os.path.join(bpki, purpose, "crl_number"))
-
- return rpki.irdb.CA.objects.get_or_create(
- handle = self_handle if purpose == "resources" else "*",
- certificate = cer,
- private_key = key,
- latest_crl = crl,
- next_serial = serial,
- next_crl_number = crl_number,
- last_crl_update = crl.getThisUpdate().to_sql(),
- next_crl_update = crl.getNextUpdate().to_sql())[0]
-
-def get_or_create_EECertificate(issuer, capurpose, eepurpose):
- cer = rpki.x509.X509(Auto_file = os.path.join(bpki, capurpose, eepurpose + ".cer"))
- key = rpki.x509.RSA(Auto_file = os.path.join(bpki, capurpose, eepurpose + ".key"))
- rpki.irdb.EECertificate.objects.get_or_create(
+def get_or_create_ServerCertificate(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(
issuer = issuer,
- purpose = eepurpose,
+ purpose = purpose,
certificate = cer,
private_key = key)
# Load BPKI CA data
-resource_ca = get_or_create_CA("resources")
+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"))
+crl = rpki.x509.CRL(Auto_file = os.path.join(bpki, "resources", "ca.crl"))
+serial = read_openssl_serial(os.path.join(bpki, "resources", "serial"))
+crl_number = read_openssl_serial(os.path.join(bpki, "resources", "crl_number"))
+
+resource_ca = rpki.irdb.ResourceHolderCA.objects.get_or_create(
+ handle = self_handle,
+ certificate = cer,
+ private_key = key,
+ latest_crl = crl,
+ next_serial = serial,
+ next_crl_number = crl_number,
+ last_crl_update = crl.getThisUpdate().to_sql(),
+ next_crl_update = crl.getNextUpdate().to_sql())[0]
+
if os.path.exists(os.path.join(bpki, "resources", "referral.cer")):
- get_or_create_EECertificate(resource_ca, "resources", "referral")
+ 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(
+ issuer = resource_ca,
+ certificate = cer,
+ private_key = key)
# Load BPKI server EE certificates and keys
@@ -147,15 +150,29 @@ run_flags = dict((i, cfg.getboolean(i, section = "myrpki"))
for i in ("run_rpkid", "run_pubd", "run_rootd"))
if any(run_flags.itervalues()):
- server_ca = get_or_create_CA("servers")
- get_or_create_EECertificate(server_ca, "servers", "irbe")
+ 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,
+ latest_crl = crl,
+ next_serial = serial,
+ next_crl_number = crl_number,
+ last_crl_update = crl.getThisUpdate().to_sql(),
+ next_crl_update = crl.getNextUpdate().to_sql())[0]
+
+ get_or_create_ServerCertificate(server_ca, "irbe")
if run_flags["run_rpkid"]:
- get_or_create_EECertificate(server_ca, "servers", "rpkid")
- get_or_create_EECertificate(server_ca, "servers", "irdbd")
+ get_or_create_ServerCertificate(server_ca, "rpkid")
+ get_or_create_ServerCertificate(server_ca, "irdbd")
if run_flags["run_pubd"]:
- get_or_create_EECertificate(server_ca, "servers", "pubd")
+ get_or_create_ServerCertificate(server_ca, "pubd")
if run_flags["run_rootd"]:
- get_or_create_EECertificate(server_ca, "servers", "rootd")
+ get_or_create_ServerCertificate(server_ca, "rootd")
else:
server_ca = None
@@ -194,24 +211,6 @@ def xcert_hash(cert):
hash = hash[len("(stdin)="):]
return hash
-# OK, all this wretched cross-certification looks complicated, but
-# that's partly because of the way we've been doing it on disk. The
-# new SQL/object based approach should make it much clearer:
-#
-# Child cross certifies parent's resource TA in child's resource CA.
-#
-# Parent cross certifies child's resource TA in parent's resource
-# CA.
-#
-# Repository cross certifies client's resource TA in repository's
-# server CA.
-#
-# Client cross certifies repository's server TA in client's resource
-# CA.
-#
-# The remaining xcert files look to be TLS relics which no longer
-# serve any real purpose; in theory, those can just go away.
-
# Let's try keeping track of all the xcert filenames we use, so we can
# list the ones we didn't.