aboutsummaryrefslogtreecommitdiff
path: root/rpkid/rpki/irdb/models.py
diff options
context:
space:
mode:
Diffstat (limited to 'rpkid/rpki/irdb/models.py')
-rw-r--r--rpkid/rpki/irdb/models.py646
1 files changed, 0 insertions, 646 deletions
diff --git a/rpkid/rpki/irdb/models.py b/rpkid/rpki/irdb/models.py
deleted file mode 100644
index 1ad9b4e3..00000000
--- a/rpkid/rpki/irdb/models.py
+++ /dev/null
@@ -1,646 +0,0 @@
-# $Id$
-#
-# Copyright (C) 2013--2014 Dragon Research Labs ("DRL")
-# Portions copyright (C) 2011--2012 Internet Systems Consortium ("ISC")
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notices and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND DRL AND ISC DISCLAIM ALL
-# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL OR
-# ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
-# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
-# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-"""
-Internet Registry (IR) Database, Django-style.
-
-This is the back-end code's interface to the database. It's intended
-to be usable by command line programs and other scripts, not just
-Django GUI code, so be careful.
-"""
-
-# pylint: disable=W0232
-
-import django.db.models
-import rpki.x509
-import rpki.sundial
-import rpki.resource_set
-import socket
-import rpki.POW
-from south.modelsinspector import add_introspection_rules
-
-## @var ip_version_choices
-# Choice argument for fields implementing IP version numbers.
-
-ip_version_choices = ((4, "IPv4"), (6, "IPv6"))
-
-## @var ca_certificate_lifetime
-# Lifetime for a BPKI CA certificate.
-
-ca_certificate_lifetime = rpki.sundial.timedelta(days = 3652)
-
-## @var crl_interval
-
-# Expected interval between BPKI CRL updates. This should be a little
-# longer than the real regeneration cycle, so that the old CRL will
-# not go stale while we're generating the new one. Eg, if we
-# regenerate daily, an interval of 24 hours is too short, but 25 hours
-# would be OK, as would 24 hours and 30 minutes.
-
-crl_interval = rpki.sundial.timedelta(hours = 25)
-
-## @var ee_certificate_lifetime
-# Lifetime for a BPKI EE certificate.
-
-ee_certificate_lifetime = rpki.sundial.timedelta(days = 60)
-
-###
-
-# Field types
-
-class HandleField(django.db.models.CharField):
- """
- A handle field type.
- """
-
- description = 'A "handle" in one of the RPKI protocols'
-
- def __init__(self, *args, **kwargs):
- 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.
- """
-
- description = "An enumeration type"
-
- __metaclass__ = django.db.models.SubfieldBase
-
- def __init__(self, *args, **kwargs):
- if isinstance(kwargs.get("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):
- """
- A field type for our customized datetime objects.
- """
- __metaclass__ = django.db.models.SubfieldBase
-
- description = "A datetime type using our customized datetime objects"
-
- def to_python(self, value):
- if isinstance(value, rpki.sundial.pydatetime.datetime):
- return rpki.sundial.datetime.from_datetime(
- django.db.models.DateTimeField.to_python(self, value))
- else:
- return value
-
- def get_prep_value(self, value):
- if isinstance(value, rpki.sundial.datetime):
- return value.to_datetime()
- else:
- return value
-
-
-class DERField(django.db.models.Field):
- """
- Field types for DER objects.
- """
-
- __metaclass__ = django.db.models.SubfieldBase
-
- def __init__(self, *args, **kwargs):
- kwargs["serialize"] = False
- kwargs["blank"] = True
- kwargs["default"] = None
- django.db.models.Field.__init__(self, *args, **kwargs)
-
- def db_type(self, connection):
- if connection.settings_dict['ENGINE'] == "django.db.backends.posgresql":
- return "bytea"
- else:
- return "BLOB"
-
- def to_python(self, value):
- assert value is None or isinstance(value, (self.rpki_type, str))
- if isinstance(value, str):
- return self.rpki_type(DER = value)
- else:
- return value
-
- def get_prep_value(self, value):
- assert value is None or isinstance(value, (self.rpki_type, str))
- if isinstance(value, self.rpki_type):
- return value.get_DER()
- else:
- return value
-
-class CertificateField(DERField):
- description = "X.509 certificate"
- rpki_type = rpki.x509.X509
-
-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
-
-class SignedReferralField(DERField):
- description = "CMS signed object containing XML"
- rpki_type = rpki.x509.SignedReferral
-
-
-# Custom managers
-
-class CertificateManager(django.db.models.Manager):
-
- def get_or_certify(self, **kwargs):
- """
- Sort of like .get_or_create(), but for models containing
- certificates which need to be generated based on other fields.
-
- Takes keyword arguments like .get(), checks for existing object.
- If none, creates a new one; if found an existing object but some
- of the non-key fields don't match, updates the existing object.
- Runs certification method for new or updated objects. Returns a
- tuple consisting of the object and a boolean indicating whether
- anything has changed.
- """
-
- changed = False
-
- try:
- obj = self.get(**self._get_or_certify_keys(kwargs))
-
- except self.model.DoesNotExist:
- obj = self.model(**kwargs)
- changed = True
-
- else:
- for k in kwargs:
- if getattr(obj, k) != kwargs[k]:
- setattr(obj, k, kwargs[k])
- changed = True
-
- if changed:
- obj.avow()
- obj.save()
-
- return obj, changed
-
- def _get_or_certify_keys(self, kwargs):
- assert len(self.model._meta.unique_together) == 1
- 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 ResourceHolderEEManager(CertificateManager):
- def _get_or_certify_keys(self, kwargs):
- return { "issuer" : kwargs["issuer"] }
-
-###
-
-class CA(django.db.models.Model):
- 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 = SundialField()
- next_crl_update = SundialField()
-
- class Meta:
- abstract = True
-
- def avow(self):
- if self.private_key is None:
- self.private_key = rpki.x509.RSA.generate(quiet = True)
- now = rpki.sundial.now()
- notAfter = now + ca_certificate_lifetime
- self.certificate = rpki.x509.X509.bpki_self_certify(
- keypair = self.private_key,
- subject_name = self.subject_name,
- serial = self.next_serial,
- now = now,
- notAfter = notAfter)
- self.next_serial += 1
- self.generate_crl()
- 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 = self.next_serial,
- now = now,
- notAfter = notAfter,
- is_ca = is_ca,
- pathLenConstraint = pathLenConstraint)
- self.next_serial += 1
- return result
-
- def revoke(self, cert):
- Revocation.objects.create(
- issuer = self,
- revoked = rpki.sundial.now(),
- serial = cert.certificate.getSerial(),
- expires = cert.certificate.getNotAfter() + crl_interval)
- cert.delete()
- self.generate_crl()
-
- def generate_crl(self):
- now = rpki.sundial.now()
- self.revocations.filter(expires__lt = now).delete()
- revoked = [(r.serial, r.revoked) for r in self.revocations.all()]
- self.latest_crl = rpki.x509.CRL.generate(
- keypair = self.private_key,
- issuer = self.certificate,
- serial = self.next_crl_number,
- thisUpdate = now,
- nextUpdate = now + crl_interval,
- revokedCertificates = revoked)
- self.last_crl_update = now
- self.next_crl_update = now + crl_interval
- self.next_crl_number += 1
-
-class ServerCA(CA):
- objects = ServerCAManager()
-
- def __unicode__(self):
- return ""
-
- @property
- def subject_name(self):
- if self.certificate is not None:
- return self.certificate.getSubject()
- else:
- return rpki.x509.X501DN.from_cn("%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):
- if self.certificate is not None:
- return self.certificate.getSubject()
- else:
- return rpki.x509.X501DN.from_cn("%s BPKI resource CA" % self.handle)
-
-class Certificate(django.db.models.Model):
-
- certificate = CertificateField()
- objects = CertificateManager()
-
- class Meta:
- abstract = True
- unique_together = ("issuer", "handle")
-
- def revoke(self):
- self.issuer.revoke(self)
-
-class CrossCertification(Certificate):
- handle = HandleField()
- ta = CertificateField()
-
- class Meta:
- abstract = True
-
- def avow(self):
- self.certificate = self.issuer.certify(
- subject_name = self.ta.getSubject(),
- subject_key = self.ta.getPublicKey(),
- validity_interval = ee_certificate_lifetime,
- is_ca = True,
- pathLenConstraint = 0)
-
- def __unicode__(self):
- return self.handle
-
-class HostedCA(Certificate):
- 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.certificate.getSubject(),
- subject_key = self.hosted.certificate.getPublicKey(),
- validity_interval = ee_certificate_lifetime,
- is_ca = True,
- pathLenConstraint = 1)
-
- class Meta:
- unique_together = ("issuer", "hosted")
-
- def __unicode__(self):
- return self.hosted.handle
-
-class Revocation(django.db.models.Model):
- 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):
- private_key = RSAKeyField()
-
- class Meta:
- abstract = True
-
- def avow(self):
- if self.private_key is None:
- self.private_key = rpki.x509.RSA.generate(quiet = True)
- self.certificate = self.issuer.certify(
- subject_name = self.subject_name,
- subject_key = self.private_key.get_public(),
- validity_interval = ee_certificate_lifetime,
- is_ca = False)
-
-class ServerEE(EECertificate):
- issuer = django.db.models.ForeignKey(ServerCA, related_name = "ee_certificates")
- purpose = EnumField(choices = ("rpkid", "pubd", "irdbd", "irbe"))
-
- class Meta:
- unique_together = ("issuer", "purpose")
-
- @property
- def subject_name(self):
- return rpki.x509.X501DN.from_cn("%s BPKI %s EE" % (socket.gethostname(),
- self.get_purpose_display()))
-
-class Referral(EECertificate):
- issuer = django.db.models.OneToOneField(ResourceHolderCA, related_name = "referral_certificate")
- objects = ResourceHolderEEManager()
-
- @property
- def subject_name(self):
- return rpki.x509.X501DN.from_cn("%s BPKI Referral EE" % self.issuer.handle)
-
-class Turtle(django.db.models.Model):
- service_uri = django.db.models.CharField(max_length = 255)
-
-class Rootd(EECertificate, Turtle):
- issuer = django.db.models.OneToOneField(ResourceHolderCA, related_name = "rootd")
- objects = ResourceHolderEEManager()
-
- @property
- def subject_name(self):
- return rpki.x509.X501DN.from_cn("%s BPKI rootd EE" % self.issuer.handle)
-
-class BSC(Certificate):
- 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(),
- validity_interval = ee_certificate_lifetime,
- is_ca = False)
-
- def __unicode__(self):
- return self.handle
-
-class ResourceSet(django.db.models.Model):
- valid_until = SundialField()
-
- class Meta:
- abstract = True
-
- @property
- def resource_bag(self):
- raw_asn, raw_net = self._select_resource_bag()
- asns = rpki.resource_set.resource_set_as.from_django(
- (a.start_as, a.end_as) for a in raw_asn)
- ipv4 = rpki.resource_set.resource_set_ipv4.from_django(
- (a.start_ip, a.end_ip) for a in raw_net if a.version == "IPv4")
- ipv6 = rpki.resource_set.resource_set_ipv6.from_django(
- (a.start_ip, a.end_ip) for a in raw_net if a.version == "IPv6")
- return rpki.resource_set.resource_bag(
- valid_until = self.valid_until, asn = asns, v4 = ipv4, v6 = ipv6)
-
- # Writing of .setter method deferred until something needs it.
-
-class ResourceSetASN(django.db.models.Model):
- start_as = django.db.models.BigIntegerField()
- end_as = django.db.models.BigIntegerField()
-
- class Meta:
- abstract = True
-
- def as_resource_range(self):
- return rpki.resource_set.resource_range_as(self.start_as, self.end_as)
-
-class ResourceSetNet(django.db.models.Model):
- start_ip = django.db.models.CharField(max_length = 40)
- end_ip = django.db.models.CharField(max_length = 40)
- version = EnumField(choices = ip_version_choices)
-
- class Meta:
- abstract = True
-
- def as_resource_range(self):
- return rpki.resource_set.resource_range_ip.from_strings(self.start_ip, self.end_ip)
-
-class Child(CrossCertification, ResourceSet):
- issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "children")
- name = django.db.models.TextField(null = True, blank = True)
-
- def _select_resource_bag(self):
- child_asn = rpki.irdb.ChildASN.objects.raw("""
- SELECT *
- FROM irdb_childasn
- WHERE child_id = %s
- """, [self.id])
- child_net = list(rpki.irdb.ChildNet.objects.raw("""
- SELECT *
- FROM irdb_childnet
- WHERE child_id = %s
- """, [self.id]))
- return child_asn, child_net
-
- class Meta:
- unique_together = ("issuer", "handle")
-
-class ChildASN(ResourceSetASN):
- child = django.db.models.ForeignKey(Child, related_name = "asns")
-
- class Meta:
- unique_together = ("child", "start_as", "end_as")
-
-class ChildNet(ResourceSetNet):
- child = django.db.models.ForeignKey(Child, related_name = "address_ranges")
-
- class Meta:
- unique_together = ("child", "start_ip", "end_ip", "version")
-
-class Parent(CrossCertification, Turtle):
- issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "parents")
- parent_handle = HandleField()
- child_handle = HandleField()
- repository_type = EnumField(choices = ("none", "offer", "referral"))
- referrer = HandleField(null = True, blank = True)
- referral_authorization = SignedReferralField(null = True, blank = True)
-
- # This shouldn't be necessary
- class Meta:
- unique_together = ("issuer", "handle")
-
-class ROARequest(django.db.models.Model):
- issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "roa_requests")
- asn = django.db.models.BigIntegerField()
-
- @property
- def roa_prefix_bag(self):
- prefixes = list(rpki.irdb.ROARequestPrefix.objects.raw("""
- SELECT *
- FROM irdb_roarequestprefix
- WHERE roa_request_id = %s
- """, [self.id]))
- v4 = rpki.resource_set.roa_prefix_set_ipv4.from_django(
- (p.prefix, p.prefixlen, p.max_prefixlen) for p in prefixes if p.version == "IPv4")
- v6 = rpki.resource_set.roa_prefix_set_ipv6.from_django(
- (p.prefix, p.prefixlen, p.max_prefixlen) for p in prefixes if p.version == "IPv6")
- return rpki.resource_set.roa_prefix_bag(v4 = v4, v6 = v6)
-
- # Writing of .setter method deferred until something needs it.
-
-class ROARequestPrefix(django.db.models.Model):
- roa_request = django.db.models.ForeignKey(ROARequest, related_name = "prefixes")
- 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()
-
- def as_roa_prefix(self):
- if self.version == 'IPv4':
- return rpki.resource_set.roa_prefix_ipv4(rpki.POW.IPAddress(self.prefix), self.prefixlen, self.max_prefixlen)
- else:
- return rpki.resource_set.roa_prefix_ipv6(rpki.POW.IPAddress(self.prefix), self.prefixlen, self.max_prefixlen)
-
- def as_resource_range(self):
- return self.as_roa_prefix().to_resource_range()
-
- class Meta:
- unique_together = ("roa_request", "version", "prefix", "prefixlen", "max_prefixlen")
-
-class GhostbusterRequest(django.db.models.Model):
- 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 EECertificateRequest(ResourceSet):
- issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "ee_certificate_requests")
- pkcs10 = PKCS10Field()
- gski = django.db.models.CharField(max_length = 27)
- cn = django.db.models.CharField(max_length = 64)
- sn = django.db.models.CharField(max_length = 64)
- eku = django.db.models.TextField(null = True)
-
- def _select_resource_bag(self):
- ee_asn = rpki.irdb.EECertificateRequestASN.objects.raw("""
- SELECT *
- FROM irdb_eecertificaterequestasn
- WHERE ee_certificate_request_id = %s
- """, [self.id])
- ee_net = rpki.irdb.EECertificateRequestNet.objects.raw("""
- SELECT *
- FROM irdb_eecertificaterequestnet
- WHERE ee_certificate_request_id = %s
- """, [self.id])
- return ee_asn, ee_net
-
- class Meta:
- unique_together = ("issuer", "gski")
-
-class EECertificateRequestASN(ResourceSetASN):
- ee_certificate_request = django.db.models.ForeignKey(EECertificateRequest, related_name = "asns")
-
- class Meta:
- unique_together = ("ee_certificate_request", "start_as", "end_as")
-
-class EECertificateRequestNet(ResourceSetNet):
- ee_certificate_request = django.db.models.ForeignKey(EECertificateRequest, related_name = "address_ranges")
-
- class Meta:
- unique_together = ("ee_certificate_request", "start_ip", "end_ip", "version")
-
-class Repository(CrossCertification):
- 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()
- turtle = django.db.models.OneToOneField(Turtle, related_name = "repository")
-
- # This shouldn't be necessary
- class Meta:
- unique_together = ("issuer", "handle")
-
-class Client(CrossCertification):
- issuer = django.db.models.ForeignKey(ServerCA, related_name = "clients")
- sia_base = django.db.models.TextField()
- parent_handle = HandleField()
-
- # This shouldn't be necessary
- class Meta:
- unique_together = ("issuer", "handle")
-
-# for Django South -- these are just simple subclasses
-add_introspection_rules([],
- ('^rpki\.irdb\.models\.CertificateField',
- '^rpki\.irdb\.models\.CRLField',
- '^rpki\.irdb\.models\.EnumField',
- '^rpki\.irdb\.models\.HandleField',
- '^rpki\.irdb\.models\.RSAKeyField',
- '^rpki\.irdb\.models\.SignedReferralField',
- '^rpki\.irdb\.models\.SundialField'))