aboutsummaryrefslogtreecommitdiff
path: root/rpkid
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2014-01-26 19:19:39 +0000
committerRob Austein <sra@hactrn.net>2014-01-26 19:19:39 +0000
commit2edf966870ae87327c381d4091178aa025ff09ff (patch)
tree44cc0d8f8dde15c1503cfead21a1e8d68251c088 /rpkid
parent3bc8ab851de7d5be2b9c6258de56c0cf41634f0e (diff)
Checkpoint.
svn path=/branches/tk671/; revision=5646
Diffstat (limited to 'rpkid')
-rw-r--r--rpkid/rpki/exceptions.py10
-rw-r--r--rpkid/rpki/irdb/models.py16
-rw-r--r--rpkid/rpki/irdb/zookeeper.py52
-rw-r--r--rpkid/rpki/x509.py63
4 files changed, 124 insertions, 17 deletions
diff --git a/rpkid/rpki/exceptions.py b/rpkid/rpki/exceptions.py
index d390d67b..7a0eb71c 100644
--- a/rpkid/rpki/exceptions.py
+++ b/rpkid/rpki/exceptions.py
@@ -350,3 +350,13 @@ class NullValidityInterval(RPKI_Exception):
"""
Requested validity interval is null.
"""
+
+class BadX510DN(RPKI_Exception):
+ """
+ X.510 distinguished name does not match profile.
+ """
+
+class BadAutonomousSystemNumber(RPKI_Exception):
+ """
+ Bad AutonomousSystem number.
+ """
diff --git a/rpkid/rpki/irdb/models.py b/rpkid/rpki/irdb/models.py
index 03b6643c..3553581e 100644
--- a/rpkid/rpki/irdb/models.py
+++ b/rpkid/rpki/irdb/models.py
@@ -581,10 +581,22 @@ class GhostbusterRequest(django.db.models.Model):
class EECertificateRequest(ResourceSet):
issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "ee_certificate_requests")
- router_id = django.db.models.BigIntegerField(null = True)
pkcs10 = PKCS10Field()
gski = django.db.models.CharField(max_length = 27)
-
+
+ # At one point I had a router_id field here, but I don't think it
+ # serves any real purpose. Put it back if I remember why I thought
+ # we needed it, but the current I-D has router-id encoded in teh
+ # subject name.
+
+ # Need subject name field here? It's in the PKCS #10, but then so
+ # is the public key from which we generate the g(SKI); question is
+ # whether we need to use the subject name or just transport it.
+ #
+ # I guess we could have left-right XML attributes corresponding to
+ # X.509 commonName and serialNumber if necessary, question is whether
+ # this is necessary.
+
def _select_resource_bag(self):
ee_asn = rpki.irdb.EECertificateRequestASN.objects.raw("""
SELECT *
diff --git a/rpkid/rpki/irdb/zookeeper.py b/rpkid/rpki/irdb/zookeeper.py
index 1c2d2d16..bb52bddd 100644
--- a/rpkid/rpki/irdb/zookeeper.py
+++ b/rpkid/rpki/irdb/zookeeper.py
@@ -1586,3 +1586,55 @@ class Zookeeper(object):
if rpkid_query:
rpkid_reply = self.call_rpkid(rpkid_query)
self.check_error_report(rpkid_reply)
+
+
+ @django.db.transaction.commit_on_success
+ def add_ee_certificate_request(self, pkcs10, resources):
+ """
+ Check a PKCS #10 request to see if it complies with the
+ specification for a RPKI EE certificate; if it does, add an
+ EECertificateRequest for it to the IRDB.
+
+ Not yet sure what we want for update and delete semantics here, so
+ for the moment this is straight addition. See methods like
+ .load_asns() and .load_prefixes() for other strategies.
+ """
+
+ pkcs10.check_valid_rpki(ee = True)
+ ee_request = self.resource_ca.ee_certificate_requests.create(
+ pkcs10 = pkcs10,
+ gski = pkcs10.gSKI(),
+ valid_until = resources.valid_until)
+ for range in resources.asn:
+ ee_request.asns.create(start_as = str(range.min), end_as = str(range.max))
+ for range in resources.v4:
+ ee_request.address_ranges.create(start_ip = str(range.min), end_ip = str(range.max), version = 4)
+ for range in resources.v6:
+ ee_request.address_ranges.create(start_ip = str(range.min), end_ip = str(range.max), version = 6)
+
+
+ def add_router_certificate_request(self, pkcs10, asn):
+ """
+ Check a PKCS #10 request to see if it complies with the
+ specification for a router certificate; if it does, create an EE
+ certificate request for it along with a specified ASN.
+ """
+
+ if isinstance(asn, (str, unicode)):
+ asn = long(asn)
+ if not isinstance(asn, (int, long)) or asn < 0 or asn > 0xFFFFFFFF:
+ raise rpki.exceptions.BadAutonomousSystemNumber("Bad AutonomousSystem number: %s" % asn)
+
+ # This attempts to enforce draft-ietf-sidr-bgpsec-pki-profiles-06
+ # section 3.1.1.1, which may be a mistake, too early to tell.
+ cn, sn = pkcs10.getSubject().extract_cn_and_sn()
+ if not cn.startswith("ROUTER-") \
+ or len(cn) != 7 + 8 \
+ or not cn[7:].isalnum() \
+ or int(cn[7:], 16) != asn \
+ or not sn.isalnum() \
+ or len(sn) != 8 \
+ or int(sn, 16) > 0xFFFFFFFF:
+ raise rpki.exceptions.BadX510DN("Subject name doesn't match router profile: %s" % pkcs10.getSubject())
+
+ raise NotImplementedError, "Not finished"
diff --git a/rpkid/rpki/x509.py b/rpkid/rpki/x509.py
index 5475a452..2e09cb35 100644
--- a/rpkid/rpki/x509.py
+++ b/rpkid/rpki/x509.py
@@ -161,6 +161,30 @@ class X501DN(object):
def get_POW(self):
return self.dn
+ def extract_cn_and_sn(self):
+ cn = None
+ sn = None
+
+ for rdn in self.dn:
+ if len(rdn) == 1 and len(rdn[0]) == 2:
+ oid = rpki.oids.safe_dotted2name(rdn[0][0])
+ val = rdn[0][1]
+ print "OID:", oid
+ print "Val:", val
+ if oid == "commonName" and cn is None:
+ cn = val
+ continue
+ if oid == "serialNumber" and sn is None:
+ sn = val
+ continue
+ raise rpki.exceptions.BadX510DN("Bad subject name: %s" % (self.dn,))
+
+ if cn is None:
+ raise rpki.exceptions.BadX510DN("Subject name is missing CN: %s" % (self.dn,))
+
+ return cn, sn
+
+
class DER_object(object):
"""
Virtual class to hold a generic DER object.
@@ -875,7 +899,13 @@ class PKCS10(DER_object):
"""
return RSApublic(POW = self.get_POW().getPublicKey())
- def check_valid_rpki(self):
+ def get_SKI(self):
+ """
+ Compute SKI for public key from this certification request.
+ """
+ return self.getPublicKey().get_SKI()
+
+ def check_valid_rpki(self, ee = False):
"""
Check this certification request to see whether it's a valid
request for an RPKI certificate. This is broken out of the
@@ -890,18 +920,21 @@ class PKCS10(DER_object):
RPKI profile only allows EKU for EE certificates.
"""
+ if ee:
+ raise NotImplementedError("Haven't written EE-certificate checking yet, oops")
+
if not self.get_POW().verify():
- raise rpki.exceptions.BadPKCS10("Signature check failed")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 signature check failed")
ver = self.get_POW().getVersion()
if ver != 0:
- raise rpki.exceptions.BadPKCS10("Bad version number %s" % ver)
+ raise rpki.exceptions.BadPKCS10("PKCS #10 request has bad version number %s" % ver)
alg = rpki.oids.safe_dotted2name(self.get_POW().getSignatureAlgorithm())
if alg != "sha256WithRSAEncryption":
- raise rpki.exceptions.BadPKCS10("Bad signature algorithm %s" % alg)
+ raise rpki.exceptions.BadPKCS10("PKCS #10 request has bad signature algorithm %s" % alg)
bc = self.get_POW().getBasicConstraints()
@@ -909,44 +942,44 @@ class PKCS10(DER_object):
raise rpki.exceptions.BadPKCS10("Request for EE certificate not allowed here")
if bc[1] is not None:
- raise rpki.exceptions.BadPKCS10("basicConstraints must not specify Path Length")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 basicConstraints must not specify Path Length")
ku = self.get_POW().getKeyUsage()
if ku is not None and self.expected_ca_keyUsage != ku:
- raise rpki.exceptions.BadPKCS10("keyUsage doesn't match basicConstraints: %r" % ku)
+ raise rpki.exceptions.BadPKCS10("PKCS #10 keyUsage doesn't match basicConstraints: %r" % ku)
if any(oid not in self.allowed_extensions
for oid in self.get_POW().getExtensionOIDs()):
- raise rpki.exceptions.BadExtension("Forbidden extension(s) in certificate request")
+ raise rpki.exceptions.BadExtension("Forbidden extension(s) in PKCS #10 certificate request")
sias = self.get_POW().getSIA()
if sias is None:
- raise rpki.exceptions.BadPKCS10("Certificate request is missing SIA extension")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 is missing SIA extension")
caRepository, rpkiManifest, signedObject = sias
if signedObject:
- raise rpki.exceptions.BadPKCS10("CA certificate request has SIA id-ad-signedObject")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request has SIA id-ad-signedObject")
if not caRepository:
- raise rpki.exceptions.BadPKCS10("Certificate request is missing SIA id-ad-caRepository")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request is missing SIA id-ad-caRepository")
if not any(uri.startswith("rsync://") for uri in caRepository):
- raise rpki.exceptions.BadPKCS10("Certificate request SIA id-ad-caRepository contains no rsync URIs")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request SIA id-ad-caRepository contains no rsync URIs")
if not rpkiManifest:
- raise rpki.exceptions.BadPKCS10("Certificate request is missing SIA id-ad-rpkiManifest")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request is missing SIA id-ad-rpkiManifest")
if not any(uri.startswith("rsync://") for uri in rpkiManifest):
- raise rpki.exceptions.BadPKCS10("Certificate request SIA id-ad-rpkiManifest contains no rsync URIs")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request SIA id-ad-rpkiManifest contains no rsync URIs")
if any(uri.startswith("rsync://") and not uri.endswith("/") for uri in caRepository):
- raise rpki.exceptions.BadPKCS10("Certificate request SIA id-ad-caRepository does not end with slash")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request SIA id-ad-caRepository does not end with slash")
if any(uri.startswith("rsync://") and uri.endswith("/") for uri in rpkiManifest):
- raise rpki.exceptions.BadPKCS10("Certificate request SIA id-ad-rpkiManifest ends with slash")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request SIA id-ad-rpkiManifest ends with slash")
@classmethod
def create(cls, keypair, exts = None, is_ca = False,