aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rpkid/rpki/irdb/models.py145
-rw-r--r--rpkid/rpki/x509.py6
-rw-r--r--scripts/convert-from-entitydb-to-sql.py38
3 files changed, 125 insertions, 64 deletions
diff --git a/rpkid/rpki/irdb/models.py b/rpkid/rpki/irdb/models.py
index 3a898d8d..1a4fdbd0 100644
--- a/rpkid/rpki/irdb/models.py
+++ b/rpkid/rpki/irdb/models.py
@@ -24,6 +24,7 @@ PERFORMANCE OF THIS SOFTWARE.
import django.db.models
import rpki.x509
+import rpki.sundial
###
@@ -98,6 +99,10 @@ class RSAKeyField(DERField):
description = "RSA keypair"
rpki_type = rpki.x509.RSA
+class CRLField(DERField):
+ description = "Certificate Revocation List"
+ rpki_type = rpki.x509.CRL
+
class PKCS10Field(DERField):
description = "PKCS #10 certificate request"
rpki_type = rpki.x509.PKCS10
@@ -145,6 +150,14 @@ class CA(django.db.models.Model):
identity = django.db.models.ForeignKey(Identity, related_name = "bpki_certificates")
purpose_map = ChoiceMap("resources", "servers")
purpose = django.db.models.PositiveSmallIntegerField(choices = purpose_map.choices)
+ certificate = CertificateField()
+ private_key = RSAKeyField()
+ latest_crl = CRLField()
+
+ # Might want to bring these into line with what rpkid does. Current
+ # variables here were chosen to map easily to what OpenSSL command
+ # line tool was keeping on disk.
+
next_serial = django.db.models.BigIntegerField(default = 1)
next_crl_number = django.db.models.BigIntegerField(default = 1)
last_crl_update = django.db.models.DateTimeField()
@@ -153,55 +166,71 @@ class CA(django.db.models.Model):
class Meta:
unique_together = ("identity", "purpose")
-class Certificate(django.db.models.Model):
-
- certificate = CertificateField()
-
- class Meta:
- abstract = True
-
- def generate_certificate(self):
-
- # This is sort of vaguely the right idea, but most of it probably
- # ought to be a method of the CA, not the object being certified,
- # and the rest doesn't yet cover all the different kinds of
- # certificates we need to support.
-
- # Perhaps something where each specialized class has its own
- # generate_certificate() method which is mostly just a wrapper for
- # a call to the CA object with the right parameters to get the CA
- # to issue the certificate. Seems about right. Not awake enough
- # to write it now.
-
- # This doesn't handle self-certification yet either.
- # Self-certification may be different enough that we want to move
- # the certificate and keypair back to the CA object, since we have
- # to special-case it no matter what we do.
-
- cacert = self.issuer.keyed_certificates.filter(purpose = KeyedCertificate.purpose_map["ca"])
- subject_name, subject_key = self.get_certificate_subject()
- cer = cacert.certificate
- key = cacert.private_key
-
- result = cer.bpki_certify(
- keypair = key,
+ # 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 self_certify(self):
+ subject_name = rpki.x509.X501DN("%s BPKI %s CA" % (
+ self.identity.handle, self.get_purpose_display()))
+ 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,
+ serial = self.next_serial,
+ now = now,
+ notAfter = notAfter)
+ self.serial += 1
+ return self.certificate
+
+ def certify(self, subject_name, subject_key, validity_interval, is_ca, pathLenConstraint = None):
+ now = rpki.sundial.now()
+ notAfter = now + validity_interval
+ result = self.certificate.bpki_certify(
+ keypair = self.private_key,
subject_name = subject_name,
subject_key = subject_key,
- serial = ca.next_serial,
-
- # This needs to be configurable
- notAfter = rpki.sundial.now() + rpki.sundial.timedelta(days = 60),
+ serial = self.next_serial,
+ now = now,
+ notAfter = notAfter,
+ is_ca = is_ca,
+ pathLenConstraint = pathLenConstraint)
+ self.serial += 1
+ return result
+
+ def revoke(self, cert):
+ Revocations.objects.create(
+ issuer = self,
+ revoked = rpki.sundial.now(),
+ serial = cert.certificate.getSerial(),
+ expires = cert.certificate.getNotAfter() + self.crl_interval)
+ cert.delete()
+ self.generate_crl()
+
+ def generate_crl(self):
+ now = rpki.sundial.now()
+ self.revocations.filter(expires__lt = now).delete()
+ revoked_certificates = [(r.serial, rpki.sundial.datetime.fromdatetime(r.revoked).toASN1tuple(), ())
+ for r in self.revocations]
+ self.latest_crl = rpki.x509.CRL.generate(
+ keypair = self.private_key,
+ issuer = self.certificate.getSubject(),
+ thisUpdate = now,
+ nextUpdate = now + self.crl_interval,
+ revoked_certificates = revoked_certificates)
- # This is (at least) per-class, not universal
- pathLenConstraint = 0,
- # This is per-class too
- is_ca = True)
+class Certificate(django.db.models.Model):
+ certificate = CertificateField()
- self.ca.next_serial += 1
+ default_interval = rpki.sundial.timedelta(days = 60)
- self.certificate = result
+ class Meta:
+ abstract = True
+ def revoke(self):
+ self.ca.revoke(self)
class CrossCertification(Certificate):
@@ -212,8 +241,14 @@ class CrossCertification(Certificate):
abstract = True
unique_together = ("issuer", "handle")
- def get_certificate_subject(self):
- return self.certificate.getSubject(), self.certificate.getPublicKey()
+ def generate_certificate(self):
+ self.certificate = self.issuer.certify(
+ subject_name = self.ta.getSubject(),
+ subject_key = self.ta.getPublicKey(),
+ interval = self.default_interval,
+ is_ca = True,
+ pathLenConstraint = 0)
+
class Revocation(django.db.models.Model):
issuer = django.db.models.ForeignKey(CA, related_name = "revocations")
@@ -224,15 +259,24 @@ class Revocation(django.db.models.Model):
class Meta:
unique_together = ("issuer", "serial")
-class KeyedCertificate(Certificate):
- issuer = django.db.models.ForeignKey(CA, related_name = "keyed_certificates")
- purpose_map = ChoiceMap("ca", "rpkid", "pubd", "irdbd", "irbe", "rootd")
+class EECertificate(Certificate):
+ issuer = django.db.models.ForeignKey(CA, related_name = "ee_certificates")
+ purpose_map = ChoiceMap("rpkid", "pubd", "irdbd", "irbe", "rootd")
purpose = django.db.models.PositiveSmallIntegerField(choices = purpose_map.choices)
private_key = RSAKeyField()
class Meta:
unique_together = ("issuer", "purpose")
+ def generate_certificate(self):
+ subject_name = rpki.x509.X501DN("%s BPKI %s EE" % (
+ self.issuer.identity.handle, self.get_purpose_display()))
+ self.certificate = self.issuer.certify(
+ subject_name = subject_name,
+ subject_key = self.private_key.getPublicKey(),
+ interval = self.default_interval,
+ is_ca = False)
+
class BSC(Certificate):
issuer = django.db.models.ForeignKey(CA, related_name = "bscs")
handle = HandleField()
@@ -241,6 +285,13 @@ class BSC(Certificate):
class Meta:
unique_together = ("issuer", "handle")
+ def generate_certificate(self):
+ self.certificate = self.issuer.certify(
+ subject_name = self.pkcs10.getSubject(),
+ subject_key = self.pkcs10.getPublicKey(),
+ interval = self.default_interval,
+ is_ca = False)
+
class Child(CrossCertification):
issuer = django.db.models.ForeignKey(CA, related_name = "children")
name = django.db.models.TextField(null = True, blank = True)
diff --git a/rpkid/rpki/x509.py b/rpkid/rpki/x509.py
index 2011b416..2d5505d5 100644
--- a/rpkid/rpki/x509.py
+++ b/rpkid/rpki/x509.py
@@ -761,6 +761,12 @@ class PKCS10(DER_object):
self.POWpkix = req
return self.POWpkix
+ def getSubject(self):
+ """
+ Extract the subject name from this certification request.
+ """
+ return X501DN(self.get_POWpkix().certificationRequestInfo.subject.get())
+
def getPublicKey(self):
"""
Extract the public key from this certification request.
diff --git a/scripts/convert-from-entitydb-to-sql.py b/scripts/convert-from-entitydb-to-sql.py
index 8885893b..1ab5201d 100644
--- a/scripts/convert-from-entitydb-to-sql.py
+++ b/scripts/convert-from-entitydb-to-sql.py
@@ -113,30 +113,35 @@ def read_openssl_serial(filename):
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(identity = identity,
- purpose = rpki.irdb.CA.purpose_map[purpose],
- 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_KeyedCertificate(issuer, purpose):
+ return rpki.irdb.CA.objects.get_or_create(
+ identity = identity,
+ purpose = rpki.irdb.CA.purpose_map[purpose],
+ 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, 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.KeyedCertificate.objects.get_or_create(
+ rpki.irdb.EECertificate.objects.get_or_create(
issuer = issuer,
- purpose = rpki.irdb.KeyedCertificate.purpose_map[purpose],
+ purpose = rpki.irdb.EECertificate.purpose_map[purpose],
certificate = cer,
private_key = key)
# Load BPKI CA data
resource_ca = get_or_create_CA("resources")
-get_or_create_KeyedCertificate(resource_ca, "ca")
# Load BPKI server EE certificates and keys
@@ -145,15 +150,14 @@ run_flags = dict((i, cfg.getboolean(i, section = "myrpki"))
if any(run_flags.itervalues()):
server_ca = get_or_create_CA("servers")
- get_or_create_KeyedCertificate(server_ca, "ca")
- get_or_create_KeyedCertificate(server_ca, "irbe")
+ get_or_create_EECertificate(server_ca, "irbe")
if run_flags["run_rpkid"]:
- get_or_create_KeyedCertificate(server_ca, "rpkid")
- get_or_create_KeyedCertificate(server_ca, "irdbd")
+ get_or_create_EECertificate(server_ca, "rpkid")
+ get_or_create_EECertificate(server_ca, "irdbd")
if run_flags["run_pubd"]:
- get_or_create_KeyedCertificate(server_ca, "pubd")
+ get_or_create_EECertificate(server_ca, "pubd")
if run_flags["run_rootd"]:
- get_or_create_KeyedCertificate(server_ca, "rootd")
+ get_or_create_EECertificate(server_ca, "rootd")
else:
server_ca = None