aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scripts/README24
-rw-r--r--scripts/biz-certs/Bob-CA.srl2
-rw-r--r--scripts/manifests.py22
-rw-r--r--scripts/rpki/left_right.py30
-rw-r--r--scripts/rpki/sql.py28
-rw-r--r--scripts/rpki/up_down.py4
-rw-r--r--scripts/rpki/x509.py27
-rwxr-xr-xscripts/rpkid.py7
-rw-r--r--scripts/testroot.sh2
9 files changed, 94 insertions, 52 deletions
diff --git a/scripts/README b/scripts/README
index b0d17fa4..f43ac9b8 100644
--- a/scripts/README
+++ b/scripts/README
@@ -97,16 +97,9 @@ Current TO DO list:
- Publication protocol and implementation thereof. Defer until core
functionality in the main engine is done.
- As an interim measure, hack some kind of stub publication (not real
- protocol yet, just dump to local filesystem so can see outputs and
- maybe rcynic against them); this is a stop-gap to let me concentrate
- on the main engine and defer work on the publication protocol and
- engine.
+ As an interim measure, I hacked up a local filesystem publication kludge.
-- Publication hooks everywhere - need not wait for protocol, can just
- log what would happen for now, or write to local file store (perhaps
- even in a form that we can use with rcynic as a relying party).
- Hooks for this go into:
+ Need publication hooks for:
- Cert publication
@@ -116,10 +109,6 @@ Current TO DO list:
- Withdrawal of any of the above
- Consolidate generation of filenames and URIs into methods, duh.
-
- (tags-search "\\.\\(publish\\|withdraw\\)(\\|\\+ \"\\.")
-
- Logging subsystem, including syslog support.
- Child batch processing loop, eg, regeneration or removal of expired
@@ -128,14 +117,7 @@ Current TO DO list:
everything that might need to be done.
Figuring out whether to regenerate or remove expired certs requires
- some of the same data as CRL generation.
-
- - Code to clean up expired certs
-
- - Code to revoke certs -- need to sort out when we do this
- automatically vs waiting for explicit revoke PDU from child
-
- - Code to generate CRLs
+ looking in the IRDB.
- Subsetting (req_* attributes in up-down protocol)
diff --git a/scripts/biz-certs/Bob-CA.srl b/scripts/biz-certs/Bob-CA.srl
index de578a4d..fc2f754e 100644
--- a/scripts/biz-certs/Bob-CA.srl
+++ b/scripts/biz-certs/Bob-CA.srl
@@ -1 +1 @@
-90801F1ED19454C4
+90801F1ED19454CF
diff --git a/scripts/manifests.py b/scripts/manifests.py
index b352b461..0204e882 100644
--- a/scripts/manifests.py
+++ b/scripts/manifests.py
@@ -1,6 +1,7 @@
# $Id$
-import rpki.x509, rpki.manifest, time, glob, os
+import time, glob, os
+import rpki.x509, rpki.manifest, rpki.sundial
show_content_1 = False
show_signed_manifest_PEM = False
@@ -9,6 +10,7 @@ show_content_2 = False
show_content_3 = False
dump_signed_manifest_DER = False
dump_manifest_content_DER = False
+test_empty_manifest = False
def dumpasn1(thing):
# Save to file rather than using popen4() because dumpasn1 uses
@@ -24,18 +26,22 @@ def dumpasn1(thing):
finally:
os.unlink(fn)
+if test_empty_manifest:
+ names_and_objs = []
+else:
+ names_and_objs = [(fn, rpki.x509.X509(Auto_file = fn)) for fn in glob.glob("resource-cert-samples/*.cer")]
+
m = rpki.x509.SignedManifest()
-m.build(serial = 17,
- nextUpdate = rpki.datetime.datetime.utcnow() + rpki.datetime.timedelta(days = 1),
- names_and_objs = [(fn, rpki.x509.X509(Auto_file = fn))
- for fn in glob.glob("resource-cert-samples/*.cer")])
+m.build(
+ serial = 17,
+ nextUpdate = rpki.sundial.datetime.utcnow() + rpki.sundial.timedelta(days = 1),
+ names_and_objs = names_and_objs,
+ keypair = rpki.x509.RSA(Auto_file = "biz-certs/Alice-EE.key"),
+ certs = rpki.x509.X509_chain(Auto_files = ("biz-certs/Alice-EE.cer", "biz-certs/Alice-CA.cer")))
if show_content_1:
dumpasn1(m.get_content().toString())
-m.sign(keypair = rpki.x509.RSA(Auto_file = "biz-certs/Alice-EE.key"),
- certs = rpki.x509.X509_chain(Auto_files = ("biz-certs/Alice-EE.cer", "biz-certs/Alice-CA.cer")))
-
if show_signed_manifest_PEM:
print m.get_PEM()
diff --git a/scripts/rpki/left_right.py b/scripts/rpki/left_right.py
index 63ebc385..b67ff84d 100644
--- a/scripts/rpki/left_right.py
+++ b/scripts/rpki/left_right.py
@@ -260,6 +260,7 @@ class self_elt(data_elt):
def client_poll(self, gctx):
"""Run the regular client poll cycle with each of this self's parents in turn."""
+
for parent in parent_elt.sql_fetch_where(gctx, "self_id = %s" % self.self_id):
# This will need a callback when we go event-driven
@@ -278,6 +279,35 @@ class self_elt(data_elt):
ca.delete(gctx, parent) # CA not listed by parent
rpki.sql.sql_sweep(gctx)
+ def update_children(self, gctx):
+ """Check for updated IRDB data for all of this self's children and
+ issue new certs as necessary. Must handle changes both in
+ resources and in expiration date.
+ """
+ print "Code to check IRDB for updates to children not yet written"
+
+ def regenerate_crls_and_manifests(self, gctx):
+ """Generate new CRLs and manifests as necessary for all of this
+ self's CAs. Extracting nextUpdate from a manifest is hard at the
+ moment due to implementation silliness, so for now we generate a
+ new manifest whenever we generate a new CRL
+ """
+
+ now = rpki.sundial.datetime.utcnow()
+ for parent in parent_elt.sql_fetch_where(gctx, "self_id = %s" % self.self_id):
+ repository = repository_elt.sql_fetch(gctx, parent.repository_id)
+ for ca in rpki.sql.ca_obj.sql_fetch_where(gctx, "parent_id = %s" % parent.parent_id):
+ ca_detail = ca.fetch_active(gctx)
+ #
+ # Temporary kludge until I sort out initial publication.
+ #
+ if True or now > ca_detail.latest_crl.getNextUpdate():
+ ca_detail.generate_crl(gctx)
+ ca_detail.generate_manifest(gctx)
+ repository.publish(gctx,
+ (ca_detail.latest_crl, ca_detail.crl_uri(ca)),
+ (ca_detail.latest_manifest, ca_detail.manifest_uri(ca)))
+
class bsc_elt(data_elt):
"""<bsc/> (Business Signing Context) element."""
diff --git a/scripts/rpki/sql.py b/scripts/rpki/sql.py
index b40bb672..0e148988 100644
--- a/scripts/rpki/sql.py
+++ b/scripts/rpki/sql.py
@@ -275,6 +275,7 @@ class ca_obj(sql_persistant):
issue_response = rpki.up_down.issue_pdu.query(gctx, parent, self, ca_detail)
ca_detail.activate(
+ gctx = gctx,
ca = self,
cert = issue_response.payload.classes[0].certs[0].cert,
uri = issue_response.payload.classes[0].certs[0].cert_url)
@@ -317,6 +318,10 @@ class ca_obj(sql_persistant):
self.sql_mark_dirty()
return self.last_crl_sn
+ def fetch_active(self, gctx):
+ """Fetch the current active ca_detail for this ca."""
+ return ca_detail_obj.sql_fetch_where1(gctx, "ca_id = %s AND state = 'active'" % self.ca_id)
+
class ca_detail_obj(sql_persistant):
"""Internal CA detail object."""
@@ -344,11 +349,6 @@ class ca_detail_obj(sql_persistant):
assert (self.manifest_public_key is None and self.manifest_private_key_id is None) or \
self.manifest_public_key.get_DER() == self.manifest_private_key_id.get_public_DER()
- @classmethod
- def sql_fetch_active(cls, gctx, ca_id):
- """Fetch the current active ca_detail_obj associated with a given ca_id."""
- return cls.sql_fetch_where1(gctx, "ca_id = %s AND state = 'active'" % ca_id)
-
def crl_uri(self, ca):
"""Return publication URI for this ca_detail's CRL."""
return ca.sia_uri + self.public_key.gSKI() + ".crl"
@@ -357,12 +357,14 @@ class ca_detail_obj(sql_persistant):
"""Return publication URI for this ca_detail's manifest."""
return ca.sia_uri + self.public_key.gSKI() + ".mnf"
- def activate(self, ca, cert, uri, predecessor = None):
+ def activate(self, gctx, ca, cert, uri, predecessor = None):
"""Activate this ca_detail."""
self.latest_ca_cert = cert
self.ca_cert_uri = uri.rsync()
self.generate_manifest_cert(ca)
+ self.generate_crl(gctx)
+ self.generate_manifest(gctx)
self.state = "active"
self.sql_mark_dirty()
@@ -488,7 +490,7 @@ class ca_detail_obj(sql_persistant):
certlist.append((child_cert.cert.getSerial(), child_cert.revoked, ()))
certlist.sort()
- return rpki.x509.CRL.generate(
+ self.latest_crl = rpki.x509.CRL.generate(
keypair = self.private_key_id,
issuer = self.latest_ca_cert,
serial = ca.next_crl_number(),
@@ -505,12 +507,12 @@ class ca_detail_obj(sql_persistant):
certs = child_cert_obj.sql_fetch_where(gctx, "child_cert.ca_detail_id = %s AND child_cert.revoked IS NULL" % self.ca_detail_id)
m = rpki.x509.SignedManifest()
- m.build(serial = ca.next_manifest_number(),
- nextUpdate = rpki.sundial.datetime.utcnow() + rpki.sundial.timedelta(seconds = self_obj.crl_interval),
- names_and_objs = [(c.uri_tail(), c.cert) for c in certs])
- m.sign(keypair = self.manifest_private_key_id,
- certs = rpki.x509.X509_chain(self.latest_manifest_cert))
-
+ m.build(
+ serial = ca.next_manifest_number(),
+ nextUpdate = rpki.sundial.datetime.utcnow() + rpki.sundial.timedelta(seconds = self_obj.crl_interval),
+ names_and_objs = [(c.uri_tail(), c.cert) for c in certs],
+ keypair = self.manifest_private_key_id,
+ certs = rpki.x509.X509_chain(self.latest_manifest_cert))
self.latest_manifest = m
class child_cert_obj(sql_persistant):
diff --git a/scripts/rpki/up_down.py b/scripts/rpki/up_down.py
index a094b308..d2b8bf43 100644
--- a/scripts/rpki/up_down.py
+++ b/scripts/rpki/up_down.py
@@ -171,7 +171,7 @@ class list_pdu(base_elt):
irdb_resources = rpki.left_right.irdb_query(gctx, child.self_id, child.child_id)
for parent in rpki.left_right.parent_elt.sql_fetch_where(gctx, "parent.self_id = %s" % child.self_id):
for ca in rpki.sql.ca_obj.sql_fetch_where(gctx, "ca.parent_id = %s" % parent.parent_id):
- ca_detail = rpki.sql.ca_detail_obj.sql_fetch_active(gctx, ca.ca_id)
+ ca_detail = ca.fetch_active(gctx)
if not ca_detail:
continue
resources = ca_detail.latest_ca_cert.get_3779resources().intersection(irdb_resources)
@@ -252,7 +252,7 @@ class issue_pdu(base_elt):
raise rpki.exceptions.BadClassNameSyntax, "Bad class name %s" % self.class_name
ca_id = long(self.class_name)
ca = rpki.sql.ca_obj.sql_fetch(gctx, ca_id)
- ca_detail = rpki.sql.ca_detail_obj.sql_fetch_active(gctx, ca_id)
+ ca_detail = ca.fetch_active(gctx)
if ca is None or ca_detail is None:
raise rpki.exceptions.NotInDatabase
self.pkcs10.check_valid_rpki()
diff --git a/scripts/rpki/x509.py b/scripts/rpki/x509.py
index b6c56d1e..47a47b51 100644
--- a/scripts/rpki/x509.py
+++ b/scripts/rpki/x509.py
@@ -587,9 +587,13 @@ class SignedManifest(DER_object):
self.clear()
self.content = content
- def sign(self, keypair, certs):
- """Sign this manifest."""
- self.DER = rpki.cms.sign(self.content.toString(), keypair, certs)
+ def getThisUpdate(self):
+ """Get thisUpdate value from this manifest."""
+ return rpki.sundial.datetime.fromGeneralizedTime(self.get_content())
+
+ def getNextUpdate(self):
+ """Get nextUpdate value from this manifest."""
+ return rpki.sundial.datetime.fromGeneralizedTime(self.get_content())
def verify(self, ta):
"""Verify this manifest."""
@@ -598,8 +602,8 @@ class SignedManifest(DER_object):
m.fromString(s)
self.content = m
- def build(self, serial, nextUpdate, names_and_objs, version = 0):
- """Build the inner content of this manifest."""
+ def build(self, serial, nextUpdate, names_and_objs, keypair, certs, version = 0):
+ """Build the inner content of this manifest and sign it with CMS."""
filelist = []
for name, obj in names_and_objs:
d = POW.Digest(POW.SHA256_DIGEST)
@@ -614,6 +618,7 @@ class SignedManifest(DER_object):
m.fileHashAlg.set((2, 16, 840, 1, 101, 3, 4, 2, 1)) # id-sha256
m.fileList.set(filelist)
self.set_content(m)
+ self.DER = rpki.cms.sign(m.toString(), keypair, certs)
class CRL(DER_object):
"""Class to hold a Certificate Revocation List."""
@@ -650,6 +655,14 @@ class CRL(DER_object):
self.POWpkix = crl
return self.POWpkix
+ def getThisUpdate(self):
+ """Get thisUpdate value from this CRL."""
+ return rpki.sundial.datetime.fromASN1tuple(self.get_POWpkix().getThisUpdate())
+
+ def getNextUpdate(self):
+ """Get nextUpdate value from this CRL."""
+ return rpki.sundial.datetime.fromASN1tuple(self.get_POWpkix().getNextUpdate())
+
@classmethod
def generate(cls, keypair, issuer, serial, thisUpdate, nextUpdate, revokedCertificates, version = 1, digestType = "sha256WithRSAEncryption"):
crl = POW.pkix.CertificateList()
@@ -660,7 +673,7 @@ class CRL(DER_object):
if revokedCertificates:
crl.setRevokedCertificates(revokedCertificates)
crl.setExtensions(
- (rpki.oids.name2oid["authorityKeyIdentifier"], False, (issuer.get_SKI(), (), None)),
- (rpki.oids.name2oid["cRLNumber"], False, serial))
+ ((rpki.oids.name2oid["authorityKeyIdentifier"], False, (issuer.get_SKI(), (), None)),
+ (rpki.oids.name2oid["cRLNumber"], False, serial)))
crl.sign(keypair.get_POW(), digestType)
return cls(POWpkix = crl)
diff --git a/scripts/rpkid.py b/scripts/rpkid.py
index 4cfd295a..74ba77c1 100755
--- a/scripts/rpkid.py
+++ b/scripts/rpkid.py
@@ -13,6 +13,7 @@ import rpki.resource_set, rpki.up_down, rpki.left_right, rpki.x509
import rpki.https, rpki.config, rpki.cms, rpki.exceptions, rpki.relaxng
def left_right_handler(query, path):
+ """Process one left-right PDU."""
try:
q_elt = rpki.cms.xml_verify(query, gctx.cms_ta_irbe)
rpki.relaxng.left_right.assertValid(q_elt)
@@ -26,6 +27,7 @@ def left_right_handler(query, path):
return 500, "Unhandled exception %s" % data
def up_down_handler(query, path):
+ """Process one up-down PDU."""
try:
child_id = path.partition("/up-down/")[2]
if not child_id.isdigit():
@@ -39,8 +41,13 @@ def up_down_handler(query, path):
return 400, "Could not process PDU: %s" % data
def cronjob_handler(query, path):
+ """Periodic tasks. As simple as possible for now, may need to break
+ this up into separate handlers later.
+ """
for s in rpki.left_right.self_elt.sql_fetch_all(gctx):
s.client_poll(gctx)
+ s.update_children(gctx)
+ s.regenerate_crls_and_manifests(gctx)
return 200, "OK"
class global_context(object):
diff --git a/scripts/testroot.sh b/scripts/testroot.sh
index ebc61d95..f3818496 100644
--- a/scripts/testroot.sh
+++ b/scripts/testroot.sh
@@ -67,6 +67,8 @@ python irbe-cli.py child --self_id 1 --action create --bsc_id 1 --cms_ta biz-cer
if test "$1" = "run"
then
+ rm -rf publication
+
python testroot.py & testroot=$!
python irdb.py & irdb=$!
trap "kill $rpkid $irdb $testroot" 0