aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2011-12-20 19:00:07 +0000
committerRob Austein <sra@hactrn.net>2011-12-20 19:00:07 +0000
commitb87cc14f975ed5cf1e0b34d3a8e30d49ca1a4632 (patch)
tree5b5da1a955f697b51aa653a34d6f7c9002fa820c
parent022a93196b06dbfebb7757ce5b97a814075a57c5 (diff)
Checkpoint. More schema tweaks (HostedCA model).
svn path=/branches/tk100/; revision=4129
-rw-r--r--rpkid/rpki/irdb/models.py65
-rw-r--r--rpkid/rpki/rpkic.py63
-rw-r--r--scripts/convert-from-entitydb-to-sql.py13
3 files changed, 65 insertions, 76 deletions
diff --git a/rpkid/rpki/irdb/models.py b/rpkid/rpki/irdb/models.py
index 2cc46737..20f38d6c 100644
--- a/rpkid/rpki/irdb/models.py
+++ b/rpkid/rpki/irdb/models.py
@@ -25,6 +25,7 @@ PERFORMANCE OF THIS SOFTWARE.
import django.db.models
import rpki.x509
import rpki.sundial
+import socket
###
@@ -148,15 +149,18 @@ class CertificateManager(django.db.models.Manager):
Runs certification method for new or updated objects. Returns a
tuple consisting of the object and a boolean indicating whether
anything has changed.
-
- This is a somewhat weird use of ._meta.unique_together, but fits
- with the way this application use unique indices and foreign keys.
"""
changed = False
try:
- obj = self.get(**dict((k, kwargs[k]) for k in self.model._meta.unique_together[0]))
+ # Icky, but does what we need.
+ try:
+ keys = self.model._meta.unique_together
+ except AttributeError:
+ keys = ("handle",)
+ print "++ Keys:", repr(keys)
+ obj = self.get(**dict((k, kwargs[k]) for k in keys))
except self.model.DoesNotExist:
obj = self.model(**kwargs)
@@ -176,15 +180,8 @@ class CertificateManager(django.db.models.Manager):
###
-class Identity(django.db.models.Model):
- handle = HandleField(unique = True)
-
- def __unicode__(self):
- return self.handle
-
class CA(django.db.models.Model):
- identity = django.db.models.ForeignKey(Identity)
- purpose = EnumField(choices = ("resources", "servers"))
+ handle = HandleField(unique = True)
certificate = CertificateField()
private_key = RSAKeyField()
latest_crl = CRLField()
@@ -200,18 +197,20 @@ class CA(django.db.models.Model):
objects = CertificateManager()
- class Meta:
- unique_together = ("identity", "purpose")
-
# 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
+
def avow(self):
if self.private_key is None:
self.private_key = rpki.x509.RSA.generate()
- subject_name = rpki.x509.X501DN("%s BPKI %s CA" % (
- self.identity.handle, self.get_purpose_display()))
+ 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(
@@ -265,6 +264,7 @@ class CA(django.db.models.Model):
self.next_crl_number += 1
class Certificate(django.db.models.Model):
+
certificate = CertificateField()
objects = CertificateManager()
@@ -272,10 +272,10 @@ class Certificate(django.db.models.Model):
class Meta:
abstract = True
+ unique_together = ("issuer", "handle")
def revoke(self):
- self.ca.revoke(self)
-
+ self.issuer.revoke(self)
class CrossCertification(Certificate):
handle = HandleField()
@@ -283,7 +283,6 @@ class CrossCertification(Certificate):
class Meta:
abstract = True
- unique_together = ("issuer", "handle")
def avow(self):
self.certificate = self.issuer.certify(
@@ -296,6 +295,20 @@ class CrossCertification(Certificate):
def __unicode__(self):
return self.handle
+class HostedCA(Certificate):
+ hosted_ca = OneToOneField(CA, related_name = "hosting_ca")
+
+ 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,
+ pathLenConstraint = 1)
+
+ def __unicode__(self):
+ 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()
@@ -317,7 +330,8 @@ class EECertificate(Certificate):
if self.private_key is None:
self.private_key = rpki.x509.RSA.generate()
subject_name = rpki.x509.X501DN("%s BPKI %s EE" % (
- self.issuer.identity.handle, self.get_purpose_display()))
+ self.issuer.handle if self.issuer.handle else socket.gethostname(),
+ self.get_purpose_display()))
self.certificate = self.issuer.certify(
subject_name = subject_name,
subject_key = self.private_key.get_RSApublic(),
@@ -329,9 +343,6 @@ class BSC(Certificate):
handle = HandleField()
pkcs10 = PKCS10Field()
- class Meta:
- unique_together = ("issuer", "handle")
-
def avow(self):
self.certificate = self.issuer.certify(
subject_name = self.pkcs10.getSubject(),
@@ -374,7 +385,7 @@ class Parent(CrossCertification):
referral_authorization = SignedReferralField(null = True, blank = True)
class ROARequest(django.db.models.Model):
- identity = django.db.models.ForeignKey(Identity, related_name = "roa_requests")
+ issuer = django.db.models.ForeignKey(CA, related_name = "roa_requests")
asn = django.db.models.BigIntegerField()
class ROARequestPrefix(django.db.models.Model):
@@ -388,8 +399,8 @@ class ROARequestPrefix(django.db.models.Model):
unique_together = ("roa_request", "version", "prefix", "prefixlen", "max_prefixlen")
class GhostbusterRequest(django.db.models.Model):
- identity = django.db.models.ForeignKey(Identity, related_name = "ghostbuster_requests")
- parent = django.db.models.ForeignKey(Parent, related_name = "ghostbuster_requests", null = True)
+ issuer = django.db.models.ForeignKey(CA, related_name = "ghostbuster_requests")
+ parent = django.db.models.ForeignKey(Parent, related_name = "ghostbuster_requests", null = True)
vcard = django.db.models.TextField()
class Repository(CrossCertification):
diff --git a/rpkid/rpki/rpkic.py b/rpkid/rpki/rpkic.py
index 8ff18fd5..f77eefbb 100644
--- a/rpkid/rpki/rpkic.py
+++ b/rpkid/rpki/rpkic.py
@@ -216,20 +216,13 @@ class main(rpki.cli.Cmd):
def reset_identity(self):
try:
- self.identity = rpki.irdb.Identity.objects.get(handle = self.handle)
- except rpki.irdb.Identity.DoesNotExist:
- self.identity = None
+ self.resource_ca = rpki.irdb.CA.objects.get(handle = self.handle)
+ except rpki.irdb.CA.DoesNotExist:
self.resource_ca = None
+ try:
+ self.server_ca = rpki.irdb.CA.objects.get(handle = "")
+ except rpki.irdb.CA.DoesNotExist:
self.server_ca = None
- else:
- try:
- self.resource_ca = self.identity.ca_set.get(purpose = "resources")
- except rpki.irdb.CA.DoesNotExist:
- self.resource_ca = None
- try:
- self.server_ca = self.identity.ca_set.get(purpose = "servers")
- except rpki.irdb.CA.DoesNotExist:
- self.server_ca = None
def help_overview(self):
"""
@@ -243,7 +236,7 @@ class main(rpki.cli.Cmd):
self.stdout.write("\n")
def irdb_handle_complete(self, klass, text, line, begidx, endidx):
- return [obj.handle for obj in klass.objects.all() if obj.handle.startswith(text)]
+ return [obj.handle for obj in klass.objects.all() if obj.handle and obj.handle.startswith(text)]
def do_select_identity(self, arg):
"""
@@ -257,7 +250,7 @@ class main(rpki.cli.Cmd):
self.reset_identity()
def complete_select_identity(self, *args):
- return self.irdb_handle_complete(rpki.irdb.Identity, *args)
+ return self.irdb_handle_complete(rpki.irdb.CA, *args)
def do_initialize(self, arg):
@@ -271,23 +264,14 @@ class main(rpki.cli.Cmd):
if arg:
raise BadCommandSyntax, "This command takes no arguments"
- self.identity, created = rpki.irdb.Identity.objects.get_or_create(handle = self.handle)
+ self.resource_ca, created = rpki.irdb.CA.objects.get_or_certify(handle = self.handle)
if created:
- print 'Created new identity for "%s"' % self.handle
+ print "Created new BPKI resource CA for identity %s" % self.handle
- self.resource_ca, created = rpki.irdb.CA.objects.get_or_certify(
- identity = self.identity, purpose = "resources")
- if created:
- print "Created new BPKI resource CA"
-
- if not self.run_rpkid and not self.run_pubd and not self.run_rootd:
- self.server_ca = None
- else:
- self.server_ca, created = rpki.irdb.CA.objects.get_or_certify(
- identity = self.identity, purpose = "servers")
+ if self.run_rpkid or self.run_pubd or self.run_rootd:
+ self.server_ca, created = rpki.irdb.CA.objects.get_or_certify(handle = "")
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")
@@ -295,6 +279,8 @@ class main(rpki.cli.Cmd):
rpki.irdb.EECertificate.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")
+ if self.run_rootd:
+ rpki.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "rootd")
## @todo
# Why do we issue root's EE certificate under our server CA?
@@ -306,9 +292,6 @@ class main(rpki.cli.Cmd):
# -didn't- have to cross-certify. Leave alone for now, but
# think about this later.
- if self.run_rootd:
- rpki.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "rootd")
-
# Build the identity.xml file. Need to check for existing file so we don't
# overwrite? Worry about that later.
@@ -372,7 +355,7 @@ class main(rpki.cli.Cmd):
obj.avow()
for ca in rpki.irdb.CA.all():
- print "Regenerating CRL for", ca.identity.handle, ca.purpose
+ print "Regenerating CRL for", ca.handle if ca.handle else "[servers]"
ca.generate_crl()
def do_configure_child(self, arg):
@@ -885,16 +868,16 @@ class main(rpki.cli.Cmd):
action = "set",
bpki_crl = self.server_ca.latest_crl))
+ for ca in rpki.irdb.CA.objects.exclude(handle = ""):
- for xmlfile in xmlfiles:
-
-
- # Check for certificates before attempting anything else
-
- hosted_cacert = findbase64(tree, "bpki_ca_certificate")
- if not hosted_cacert:
- print "Nothing else I can do without a trust anchor for the entity I'm hosting."
- continue
+ # rpkid_xcert is the server CA cross-certifying this resource CA
+ # so that stuff trusted by this resource CA will validate for
+ # rpkid. The resource cross-certifies parents and children with
+ # PathLen 0 so that parent and child EE certs can be rolled;
+ # this cross-certification therefore needs to be PathLen 1.
+ #
+ # HostedCA class in models is an attempt to represent this.
+ # Not yet hacked into other code.
rpkid_xcert = rpki.x509.X509(PEM_file = self.bpki_servers.fxcert(
b64 = hosted_cacert.get_Base64(),
diff --git a/scripts/convert-from-entitydb-to-sql.py b/scripts/convert-from-entitydb-to-sql.py
index 1fae02c4..aa15b461 100644
--- a/scripts/convert-from-entitydb-to-sql.py
+++ b/scripts/convert-from-entitydb-to-sql.py
@@ -101,10 +101,6 @@ assert e.tag == tag_identity
self_handle = e.get("handle")
assert self_handle == cfg.get("handle", section = "myrpki")
-# Create identity if we haven't already
-
-identity = rpki.irdb.Identity.objects.get_or_create(handle = self_handle)[0]
-
# Some BPKI utillity routines
def read_openssl_serial(filename):
@@ -121,8 +117,7 @@ def get_or_create_CA(purpose):
crl_number = read_openssl_serial(os.path.join(bpki, purpose, "crl_number"))
return rpki.irdb.CA.objects.get_or_create(
- identity = identity,
- purpose = purpose,
+ handle = self_handle if purpose == "resources" else "",
certificate = cer,
private_key = key,
latest_crl = crl,
@@ -319,7 +314,7 @@ for filename in glob.iglob(os.path.join(entitydb, "parents", "*.xml")):
""", (self_handle, parent_handle))
for row in cur.fetchall():
rpki.irdb.GhostbusterRequest.objects.get_or_create(
- identity = identity,
+ issuer = resource_ca,
parent = parent,
vcard = row[0])
@@ -383,7 +378,7 @@ if copy_csv_data:
WHERE roa_request_handle = %s
""", (self_handle,))
for roa_request_id, asn in cur.fetchall():
- roa_request = rpki.irdb.ROARequest.objects.get_or_create(identity = identity, asn = asn)[0]
+ roa_request = rpki.irdb.ROARequest.objects.get_or_create(issuer = resource_ca, asn = asn)[0]
cur.execute("""
SELECT prefix, prefixlen, max_prefixlen, version FROM roa_request_prefix
WHERE roa_request_id = %s
@@ -404,7 +399,7 @@ if copy_csv_data:
""", (self_handle,))
for row in cur.fetchall():
rpki.irdb.GhostbusterRequest.objects.get_or_create(
- identity = identity,
+ issuer = resource_ca,
parent = None,
vcard = row[0])