diff options
author | Rob Austein <sra@hactrn.net> | 2011-12-16 02:44:20 +0000 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2011-12-16 02:44:20 +0000 |
commit | bbde00990b0aae93d4b3d9fac8d163f66eca0c43 (patch) | |
tree | 1b51c35da1e247f0110bd0b39df1ce95f469a13f | |
parent | 3c52d332ed264fb6d5257c9cde787fc9fc0624c3 (diff) |
Checkpoint. Add EnumField. Debug CertificateManager.
svn path=/branches/tk100/; revision=4124
-rw-r--r-- | rpkid/rpki/irdb/models.py | 115 | ||||
-rw-r--r-- | rpkid/rpki/rpkic.py | 30 | ||||
-rw-r--r-- | rpkid/rpki/x509.py | 10 | ||||
-rw-r--r-- | scripts/convert-from-entitydb-to-sql.py | 6 |
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] |