aboutsummaryrefslogtreecommitdiff
path: root/rpkid/rpki
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2014-01-29 21:48:30 +0000
committerRob Austein <sra@hactrn.net>2014-01-29 21:48:30 +0000
commit36e21b634a78d046860104cc462d2fa02b5822c4 (patch)
tree704c4c0d4ff99f7472464bfb40ef645e7979eaa2 /rpkid/rpki
parent2645eabce95e2cbca2e81339b093f457d0c3310e (diff)
First cut of zookeeper methods to add router certs and other EE certs.
Likely needs further refactoring before really usable by GUI or CLI. svn path=/branches/tk671/; revision=5654
Diffstat (limited to 'rpkid/rpki')
-rw-r--r--rpkid/rpki/irdb/models.py25
-rw-r--r--rpkid/rpki/irdb/zookeeper.py57
-rw-r--r--rpkid/rpki/x509.py88
3 files changed, 97 insertions, 73 deletions
diff --git a/rpkid/rpki/irdb/models.py b/rpkid/rpki/irdb/models.py
index b6fc28be..8e492409 100644
--- a/rpkid/rpki/irdb/models.py
+++ b/rpkid/rpki/irdb/models.py
@@ -582,26 +582,15 @@ class GhostbusterRequest(django.db.models.Model):
class EECertificateRequest(ResourceSet):
issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "ee_certificate_requests")
pkcs10 = PKCS10Field()
- gski = django.db.models.CharField(max_length = 27)
+ gski = django.db.models.CharField(max_length = 27)
+ router_id = django.db.models.BigIntegerField(null = True)
- # 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 the
- # 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.
+ # Subject name isn't allowed in the PKCS #10, so we need to carry
+ # either a subject name or a router-id as a separate field.
+ # Carrying subject name would be more flexible, but is also a swamp
+ # if we start allowing more than just CN and SN.
#
- # I guess we could have left-right XML attributes corresponding to
- # X.509 commonName and serialNumber if necessary, question is whether
- # this is necessary.
-
- # Well, we need //some// way of storing the router-id, and the PKCS
- # #10 doesn't contain a subject name, so we need an additional field.
- # Question becomes whether user wants to control which AS is used
- # in the router certificate's name in the rare case where there's
- # more than one (AS aliasing, I gather).
+ # For the moment we just do router-id.
def _select_resource_bag(self):
ee_asn = rpki.irdb.EECertificateRequestASN.objects.raw("""
diff --git a/rpkid/rpki/irdb/zookeeper.py b/rpkid/rpki/irdb/zookeeper.py
index 97e56d5a..fc330db4 100644
--- a/rpkid/rpki/irdb/zookeeper.py
+++ b/rpkid/rpki/irdb/zookeeper.py
@@ -1589,7 +1589,7 @@ class Zookeeper(object):
@django.db.transaction.commit_on_success
- def add_ee_certificate_request(self, pkcs10, resources, kind = "ee"):
+ 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
@@ -1600,7 +1600,7 @@ class Zookeeper(object):
.load_asns() and .load_prefixes() for other strategies.
"""
- pkcs10.check_valid_request_ee(kind = kind)
+ pkcs10.check_valid_request_ee()
ee_request = self.resource_ca.ee_certificate_requests.create(
pkcs10 = pkcs10,
gski = pkcs10.gSKI(),
@@ -1613,40 +1613,41 @@ class Zookeeper(object):
ee_request.address_ranges.create(start_ip = str(range.min), end_ip = str(range.max), version = 6)
- def add_router_certificate_request(self, pkcs10, *asns):
+ @django.db.transaction.commit_on_success
+ def add_router_certificate_request(self, pkcs10, router_id, *asns, valid_until = None):
"""
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.
+ certificate request for it along with a specified router-id and
+ ASN(s).
+
+ 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_request_router()
+
asns = tuple(long(a) if isinstance(a, (str, unicode)) else a for a in asns)
if not asns or not all(isinstance(a, (int, long)) and a >= 0 and a <= 0xFFFFFFFF for a in asns):
raise rpki.exceptions.BadAutonomousSystemNumber("Bad AutonomousSystem number%s: %s" % (
"" if len(asns) == 1 else "s", ", ".join(repr(a) for a in asns)))
- # 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.
- #
- # Upon further reading: this will have to go somewhere else,
- # because the combination of draft-ietf-sidr-bgpsec-pki-profiles
- # and RFC 6487 says that the subject-name-to-be can't be in the
- # PKCS #10, it has to be carried separately like the ASNs. Save
- # this code, refactor once I figure out where this belongs.
-
- 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) not in asns 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())
-
- eku = pkcs10.getEKU()
- if eku is None or rpki.oids.id_kp_bgpsec_router not in eku:
- raise rpki.exceptions.WrongEKU("Router certificate EKU not present in request")
-
- raise NotImplementedError, "Not finished"
+ asn_set = rpki.resource_set.resource_set_as()
+ asn_set.extend(rpki.resource_set.resource_range_as(a, a) for a in asns)
+ asn_set.canonize()
+
+ if valid_until is None:
+ valid_until = rpki.sundial.now() + rpki.sundial.timedelta(days = 365)
+ elif valid_until < rpki.sundial.now():
+ raise PastExpiration, "Specified expiration date %s has already passed" % valid_until
+
+ ee_request = self.resource_ca.ee_certificate_requests.create(
+ pkcs10 = pkcs10,
+ gski = pkcs10.gSKI(),
+ valid_until = valid_until,
+ router_id = router_id)
+
+ for range in asn_set:
+ ee_request.asns.create(start_as = str(range.min), end_as = str(range.max))
diff --git a/rpkid/rpki/x509.py b/rpkid/rpki/x509.py
index 30e32aa8..00ed3d58 100644
--- a/rpkid/rpki/x509.py
+++ b/rpkid/rpki/x509.py
@@ -927,15 +927,10 @@ class PKCS10(DER_object):
def check_valid_request_ca(self):
"""
Check this certification request to see whether it's a valid
- request for an RPKI certificate. This is broken out of the
- up-down protocol code because it's somewhat involved and the
- up-down code doesn't need to know the details.
+ request for an RPKI CA certificate.
Throws an exception if the request isn't valid, so if this method
returns at all, the request is ok.
-
- This needs refactoring, as the nested conditionals to handle the
- different kinds of certificates have gotten rather nasty.
"""
self.check_valid_request_common()
@@ -946,39 +941,83 @@ class PKCS10(DER_object):
sias = self.get_POW().getSIA()
if alg != rpki.oids.sha256WithRSAEncryption:
- raise rpki.exceptions.BadPKCS10("PKCS #10 request has bad signature algorithm %s" % alg)
+ raise rpki.exceptions.BadPKCS10("PKCS #10 has bad signature algorithm for CA: %s" % alg)
if bc is None or not bc[0] or bc[1] is not None:
- raise rpki.exceptions.BadPKCS10("PKCS #10 bad basicConstraints")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA bad basicConstraints")
if eku is not None:
- raise rpki.exceptions.BadPKCS10("EKU not allowed in CA certificate PKCS #10")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA EKU not allowed")
if sias is None:
- raise rpki.exceptions.BadPKCS10("PKCS #10 is missing SIA extension")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA SIA missing")
caRepository, rpkiManifest, signedObject = sias
if signedObject:
- raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request has SIA id-ad-signedObject")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA SIA must not have id-ad-signedObject")
if not caRepository:
- raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request is missing SIA id-ad-caRepository")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA SIA must have id-ad-caRepository")
if not any(uri.startswith("rsync://") for uri in caRepository):
- raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request SIA id-ad-caRepository contains no rsync URIs")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA SIA id-ad-caRepository contains no rsync URIs")
+
+ if any(uri.startswith("rsync://") and not uri.endswith("/") for uri in caRepository):
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA SIA id-ad-caRepository does not end with slash")
if not rpkiManifest:
- raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request is missing SIA id-ad-rpkiManifest")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA SIA must have id-ad-rpkiManifest")
if not any(uri.startswith("rsync://") for uri in rpkiManifest):
- 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("PKCS #10 CA certificate request SIA id-ad-caRepository does not end with slash")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA SIA id-ad-rpkiManifest contains no rsync URIs")
if any(uri.startswith("rsync://") and uri.endswith("/") for uri in rpkiManifest):
- raise rpki.exceptions.BadPKCS10("PKCS #10 CA certificate request SIA id-ad-rpkiManifest ends with slash")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 CA SIA id-ad-rpkiManifest ends with slash")
+
+
+ def check_valid_request_ee(self):
+ """
+ Check this certification request to see whether it's a valid
+ request for an RPKI EE certificate.
+
+ Throws an exception if the request isn't valid, so if this method
+ returns at all, the request is ok.
+
+ We're a bit less strict here than we are for either CA
+ certificates or BGPSEC router certificates, because the profile is
+ less tightly nailed down for unspecified-use RPKI EE certificates.
+ Future specific purposes may impose tighter constraints.
+
+ Note that this method does NOT apply to so-called "infrastructure"
+ EE certificates (eg, the EE certificates embedded in manifests and
+ ROAs); those are constrained fairly tightly, but they're also
+ generated internally so we don't need to check them as user or
+ protocol input.
+ """
+
+ self.check_valid_request_common()
+
+ alg = self.get_POW().getSignatureAlgorithm()
+ bc = self.get_POW().getBasicConstraints()
+ sia = self.get_POW().getSIA()
+
+ if alg not in (rpki.oids.sha256WithRSAEncryption, rpki.oids.ecdsa_with_SHA256):
+ raise rpki.exceptions.BadPKCS10("PKCS #10 has bad signature algorithm for EE: %s" % alg)
+
+ if bc is not None and (bc[0] or bc[1] is not None):
+ raise rpki.exceptions.BadPKCS10("PKCS #10 EE has bad basicConstraints")
+
+ caRepository, rpkiManifest, signedObject = sias or (None, None, None)
+
+ if caRepository:
+ raise rpki.exceptions.BadPKCS10("PKCS #10 EE must not have id-ad-caRepository")
+
+ if rpkiManifest:
+ raise rpki.exceptions.BadPKCS10("PKCS #10 EE must not have id-ad-rpkiManifest")
+
+ if signedObject and not any(uri.startswith("rsync://") for uri in signedObject):
+ raise rpki.exceptions.BadPKCS10("PKCS #10 EE SIA id-ad-signedObject contains no rsync URIs")
def check_valid_request_router(self):
@@ -999,21 +1038,16 @@ class PKCS10(DER_object):
the certificate when we get to the code that generates that.
"""
- self.check_valid_request_common()
+ self.check_valid_request_ee()
alg = self.get_POW().getSignatureAlgorithm()
- bc = self.get_POW().getBasicConstraints()
eku = self.get_POW().getEKU()
- #sia = self.get_POW().getSIA()
if alg != rpki.oids.ecdsa_with_SHA256:
- raise rpki.exceptions.BadPKCS10("PKCS #10 request has bad signature algorithm %s" % alg)
-
- if bc is not None and (bc[0] or bc[1] is not None):
- raise rpki.exceptions.BadPKCS10("PKCS #10 has bad basicConstraints for router")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 has bad signature algorithm for router: %s" % alg)
if eku is None or rpki.oids.id_kp_bgpsec_router not in eku:
- raise rpki.exceptions.BadPKCS10("PKCS #10 for router requires EKU")
+ raise rpki.exceptions.BadPKCS10("PKCS #10 router must have EKU")
@classmethod