aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2011-12-16 02:44:20 +0000
committerRob Austein <sra@hactrn.net>2011-12-16 02:44:20 +0000
commitbbde00990b0aae93d4b3d9fac8d163f66eca0c43 (patch)
tree1b51c35da1e247f0110bd0b39df1ce95f469a13f
parent3c52d332ed264fb6d5257c9cde787fc9fc0624c3 (diff)
Checkpoint. Add EnumField. Debug CertificateManager.
svn path=/branches/tk100/; revision=4124
-rw-r--r--rpkid/rpki/irdb/models.py115
-rw-r--r--rpkid/rpki/rpkic.py30
-rw-r--r--rpkid/rpki/x509.py10
-rw-r--r--scripts/convert-from-entitydb-to-sql.py6
4 files changed, 84 insertions, 77 deletions
diff --git a/rpkid/rpki/irdb/models.py b/rpkid/rpki/irdb/models.py
index 30f179b7..dbbc61a7 100644
--- a/rpkid/rpki/irdb/models.py
+++ b/rpkid/rpki/irdb/models.py
@@ -28,20 +28,6 @@ import rpki.sundial
###
-class ChoiceMap(dict):
- """
- Map construct to simplify enumerated types in Django models.
- """
-
- def __init__(self, *tags):
- dict.__init__(self)
- for i, tag in enumerate(tags, 1):
- self[tag] = i
-
- @property
- def choices(self):
- return tuple((y, x) for (x, y) in self.iteritems())
-
class HandleField(django.db.models.CharField):
"""
A handle field type.
@@ -51,6 +37,26 @@ class HandleField(django.db.models.CharField):
kwargs["max_length"] = 120
django.db.models.CharField.__init__(self, *args, **kwargs)
+class EnumField(django.db.models.PositiveSmallIntegerField):
+ """
+ An enumeration type that uses strings in Python and small integers
+ in SQL.
+ """
+
+ __metaclass__ = django.db.models.SubfieldBase
+
+ def __init__(self, *args, **kwargs):
+ if isinstance(kwargs["choices"], (tuple, list)) and isinstance(kwargs["choices"][0], str):
+ kwargs["choices"] = tuple(enumerate(kwargs["choices"], 1))
+ django.db.models.PositiveSmallIntegerField.__init__(self, *args, **kwargs)
+ self.enum_i2s = dict(self.flatchoices)
+ self.enum_s2i = dict((v, k) for k, v in self.flatchoices)
+
+ def to_python(self, value):
+ return self.enum_i2s.get(value, value)
+
+ def get_prep_value(self, value):
+ return self.enum_s2i.get(value, value)
class SundialField(django.db.models.DateTimeField):
"""
@@ -61,6 +67,12 @@ class SundialField(django.db.models.DateTimeField):
return rpki.sundial.datetime.fromdatetime(
django.db.models.DateTimeField.to_python(self, value))
+ def get_prep_value(self, value):
+ if isinstance(value, rpki.sundial.datetime):
+ return value.to_sql()
+ else:
+ return value
+
class DERField(django.db.models.Field):
"""
A field type for DER objects.
@@ -118,17 +130,10 @@ class SignedReferralField(DERField):
description = "CMS signed object containing XML"
rpki_type = rpki.x509.SignedReferral
-## @var ip_version_map
-# Custom choice map for IP version enumerations, so we can use the
-# obvious numeric values in the database, which is a bit easier on
-# anybody reading the raw SQL.
-#
-ip_version_map = { "IPv4" : 4, "IPv6" : 6 }
-
## @var ip_version_choices
# Choice argument for fields implementing IP version numbers.
-#
-ip_version_choices = tuple((y, x) for (x, y) in ip_version_map.iteritems())
+
+ip_version_choices = ((4, "IPv4"), (6, "IPv6"))
class CertificateManager(django.db.models.Manager):
@@ -144,25 +149,30 @@ class CertificateManager(django.db.models.Manager):
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
+ 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))
+ obj = self.get(**dict((k, kwargs[k]) for k in self.model._meta.unique_together[0]))
except self.model.DoesNotExist:
obj = self.model(**kwargs)
+ changed = True
else:
- if all(getattr(obj, k) == kwargs[k] for k in kwargs):
- return obj, False
for k in kwargs:
- setattr(obj, k, kwargs[k])
+ if getattr(obj, k) != kwargs[k]:
+ setattr(obj, k, kwargs[k])
+ changed = True
+
+ if changed:
+ obj.avow()
+ obj.save()
- obj.avow()
- obj.save()
- return obj, True
+ return obj, changed
###
@@ -171,8 +181,7 @@ class Identity(django.db.models.Model):
class CA(django.db.models.Model):
identity = django.db.models.ForeignKey(Identity)
- purpose_map = ChoiceMap("resources", "servers")
- purpose = django.db.models.PositiveSmallIntegerField(choices = purpose_map.choices)
+ purpose = EnumField(choices = ("resources", "servers"))
certificate = CertificateField()
private_key = RSAKeyField()
latest_crl = CRLField()
@@ -183,8 +192,8 @@ class CA(django.db.models.Model):
next_serial = django.db.models.BigIntegerField(default = 1)
next_crl_number = django.db.models.BigIntegerField(default = 1)
- last_crl_update = django.db.models.DateTimeField()
- next_crl_update = django.db.models.DateTimeField()
+ last_crl_update = SundialField()
+ next_crl_update = SundialField()
objects = CertificateManager()
@@ -208,7 +217,7 @@ class CA(django.db.models.Model):
serial = self.next_serial,
now = now,
notAfter = notAfter)
- self.serial += 1
+ self.next_serial += 1
self.generate_crl()
return self.certificate
@@ -224,7 +233,7 @@ class CA(django.db.models.Model):
notAfter = notAfter,
is_ca = is_ca,
pathLenConstraint = pathLenConstraint)
- self.serial += 1
+ self.next_serial += 1
return result
def revoke(self, cert):
@@ -240,14 +249,14 @@ class CA(django.db.models.Model):
now = rpki.sundial.now()
self.revocations.filter(expires__lt = now).delete()
revoked = [(r.serial, rpki.sundial.datetime.fromdatetime(r.revoked).toASN1tuple(), ())
- for r in self.revocations]
+ for r in self.revocations.all()]
self.latest_crl = rpki.x509.CRL.generate(
keypair = self.private_key,
- issuer = self.certificate.getSubject(),
+ issuer = self.certificate,
serial = self.next_crl_number,
thisUpdate = now,
nextUpdate = now + self.crl_interval,
- revoked_certificates = revoked)
+ revokedCertificates = revoked)
self.last_crl_update = now
self.next_crl_update = now + self.crl_interval
self.next_crl_number += 1
@@ -285,16 +294,15 @@ class CrossCertification(Certificate):
class Revocation(django.db.models.Model):
issuer = django.db.models.ForeignKey(CA, related_name = "revocations")
serial = django.db.models.BigIntegerField()
- revoked = django.db.models.DateTimeField()
- expires = django.db.models.DateTimeField()
+ revoked = SundialField()
+ expires = SundialField()
class Meta:
unique_together = ("issuer", "serial")
class EECertificate(Certificate):
issuer = django.db.models.ForeignKey(CA, related_name = "ee_certificates")
- purpose_map = ChoiceMap("rpkid", "pubd", "irdbd", "irbe", "rootd", "referral")
- purpose = django.db.models.PositiveSmallIntegerField(choices = purpose_map.choices)
+ purpose = EnumField(choices = ("rpkid", "pubd", "irdbd", "irbe", "rootd", "referral"))
private_key = RSAKeyField()
class Meta:
@@ -306,10 +314,10 @@ class EECertificate(Certificate):
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)
+ subject_name = subject_name,
+ subject_key = self.private_key.get_RSApublic(),
+ validity_interval = self.default_interval,
+ is_ca = False)
class BSC(Certificate):
issuer = django.db.models.ForeignKey(CA, related_name = "bscs")
@@ -329,7 +337,7 @@ class BSC(Certificate):
class Child(CrossCertification):
issuer = django.db.models.ForeignKey(CA, related_name = "children")
name = django.db.models.TextField(null = True, blank = True)
- valid_until = django.db.models.DateTimeField()
+ valid_until = SundialField()
class ChildASN(django.db.models.Model):
child = django.db.models.ForeignKey(Child, related_name = "asns")
@@ -343,8 +351,7 @@ class ChildNet(django.db.models.Model):
child = django.db.models.ForeignKey(Child, related_name = "address_ranges")
start_ip = django.db.models.CharField(max_length = 40)
end_ip = django.db.models.CharField(max_length = 40)
- version_map = ip_version_map
- version = django.db.models.PositiveSmallIntegerField(choices = ip_version_choices)
+ version = EnumField(choices = ip_version_choices)
class Meta:
unique_together = ("child", "start_ip", "end_ip", "version")
@@ -354,8 +361,7 @@ class Parent(CrossCertification):
parent_handle = HandleField()
child_handle = HandleField()
service_uri = django.db.models.CharField(max_length = 255)
- repository_type_map = ChoiceMap("none", "offer", "referral")
- repository_type = django.db.models.PositiveSmallIntegerField(choices = repository_type_map.choices)
+ repository_type = EnumField(choices = ("none", "offer", "referral"))
referrer = HandleField(null = True, blank = True)
referral_authorization = SignedReferralField(null = True, blank = True)
@@ -365,8 +371,7 @@ class ROARequest(django.db.models.Model):
class ROARequestPrefix(django.db.models.Model):
roa_request = django.db.models.ForeignKey(ROARequest, related_name = "prefixes")
- version_map = ip_version_map
- version = django.db.models.PositiveSmallIntegerField(choices = ip_version_choices)
+ version = EnumField(choices = ip_version_choices)
prefix = django.db.models.CharField(max_length = 40)
prefixlen = django.db.models.PositiveSmallIntegerField()
max_prefixlen = django.db.models.PositiveSmallIntegerField()
diff --git a/rpkid/rpki/rpkic.py b/rpkid/rpki/rpkic.py
index 4aeeb100..43809d80 100644
--- a/rpkid/rpki/rpkic.py
+++ b/rpkid/rpki/rpkic.py
@@ -359,17 +359,17 @@ class main(rpki.cli.Cmd):
self.identity = rpki.irdb.Identity.objects.get(handle = self.handle)
except rpki.irdb.Identity.DoesNotExist:
self.identity = None
+ self.resource_ca = None
+ 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
- if self.run_rpkid or self.run_pubd or self.run_rootd:
- try:
- self.server_ca = self.identity.ca_set(purpose = "servers")
- except rpki.irdb.CA.DoesNotExist:
- self.server_ca = None
-
+ try:
+ self.server_ca = self.identity.ca_set.get(purpose = "servers")
+ except rpki.irdb.CA.DoesNotExist:
+ self.server_ca = None
def do_initialize(self, arg):
"""
@@ -386,24 +386,26 @@ class main(rpki.cli.Cmd):
if created:
print 'Created new identity for "%s"' % self.handle
- self.resource_ca, created = rpki.irdb.CA.objects.get_or_certify(identity = self.identity, purpose = "resources")
+ 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")
+ self.server_ca, created = rpki.irdb.CA.objects.get_or_certify(
+ identity = self.identity, purpose = "servers")
if created:
print "Created new BPKI server CA"
if self.run_rpkid:
- self.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "rpkid")
- self.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "irdbd")
+ 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")
if self.run_pubd:
- self.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "pubd")
+ rpki.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "pubd")
if self.run_rpkid or self.run_pubd:
- self.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "irbe")
+ rpki.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "irbe")
## @todo
# Why do we issue root's EE certificate under our server CA?
@@ -416,7 +418,7 @@ class main(rpki.cli.Cmd):
# think about this later.
if self.run_rootd:
- self.irdb.EECertificate.objects.get_or_certify(issuer = self.server_ca, purpose = "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.
@@ -621,7 +623,7 @@ class main(rpki.cli.Cmd):
parent_handle = p.get("parent_handle"),
service_uri = p.get("service_uri"),
ta = rpki.x509.X509(Base64 = p.findtext("bpki_resource_ta")),
- repository_type = rpki.irdb.Parent.repository_type_map[repository_type],
+ repository_type = repository_type,
referrer = referrer,
referral_authorization = referral_authorization)[0]
diff --git a/rpkid/rpki/x509.py b/rpkid/rpki/x509.py
index b5300bee..bccdce03 100644
--- a/rpkid/rpki/x509.py
+++ b/rpkid/rpki/x509.py
@@ -166,14 +166,14 @@ class X501DN(object):
assert ini is None or not kwargs
if len(kwargs) == 1 and "CN" in kwargs:
ini = kwargs.pop("CN")
- if isinstance(ini, str):
- self.dn = (((rpki.oids.name2oid["commonName"], ("printableString", cn)),),)
+ if isinstance(ini, (str, unicode)):
+ self.dn = (((rpki.oids.name2oid["commonName"], ("printableString", ini)),),)
elif isinstance(ini, tuple):
self.dn = ini
elif kwargs:
- raise NotImplementedError #("Sorry, I haven't implemented keyword arguments yet")
+ raise NotImplementedError("Sorry, I haven't implemented keyword arguments yet")
elif ini is not None:
- raise TypeError #("Don't know how to interpret %r as an X.501 DN" % (ini,), ini)
+ raise TypeError("Don't know how to interpret %r as an X.501 DN" % (ini,), ini)
def __str__(self):
return "".join("/" + "+".join("%s=%s" % (rpki.oids.oid2name[a[0]], a[1][1])
@@ -187,7 +187,7 @@ class X501DN(object):
return self.dn
def get_POW(self):
- raise NotImplementedError #("Sorry, I haven't written the conversion to POW format yet")
+ raise NotImplementedError("Sorry, I haven't written the conversion to POW format yet")
class DER_object(object):
"""
diff --git a/scripts/convert-from-entitydb-to-sql.py b/scripts/convert-from-entitydb-to-sql.py
index bea12e84..d0a080e9 100644
--- a/scripts/convert-from-entitydb-to-sql.py
+++ b/scripts/convert-from-entitydb-to-sql.py
@@ -121,7 +121,7 @@ def get_or_create_CA(purpose):
return rpki.irdb.CA.objects.get_or_create(
identity = identity,
- purpose = rpki.irdb.CA.purpose_map[purpose],
+ purpose = purpose,
certificate = cer,
private_key = key,
latest_crl = crl,
@@ -135,7 +135,7 @@ def get_or_create_EECertificate(issuer, capurpose, eepurpose):
key = rpki.x509.RSA(Auto_file = os.path.join(bpki, capurpose, eepurpose + ".key"))
rpki.irdb.EECertificate.objects.get_or_create(
issuer = issuer,
- purpose = rpki.irdb.EECertificate.purpose_map[eepurpose],
+ purpose = eepurpose,
certificate = cer,
private_key = key)
@@ -301,7 +301,7 @@ for filename in glob.iglob(os.path.join(entitydb, "parents", "*.xml")):
child_handle = e.get("child_handle"),
ta = ta,
certificate = xcert,
- repository_type = rpki.irdb.Parent.repository_type_map[repository_type],
+ repository_type = repository_type,
referrer = referrer,
referral_authorization = referral_authorization,
issuer = resource_ca)[0]