diff options
-rw-r--r-- | ca/rpki-confgen.xml | 84 | ||||
-rw-r--r-- | ca/tests/smoketest.py | 199 | ||||
-rw-r--r-- | rpki/publication.py | 2 | ||||
-rw-r--r-- | rpki/publication_control.py | 7 | ||||
-rw-r--r-- | rpki/rootd.py | 147 | ||||
-rw-r--r-- | rpki/x509.py | 10 |
6 files changed, 240 insertions, 209 deletions
diff --git a/ca/rpki-confgen.xml b/ca/rpki-confgen.xml index 5468db50..7eb62111 100644 --- a/ca/rpki-confgen.xml +++ b/ca/rpki-confgen.xml @@ -647,10 +647,9 @@ </doc> <doc> - Ok, if that wasn't enough to scare you off: rootd is a mess, and - needs to be rewritten, or, better, merged into rpkid. It - doesn't use the publication protocol, and it requires far too - many configuration parameters. + Ok, if that wasn't enough to scare you off: rootd is a mess, + needs to be rewritten, or, better, merged into rpkid, and + requires far too many configuration parameters. </doc> <doc> @@ -735,16 +734,14 @@ </doc> </option> - <option name = "rpki-root-dir" - value = "${myrpki::publication_base_directory}"> + <option name = "rpki_data_dir" + value = "${myrpki::bpki_servers_directory}"> <doc> - Where rootd should write its output. Yes, rootd should be using - pubd instead of publishing directly, but it doesn't. This - needs to match pubd's configuration. + Directory where rootd should store its RPKI data files. </doc> </option> - <option name = "rpki-base-uri" + <option name = "rpki_base_uri" value = "rsync://${myrpki::publication_rsync_server}/${myrpki::publication_rsync_module}/"> <doc> rsync URI corresponding to directory containing rootd's outputs. @@ -758,52 +755,65 @@ </doc> </option> - <option name = "rpki-root-key" - value = "${myrpki::bpki_servers_directory}/root.key"> + <option name = "rpki-root-cert-file" + value = "${rootd::rpki_data_dir}/root.cer"> <doc> - Private key corresponding to rootd's root RPKI certificate. + Filename (as opposed to rsync URI) of rootd's root RPKI + certificate. </doc> </option> - <option name = "rpki-root-cert" - value = "${myrpki::publication_root_cert_directory}/root.cer"> + <option name = "rpki-root-key-file" + value = "${rootd::rpki_data_dir}/root.key"> <doc> - Filename (as opposed to rsync URI) of rootd's root RPKI - certificate. + Private key corresponding to rootd's root RPKI certificate. </doc> </option> - <option name = "rpki-subject-pkcs10" - value = "${myrpki::bpki_servers_directory}/rootd.subject.pkcs10"> + <option name = "rpki-root-crl-uri" + value = "${rootd::rpki_base_uri}/root.crl"> <doc> - Where rootd should stash a copy of the PKCS #10 request it gets - from its one (and only) child + URI of the CRL for rootd's root RPKI certificate. </doc> </option> - <option name = "rpki-subject-lifetime" - value = "30d"> + <option name = "rpki-root-crl-file" + value = "${rootd::rpki_data_dir}/root.crl"> <doc> - Lifetime of the one and only RPKI certificate rootd issues. + Filename of the CRL for rootd's root RPKI certificate. </doc> </option> - <option name = "rpki-root-crl" - value = "root.crl"> + <option name = "rpki-root-manifest-uri" + value = "${rootd::rpki_base_uri}/root.mft"> <doc> - Filename (relative to rootd-base-uri and rpki-root-dir) of the CRL - for rootd's root RPKI certificate. + URI of the manifest for rootd's root RPKI certificate. </doc> </option> - <option name = "rpki-root-manifest" - value = "root.mft"> + <option name = "rpki-root-manifest-file" + value = "${rootd::rpki_data_dir}/root.mft"> <doc> Filename (relative to rootd-base-uri and rpki-root-dir) of the manifest for rootd's root RPKI certificate. </doc> </option> + <option name = "rpki-subject-pkcs10-file" + value = "${rootd::rpki_data_dir}/subject.pkcs10"> + <doc> + Where rootd should stash a copy of the PKCS #10 request it gets + from its one (and only) child + </doc> + </option> + + <option name = "rpki-subject-lifetime" + value = "30d"> + <doc> + Lifetime of the one and only RPKI certificate rootd issues. + </doc> + </option> + <option name = "rpki-class-name" value = "${myrpki::handle}"> <doc> @@ -812,11 +822,17 @@ </doc> </option> - <option name = "rpki-subject-cert" - value = "${myrpki::handle}.cer"> + <option name = "rpki-subject-cert-uri" + value = "${rootd::rpki_base_uri}/${myrpki::handle}.cer"> + <doc> + URI of the one (and only) RPKI certificate rootd issues. + </doc> + </option> + + <option name = "rpki-subject-cert-file" + value = "${rootd::rpki_data_dir}/${myrpki::handle}.cer"> <doc> - Filename (relative to rootd-base-uri and rpki-root-dir) of the one - (and only) RPKI certificate rootd issues. + Filename of the one (and only) RPKI certificate rootd issues. </doc> </option> diff --git a/ca/tests/smoketest.py b/ca/tests/smoketest.py index 53e65b9f..28905d90 100644 --- a/ca/tests/smoketest.py +++ b/ca/tests/smoketest.py @@ -221,7 +221,7 @@ def main(): a.setup_bpki_certs() setup_publication(pubd_sql) - setup_rootd(db.root, y.get("rootd", {})) + setup_rootd(db.root, y.get("rootd", {}), db) setup_rsyncd() setup_rcynic() @@ -250,11 +250,18 @@ def main(): # the code until final exit is all closures. def start(): - rpki.async.iterator(db.engines, create_rpki_objects, yaml_loop) + rpki.async.iterator(db.engines, create_rpki_objects, create_pubd_objects) def create_rpki_objects(iterator, a): a.create_rpki_objects(iterator) + def create_pubd_objects(): + call_pubd([rpki.publication_control.client_elt.make_pdu(action = "create", + client_handle = db.root.client_handle + "-" + rootd_name, + base_uri = rootd_sia, + bpki_cert = cross_certify(rootd_name + "-TA", pubd_name + "-TA"))], + cb = lambda ignored: yaml_loop()) + def yaml_loop(): # This is probably where we should be updating expired BPKI @@ -749,13 +756,13 @@ class allocation(object): logger.info("Writing config files for %s", self.name) assert self.rpki_port is not None - d = { "my_name" : self.name, - "irdb_db_name" : self.irdb_db_name, - "irdb_db_pass" : irdb_db_pass, - "irdb_port" : self.irdb_port, - "rpki_db_name" : self.rpki_db_name, - "rpki_db_pass" : rpki_db_pass, - "rpki_port" : self.rpki_port } + d = dict(my_name = self.name, + irdb_db_name = self.irdb_db_name, + irdb_db_pass = irdb_db_pass, + irdb_port = self.irdb_port, + rpki_db_name = self.rpki_db_name, + rpki_db_pass = rpki_db_pass, + rpki_port = self.rpki_port) f = open(self.name + ".conf", "w") f.write(conf_fmt_1 % d) for line in self.extra_conf: @@ -935,45 +942,7 @@ class allocation(object): certificant = self.name + "-SELF" else: certifier = self.name + "-SELF" - certfile = certifier + "-" + certificant + ".cer" - - logger.info("Cross certifying %s into %s's BPKI (%s)", certificant, certifier, certfile) - - child = rpki.x509.X509(Auto_file = certificant + ".cer") - parent = rpki.x509.X509(Auto_file = certifier + ".cer") - keypair = rpki.x509.RSA(Auto_file = certifier + ".key") - serial_file = certifier + ".srl" - - now = rpki.sundial.now() - notAfter = now + rpki.sundial.timedelta(days = 30) - - try: - f = open(serial_file, "r") - serial = f.read() - f.close() - serial = int(serial.splitlines()[0], 16) - except IOError: - serial = 1 - - x = parent.bpki_cross_certify( - keypair = keypair, - source_cert = child, - serial = serial, - notAfter = notAfter, - now = now) - - f = open(serial_file, "w") - f.write("%02x\n" % (serial + 1)) - f.close() - - f = open(certfile, "w") - f.write(x.get_PEM()) - f.close() - - logger.debug("Cross certified %s:", certfile) - logger.debug(" Issuer %s [%s]", x.getIssuer(), x.hAKI()) - logger.debug(" Subject %s [%s]", x.getSubject(), x.hSKI()) - return x + return cross_certify(certificant, certifier) def create_rpki_objects(self, cb): """ @@ -992,13 +961,11 @@ class allocation(object): selves = [self] + self.hosts - for i, s in enumerate(selves): - logger.info("Creating RPKI objects for [%d] %s", i, s.name) - rpkid_pdus = [] pubd_pdus = [] - for s in selves: + for i, s in enumerate(selves): + logger.info("Creating RPKI objects for [%d] %s", i, s.name) rpkid_pdus.append(rpki.left_right.self_elt.make_pdu( action = "create", @@ -1188,17 +1155,18 @@ def setup_bpki_cert_chain(name, ee = (), ca = ()): s = "exec >/dev/null 2>&1\n" #s = "set -x\n" for kind in ("TA",) + ee + ca: - d = { "name" : name, - "kind" : kind, - "ca" : "false" if kind in ee else "true", - "openssl" : prog_openssl } + d = dict(name = name, + kind = kind, + ca = "false" if kind in ee else "true", + openssl = prog_openssl) f = open("%(name)s-%(kind)s.conf" % d, "w") f.write(bpki_cert_fmt_1 % d) f.close() if not os.path.exists("%(name)s-%(kind)s.key" % d): s += bpki_cert_fmt_2 % d s += bpki_cert_fmt_3 % d - d = { "name" : name, "openssl" : prog_openssl } + d = dict(name = name, + openssl = prog_openssl) s += bpki_cert_fmt_4 % d for kind in ee + ca: d["kind"] = kind @@ -1208,20 +1176,24 @@ def setup_bpki_cert_chain(name, ee = (), ca = ()): s += bpki_cert_fmt_6 % d subprocess.check_call(s, shell = True) -def setup_rootd(rpkid, rootd_yaml): +def setup_rootd(rpkid, rootd_yaml, db): """ Write the config files for rootd. """ rpkid.cross_certify(rootd_name + "-TA", reverse = True) + cross_certify(pubd_name + "-TA", rootd_name + "-TA") logger.info("Writing config files for %s", rootd_name) - d = { "rootd_name" : rootd_name, - "rootd_port" : rootd_port, - "rpkid_name" : rpkid.name, - "rootd_sia" : rootd_sia, - "rsyncd_dir" : rsyncd_dir, - "openssl" : prog_openssl, - "lifetime" : rootd_yaml.get("lifetime", "30d") } + d = dict(rootd_name = rootd_name, + rootd_port = rootd_port, + rpkid_name = rpkid.name, + pubd_name = pubd_name, + rootd_sia = rootd_sia, + rsyncd_dir = rsyncd_dir, + openssl = prog_openssl, + lifetime = rootd_yaml.get("lifetime", "30d"), + pubd_port = pubd_port, + rootd_handle = db.root.client_handle + "-" + rootd_name) f = open(rootd_name + ".conf", "w") f.write(rootd_fmt_1 % d) f.close() @@ -1238,9 +1210,9 @@ def setup_rcynic(): """ logger.info("Config file for rcynic") - d = { "rcynic_name" : rcynic_name, - "rootd_name" : rootd_name, - "rootd_sia" : rootd_sia } + d = dict(rcynic_name = rcynic_name, + rootd_name = rootd_name, + rootd_sia = rootd_sia) f = open(rcynic_name + ".conf", "w") f.write(rcynic_fmt_1 % d) f.close() @@ -1251,10 +1223,10 @@ def setup_rsyncd(): """ logger.info("Config file for rsyncd") - d = { "rsyncd_name" : rsyncd_name, - "rsyncd_port" : rsyncd_port, - "rsyncd_module" : rsyncd_module, - "rsyncd_dir" : rsyncd_dir } + d = dict(rsyncd_name = rsyncd_name, + rsyncd_port = rsyncd_port, + rsyncd_module = rsyncd_module, + rsyncd_dir = rsyncd_dir) f = open(rsyncd_name + ".conf", "w") f.write(rsyncd_fmt_1 % d) f.close() @@ -1283,12 +1255,12 @@ def setup_publication(pubd_sql): if "DROP TABLE IF EXISTS" not in sql.upper(): raise db.close() - d = { "pubd_name" : pubd_name, - "pubd_port" : pubd_port, - "pubd_db_name" : pubd_db_name, - "pubd_db_user" : pubd_db_user, - "pubd_db_pass" : pubd_db_pass, - "pubd_dir" : rsyncd_dir } + d = dict(pubd_name = pubd_name, + pubd_port = pubd_port, + pubd_db_name = pubd_db_name, + pubd_db_user = pubd_db_user, + pubd_db_pass = pubd_db_pass, + pubd_dir = rsyncd_dir) f = open(pubd_name + ".conf", "w") f.write(pubd_fmt_1 % d) f.close() @@ -1323,7 +1295,7 @@ def call_pubd(pdus, cb): logger.debug(r_cms.pretty_print_content()) assert r_msg.is_reply for r_pdu in r_msg: - assert not isinstance(r_pdu, rpki.publication_control.report_error_elt) + r_pdu.raise_if_error() cb(r_msg) def call_pubd_eb(e): @@ -1335,6 +1307,48 @@ def call_pubd(pdus, cb): callback = call_pubd_cb, errback = call_pubd_eb) + +def cross_certify(certificant, certifier): + """ + Cross-certify and return the resulting certificate. + """ + + certfile = certifier + "-" + certificant + ".cer" + + logger.info("Cross certifying %s into %s's BPKI (%s)", certificant, certifier, certfile) + + child = rpki.x509.X509(Auto_file = certificant + ".cer") + parent = rpki.x509.X509(Auto_file = certifier + ".cer") + keypair = rpki.x509.RSA(Auto_file = certifier + ".key") + serial_file = certifier + ".srl" + + now = rpki.sundial.now() + notAfter = now + rpki.sundial.timedelta(days = 30) + + try: + with open(serial_file, "r") as f: + serial = int(f.read().splitlines()[0], 16) + except IOError: + serial = 1 + + x = parent.bpki_cross_certify( + keypair = keypair, + source_cert = child, + serial = serial, + notAfter = notAfter, + now = now) + + with open(serial_file, "w") as f: + f.write("%02x\n" % (serial + 1)) + + with open(certfile, "w") as f: + f.write(x.get_PEM()) + + logger.debug("Cross certified %s:", certfile) + logger.debug(" Issuer %s [%s]", x.getIssuer(), x.hAKI()) + logger.debug(" Subject %s [%s]", x.getSubject(), x.hSKI()) + return x + last_rcynic_run = None def run_rcynic(): @@ -1533,24 +1547,28 @@ rootd-bpki-cert = %(rootd_name)s-RPKI.cer rootd-bpki-key = %(rootd_name)s-RPKI.key rootd-bpki-crl = %(rootd_name)s-TA.crl child-bpki-cert = %(rootd_name)s-TA-%(rpkid_name)s-SELF.cer +pubd-bpki-cert = %(rootd_name)s-TA-%(pubd_name)s-TA.cer server-port = %(rootd_port)s -rpki-root-dir = %(rsyncd_dir)sroot -rpki-base-uri = %(rootd_sia)sroot/ -rpki-root-cert-uri = %(rootd_sia)sroot.cer +rpki-class-name = trunk + +pubd-contact-uri = http://localhost:%(pubd_port)d/client/%(rootd_handle)s -rpki-root-key = root.key -rpki-root-cert = root.cer +rpki-root-cert-file = root.cer +rpki-root-cert-uri = %(rootd_sia)sroot.cer +rpki-root-key-file = root.key -rpki-subject-pkcs10 = %(rootd_name)s.subject.pkcs10 +rpki-subject-cert-file = trunk.cer +rpki-subject-cert-uri = %(rootd_sia)sroot/trunk.cer +rpki-subject-pkcs10-file= trunk.p10 rpki-subject-lifetime = %(lifetime)s -rpki-root-crl = root.crl -rpki-root-manifest = root.mft +rpki-root-crl-file = root.crl +rpki-root-crl-uri = %(rootd_sia)sroot/root.crl -rpki-class-name = trunk -rpki-subject-cert = trunk.cer +rpki-root-manifest-file = root.mft +rpki-root-manifest-uri = %(rootd_sia)sroot/root.mft include-bpki-crl = yes enable_tracebacks = yes @@ -1610,8 +1628,7 @@ awk '!/-----(BEGIN|END)/' >>%(rootd_name)s.tal && -outform DER \ -extfile %(rootd_name)s.conf \ -extensions req_x509_rpki_ext \ - -signkey root.key && -ln -f root.cer %(rsyncd_dir)s + -signkey root.key ''' rcynic_fmt_1 = '''\ diff --git a/rpki/publication.py b/rpki/publication.py index b28a7421..1d428bf9 100644 --- a/rpki/publication.py +++ b/rpki/publication.py @@ -160,7 +160,7 @@ class list_elt(base_publication_elt): <list/> element. """ - pass + element_name = "list" class report_error_elt(rpki.xml_utils.text_elt, publication_namespace): diff --git a/rpki/publication_control.py b/rpki/publication_control.py index 4ddcd8b2..42a74d36 100644 --- a/rpki/publication_control.py +++ b/rpki/publication_control.py @@ -138,6 +138,13 @@ class client_elt(rpki.xml_utils.data_elt, rpki.sql.sql_persistent, publication_c if not uri.startswith(self.base_uri): raise rpki.exceptions.ForbiddenURI + def raise_if_error(self): + """ + No-op, because this isn't a <report_error/> PDU. + """ + + pass + class report_error_elt(rpki.xml_utils.text_elt, publication_control_namespace): """ diff --git a/rpki/rootd.py b/rpki/rootd.py index 1977c318..2261a83f 100644 --- a/rpki/rootd.py +++ b/rpki/rootd.py @@ -105,37 +105,29 @@ class cms_msg(rpki.up_down.cms_msg): class main(object): - def get_root_cert(self): - logger.debug("Read root cert %s", self.rpki_root_cert_file) - self.rpki_root_cert = rpki.x509.X509(Auto_file = self.rpki_root_cert_file) - def root_newer_than_subject(self): - return os.stat(self.rpki_root_cert_file).st_mtime > \ - os.stat(os.path.join(self.rpki_root_dir, self.rpki_subject_cert)).st_mtime + return self.rpki_root_cert.mtime > os.stat(self.rpki_subject_cert_file).st_mtime def get_subject_cert(self): - filename = os.path.join(self.rpki_root_dir, self.rpki_subject_cert) try: - x = rpki.x509.X509(Auto_file = filename) - logger.debug("Read subject cert %s", filename) + x = rpki.x509.X509(Auto_file = self.rpki_subject_cert_file) + logger.debug("Read subject cert %s", self.rpki_subject_cert_file) return x except IOError: return None def set_subject_cert(self, cert): - filename = os.path.join(self.rpki_root_dir, self.rpki_subject_cert) - logger.debug("Writing subject cert %s, SKI %s", filename, cert.hSKI()) - with open(filename, "wb") as f: + logger.debug("Writing subject cert %s, SKI %s", self.rpki_subject_cert_file, cert.hSKI()) + with open(self.rpki_subject_cert_file, "wb") as f: f.write(cert.get_DER()) def del_subject_cert(self): - filename = os.path.join(self.rpki_root_dir, self.rpki_subject_cert) - logger.debug("Deleting subject cert %s", filename) - os.remove(filename) + logger.debug("Deleting subject cert %s", self.rpki_subject_cert_file) + os.remove(self.rpki_subject_cert_file) def get_subject_pkcs10(self): @@ -180,7 +172,6 @@ class main(object): logger.debug("Root certificate has changed, regenerating subject") self.revoke_subject_cert(now) subject_cert = None - self.get_root_cert() if subject_cert is not None: return subject_cert, None pkcs10 = old_pkcs10 if new_pkcs10 is None else new_pkcs10 @@ -190,7 +181,7 @@ class main(object): resources = self.rpki_root_cert.get_3779resources() notAfter = now + self.rpki_subject_lifetime logger.info("Generating subject cert %s with resources %s, expires %s", - self.rpki_base_uri + self.rpki_subject_cert, resources, notAfter) + self.rpki_subject_cert_uri, resources, notAfter) req_key = pkcs10.getPublicKey() req_sia = pkcs10.get_SIA() self.next_serial_number() @@ -200,14 +191,14 @@ class main(object): serial = self.serial_number, sia = req_sia, aia = self.rpki_root_cert_uri, - crldp = self.rpki_base_uri + self.rpki_root_crl, + crldp = self.rpki_root_crl_uri, resources = resources, notBefore = now, notAfter = notAfter) self.set_subject_cert(subject_cert) pubd_msg = rpki.publication.msg.query() pubd_msg.append(rpki.publication.publish_elt.make_pdu( - uri = self.rpki_base_uri + self.rpki_subject_cert, + uri = self.rpki_subject_cert_uri, hash = hash, der = subject_cert.get_DER())) self.generate_crl_and_manifest(now, pubd_msg) @@ -227,32 +218,26 @@ class main(object): thisUpdate = now, nextUpdate = now + self.rpki_subject_regen, revokedCertificates = self.revoked) - fn = os.path.join(self.rpki_root_dir, self.rpki_root_crl) - try: - with open(fn, "rb") as f: - hash = rpki.x509.sha256(f.read()).encode("hex") - logger.debug("Old CRL hash %s", hash) - except IOError: - hash = None - logger.debug("Writing CRL %s", fn) - with open(fn, "wb") as f: + hash = self.read_hash_maybe(self.rpki_root_crl_file) + logger.debug("Writing CRL %s", self.rpki_root_crl_file) + with open(self.rpki_root_crl_file, "wb") as f: f.write(crl.get_DER()) pubd_msg.append(rpki.publication.publish_elt.make_pdu( - uri = self.rpki_base_uri + self.rpki_root_crl, + uri = self.rpki_root_crl_uri, hash = hash, der = crl.get_DER())) - manifest_content = [(self.rpki_root_crl, crl)] + manifest_content = [(os.path.basename(self.rpki_root_crl_uri), crl)] if subject_cert is not None: - manifest_content.append((self.rpki_subject_cert, subject_cert)) + manifest_content.append((os.path.basename(self.rpki_subject_cert_uri), subject_cert)) manifest_resources = rpki.resource_set.resource_bag.from_inheritance() manifest_keypair = rpki.x509.RSA.generate() manifest_cert = self.rpki_root_cert.issue( keypair = self.rpki_root_key, subject_key = manifest_keypair.get_public(), serial = self.serial_number, - sia = (None, None, self.rpki_base_uri + self.rpki_root_manifest), + sia = (None, None, self.rpki_root_manifest_uri), aia = self.rpki_root_cert_uri, - crldp = self.rpki_base_uri + self.rpki_root_crl, + crldp = self.rpki_root_crl_uri, resources = manifest_resources, notBefore = now, notAfter = now + self.rpki_subject_lifetime, @@ -264,20 +249,34 @@ class main(object): names_and_objs = manifest_content, keypair = manifest_keypair, certs = manifest_cert) - fn = os.path.join(self.rpki_root_dir, self.rpki_root_manifest) - try: - with open(fn, "rb") as f: - hash = rpki.x509.sha256(f.read()).encode("hex") - logger.debug("Old manifest hash %s", hash) - except IOError: - hash = None - logger.debug("Writing manifest %s", fn) - with open(fn, "wb") as f: + hash = self.read_hash_maybe(self.rpki_root_manifest_file) + logger.debug("Writing manifest %s", self.rpki_root_manifest_file) + with open(self.rpki_root_manifest_file, "wb") as f: f.write(manifest.get_DER()) pubd_msg.append(rpki.publication.publish_elt.make_pdu( - uri = self.rpki_base_uri + self.rpki_root_manifest, + uri = self.rpki_root_manifest_uri, hash = hash, der = manifest.get_DER())) + hash = rpki.x509.sha256(self.rpki_root_cert.get_DER()).encode("hex") + if hash != self.rpki_root_cert_hash: + pubd_msg.append(rpki.publication.publish_elt.make_pdu( + uri = self.rpki_root_cert_uri, + hash = self.rpki_root_cert_hash, + der = self.rpki_root_cert.get_DER())) + self.rpki_root_cert_hash = hash + + + @staticmethod + def read_hash_maybe(fn): + """ + Return hash of an existing object, or None. + """ + + try: + with open(fn, "rb") as f: + return rpki.x509.sha256(f.read()).encode("hex") + except IOError: + return None def revoke_subject_cert(self, now): @@ -294,7 +293,7 @@ class main(object): r_msg.payload.classes.append(rc) if subject_cert is not None: rc.certs.append(rpki.up_down.certificate_elt()) - rc.certs[0].cert_url = rpki.up_down.multi_uri(self.rpki_base_uri + self.rpki_subject_cert) + rc.certs[0].cert_url = rpki.up_down.multi_uri(self.rpki_subject_cert_uri) rc.certs[0].cert = subject_cert self.call_pubd(callback, errback, pubd_msg) @@ -314,8 +313,8 @@ class main(object): try: logger.debug("Received response from pubd") r_cms = rpki.publication.cms_msg(DER = r_der) - r_msg = r_cms.unwrap(self.bpki_ta) - r_cms.check_replay_sql(self, self.peer_contact_uri) + r_msg = r_cms.unwrap((self.bpki_ta, self.pubd_bpki_cert)) + self.pubd_cms_timestamp = r_cms.check_replay(self.pubd_cms_timestamp, self.pubd_contact_uri) for r_pdu in r_msg: r_pdu.raise_if_error() if len(q_msg) > len(r_msg): @@ -343,7 +342,7 @@ class main(object): try: q_cms = cms_msg(DER = query) q_msg = q_cms.unwrap((self.bpki_ta, self.child_bpki_cert)) - self.cms_timestamp = q_cms.check_replay(self.cms_timestamp, path) + self.rpkid_cms_timestamp = q_cms.check_replay(self.rpkid_cms_timestamp, path) except (rpki.async.ExitNow, SystemExit): raise except Exception, e: @@ -373,7 +372,7 @@ class main(object): def next_crl_number(self): if self.crl_number is None: try: - crl = rpki.x509.CRL(DER_file = os.path.join(self.rpki_root_dir, self.rpki_root_crl)) + crl = rpki.x509.CRL(DER_file = self.rpki_root_crl_file) self.crl_number = crl.getCRLNumber() except: # pylint: disable=W0702 self.crl_number = 0 @@ -397,11 +396,11 @@ class main(object): global rootd rootd = self # Gross, but simpler than what we'd have to do otherwise - self.rpki_root_cert = None self.serial_number = None self.crl_number = None self.revoked = [] - self.cms_timestamp = None + self.rpkid_cms_timestamp = None + self.pubd_cms_timestamp = None os.environ["TZ"] = "UTC" time.tzset() @@ -424,55 +423,39 @@ class main(object): if not args.foreground: rpki.daemonize.daemon(pidfile = args.pidfile) - # This mess could use a rewrite, not so much for the code that - # reads the variables themselves as for the twisty maze of ten - # zillion configuration parameters that nobody ever touches but - # which must be set by the rpki.conf template in order for any of - # this to work properly. - - # Still need to add .pubd_contac_uri and fix the target filenames - # for all the stuff we used to write in place instead of having - # pubd do it. - - # Still need to write RPKI root cert. - self.bpki_ta = rpki.x509.X509(Auto_update = self.cfg.get("bpki-ta")) self.rootd_bpki_key = rpki.x509.RSA( Auto_update = self.cfg.get("rootd-bpki-key")) self.rootd_bpki_cert = rpki.x509.X509(Auto_update = self.cfg.get("rootd-bpki-cert")) self.rootd_bpki_crl = rpki.x509.CRL( Auto_update = self.cfg.get("rootd-bpki-crl")) self.child_bpki_cert = rpki.x509.X509(Auto_update = self.cfg.get("child-bpki-cert")) + self.pubd_bpki_cert = rpki.x509.X509(Auto_update = self.cfg.get("pubd-bpki-cert")) self.http_server_host = self.cfg.get("server-host", "") self.http_server_port = self.cfg.getint("server-port") - self.rpki_class_name = self.cfg.get("rpki-class-name", "wombat") + self.rpki_class_name = self.cfg.get("rpki-class-name") - self.rpki_root_dir = self.cfg.get("rpki-root-dir") - self.rpki_base_uri = self.cfg.get("rpki-base-uri", "rsync://" + self.rpki_class_name + ".invalid/") + self.rpki_root_key = rpki.x509.RSA( Auto_update = self.cfg.get("rpki-root-key-file")) + self.rpki_root_cert = rpki.x509.X509(Auto_update = self.cfg.get("rpki-root-cert-file")) + self.rpki_root_cert_uri = self.cfg.get("rpki-root-cert-uri") + self.rpki_root_cert_hash = None - self.rpki_root_key = rpki.x509.RSA(Auto_update = self.cfg.get("rpki-root-key")) - self.rpki_root_cert_file = self.cfg.get("rpki-root-cert") - self.rpki_root_cert_uri = self.cfg.get("rpki-root-cert-uri", self.rpki_base_uri + "root.cer") + self.rpki_root_manifest_file = self.cfg.get("rpki-root-manifest-file") + self.rpki_root_manifest_uri = self.cfg.get("rpki-root-manifest-uri") - self.rpki_root_manifest = self.cfg.get("rpki-root-manifest", "root.mft") - self.rpki_root_crl = self.cfg.get("rpki-root-crl", "root.crl") - self.rpki_subject_cert = self.cfg.get("rpki-subject-cert", "child.cer") - self.rpki_subject_pkcs10 = self.cfg.get("rpki-subject-pkcs10", "child.pkcs10") + self.rpki_root_crl_file = self.cfg.get("rpki-root-crl-file") + self.rpki_root_crl_uri = self.cfg.get("rpki-root-crl-uri") + self.rpki_subject_cert_file = self.cfg.get("rpki-subject-cert-file") + self.rpki_subject_cert_uri = self.cfg.get("rpki-subject-cert-uri") + self.rpki_subject_pkcs10 = self.cfg.get("rpki-subject-pkcs10-file") self.rpki_subject_lifetime = rpki.sundial.timedelta.parse(self.cfg.get("rpki-subject-lifetime", "8w")) - self.rpki_subject_regen = rpki.sundial.timedelta.parse(self.cfg.get("rpki-subject-regen", self.rpki_subject_lifetime.convert_to_seconds() / 2)) + self.rpki_subject_regen = rpki.sundial.timedelta.parse(self.cfg.get("rpki-subject-regen", + self.rpki_subject_lifetime.convert_to_seconds() / 2)) self.include_bpki_crl = self.cfg.getboolean("include-bpki-crl", False) - # Somewhere about here we want to ask pubd about things we might - # have published previously, and might want to whack them or store - # their hashes for later update. We could use usual callback - # mechanism, or just rpki.async.async_wrapper(rpki.http.caller()) - # as we probably don't want to be doing anything else until this - # is done. - # - # Begs question of what happens if rootd comes up before pubd. - # Might need a startup delay here. + self.pubd_contact_uri = self.cfg.get("pubd-contact-uri") rpki.http.server(host = self.http_server_host, port = self.http_server_port, diff --git a/rpki/x509.py b/rpki/x509.py index 44d9484e..2c7b5e5c 100644 --- a/rpki/x509.py +++ b/rpki/x509.py @@ -323,6 +323,14 @@ class DER_object(object): else: self.lastfail = None + @property + def mtime(self): + """ + Retrieve os.stat().st_mtime for auto-update files. + """ + + return os.stat(self.filename).st_mtime + def check(self): """ Perform basic checks on a DER object. @@ -1396,7 +1404,7 @@ class CMS_object(DER_object): ## @var debug_cms_certs # Set this to True to log a lot of chatter about CMS certificates. - debug_cms_certs = False + debug_cms_certs = True ## @var dump_using_dumpasn1 # Set this to use external dumpasn1 program, which is prettier and |