diff options
-rwxr-xr-x | scripts/rcynic-lta | 217 |
1 files changed, 127 insertions, 90 deletions
diff --git a/scripts/rcynic-lta b/scripts/rcynic-lta index d490dab2..27c7a6b3 100755 --- a/scripts/rcynic-lta +++ b/scripts/rcynic-lta @@ -281,11 +281,20 @@ class DER_object_mixin(object): @target.setter def target(self, value): self._update_bool("target", value) -class X509 (rpki.x509.X509, DER_object_mixin): pass -class CRL (rpki.x509.CRL, DER_object_mixin): pass -class SignedManifest (rpki.x509.SignedManifest, DER_object_mixin): pass -class ROA (rpki.x509.ROA, DER_object_mixin): pass -class Ghostbuster (rpki.x509.Ghostbuster, DER_object_mixin): pass +class X509 (rpki.x509.X509, DER_object_mixin): + pass + +class CRL (rpki.x509.CRL, DER_object_mixin): + pass + +class SignedManifest (rpki.x509.SignedManifest, DER_object_mixin): + pass + +class ROA (rpki.x509.ROA, DER_object_mixin): + pass + +class Ghostbuster (rpki.x509.Ghostbuster, DER_object_mixin): + pass class VerifyContextNoRFC3779(rpki.POW.X509StoreCTX): """ @@ -298,6 +307,115 @@ class VerifyContextNoRFC3779(rpki.POW.X509StoreCTX): rpki.POW.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) +class Verifier(object): + """ + Perform X.509 and CMS validation checks and store markers indicating + shape of the resulting tree in SQL. + """ + + # http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/ + + def __init__(self, rpdb): + self.rpdb = rpdb + self.counter = 0 + + self.store = rpki.POW.X509Store() + self.store.setFlags(rpki.POW.X509_V_FLAG_CRL_CHECK_ALL) + self.store.setContextClass(VerifyContextNoRFC3779) + + self.spin = 0 + self.seen = set() + self.start = rpki.sundial.now() + + for fn in glob.iglob(os.path.join(tal_directory, "*.tal")): + with open(fn, "r") as f: + uri = f.readline().strip() + key = rpki.POW.Asymmetric.derReadPublic(base64.b64decode(f.read())) + self.rpdb.cur.execute( + "SELECT id, der FROM object WHERE nochain = 1 AND fn2 = 'cer' AND ski = ?", + (buffer(key.calculateSKI()),)) + for rowid, der in self.rpdb.cur.fetchall(): + assert rowid not in self.seen + cer = rpki.POW.X509.derRead(der) + if cer.getPublicKey().derWritePublic() == key.derWritePublic(): + self.seen.add(rowid) + self.rpdb.cur.execute("UPDATE object SET nochain = 0 WHERE id = ?", (rowid,)) + self.walk_tree(cer, rowid) + + sys.stderr.write("\r= %d objects in %s, committing..." % ( + len(self.seen), rpki.sundial.now() - self.start)) + + #self.rpdb.cur.execute("DELETE FROM object WHERE nochain = 1") + self.rpdb.db.commit() + + sys.stderr.write("done.\n") + + + def query(self, where, args): + self.rpdb.cur.execute( + "SELECT id, der FROM object WHERE nochain = 1 AND aki = ? AND issuer = ? AND" + where, + args) + return self.rpdb.cur.fetchall() + + + def next_counter(self): + self.counter += 1 + return self.counter + + + def walk_tree(self, issuer, issuer_id): + issuer_key = issuer.getPublicKey() + self.store.addTrust(issuer) + + self.rpdb.cur.execute( + "UPDATE object SET nochain = 0, left_paren = ? WHERE id = ?", + (self.next_counter(), issuer_id)) + + self.spin += 1 + sys.stderr.write("\r%s %d %s...\r" % ("|\\-/"[self.spin & 3], + len(self.seen), + rpki.sundial.now() - self.start)) + + args = (buffer(issuer.getSKI()), rpki.x509.X501DN.from_POW(issuer.getSubject())) + + for rowid, der in self.query("fn2 = 'crl'", args): + assert rowid not in self.seen + crl = rpki.POW.CRL.derRead(der) + if crl.verify(issuer_key): + self.seen.add(rowid) + self.rpdb.cur.execute( + "UPDATE object SET nochain = 0, left_paren = ?, right_paren = ? WHERE id = ?", + (self.next_counter(), self.next_counter(), rowid)) + self.store.addCrl(crl) + + for rowid, der in self.query("fn2 <> 'crl' AND fn2 <> 'cer'", args): + assert rowid not in self.seen + obj = rpki.POW.CMS.derRead(der) + try: + for cer in obj.certs(): + if self.store.verify(cer).getError(): + raise RuntimeError + obj.verify(self.store, flags = rpki.POW.CMS_NO_SIGNER_CERT_VERIFY) + self.seen.add(rowid) + self.rpdb.cur.execute( + "UPDATE object SET nochain = 0, left_paren = ?, right_paren = ? WHERE id = ?", + (self.next_counter(), self.next_counter(), rowid)) + except (RuntimeError, rpki.POW.OpenSSLError): + pass + + for rowid, der in self.query("fn2 = 'cer'", args): + assert rowid not in self.seen + cer = rpki.POW.X509.derRead(der) + ctx = self.store.verify(cer) + if not ctx.getError(): + self.seen.add(rowid) + self.walk_tree(cer, rowid) + + self.rpdb.cur.execute( + "UPDATE object SET right_paren = ? WHERE id = ?", + (self.next_counter(), issuer_id)) + + class RPDB(object): """ Relying party database. @@ -346,6 +464,8 @@ class RPDB(object): original BOOLEAN NOT NULL DEFAULT 0, para BOOLEAN NOT NULL DEFAULT 0, target BOOLEAN NOT NULL DEFAULT 0, + left_paren INTEGER, + right_paren INTEGER, UNIQUE (der)); CREATE TABLE uri ( @@ -673,91 +793,8 @@ class RPDB(object): self.db.close() - def validate(self, spinner = 100): - - spin = 0 - seen = set() - start = rpki.sundial.now() - - store = rpki.POW.X509Store() - store.setFlags(rpki.POW.X509_V_FLAG_CRL_CHECK_ALL) - store.setContextClass(VerifyContextNoRFC3779) - - issuers = [] - - for fn in glob.iglob(os.path.join(tal_directory, "*.tal")): - with open(fn, "r") as f: - uri = f.readline().strip() - key = rpki.POW.Asymmetric.derReadPublic(base64.b64decode(f.read())) - self.cur.execute("SELECT id, der FROM object WHERE nochain = 1 AND fn2 = 'cer' AND ski = ?", - (buffer(key.calculateSKI()),)) - for rowid, der in self.cur.fetchall(): - assert rowid not in seen - cer = rpki.POW.X509.derRead(der) - if cer.getPublicKey().derWritePublic() == key.derWritePublic(): - seen.add(rowid) - self.cur.execute("UPDATE object SET nochain = 0 WHERE id = ?", (rowid,)) - issuers.append(cer) - - while issuers: - issuer = issuers.pop(0) - issuer_key = issuer.getPublicKey() - store.addTrust(issuer) - - if spinner: - spin += 1 - sys.stderr.write("\r%s %d %s...\r" % ("|\\-/"[spin & 3], len(seen), rpki.sundial.now() - start)) - - # Do all the queries up front, as it may be a little faster than - # interleaving queries and updates. - - query = "SELECT id, der FROM object WHERE nochain = 1 AND aki = ? AND issuer = ? AND " - args = (buffer(issuer.getSKI()), rpki.x509.X501DN.from_POW(issuer.getSubject())) - - self.cur.execute(query + "fn2 = 'crl'", args) - crls = self.cur.fetchall() - - self.cur.execute(query + "fn2 = 'cer'", args) - cers = self.cur.fetchall() - - self.cur.execute(query + "fn2 <> 'crl' AND fn2 <> 'cer'", args) - objs = self.cur.fetchall() - - for rowid, der in crls: - assert rowid not in seen - crl = rpki.POW.CRL.derRead(der) - if crl.verify(issuer_key): - seen.add(rowid) - self.cur.execute("UPDATE object SET nochain = 0 WHERE id = ?", (rowid,)) - store.addCrl(crl) - - for rowid, der in cers: - assert rowid not in seen - cer = rpki.POW.X509.derRead(der) - ctx = store.verify(cer) - if not ctx.getError(): - seen.add(rowid) - self.cur.execute("UPDATE object SET nochain = 0 WHERE id = ?", (rowid,)) - issuers.append(cer) - - for rowid, der in objs: - assert rowid not in seen - obj = rpki.POW.CMS.derRead(der) - try: - for cer in obj.certs(): - if store.verify(cer).getError(): - raise RuntimeError - obj.verify(store, flags = rpki.POW.CMS_NO_SIGNER_CERT_VERIFY) - seen.add(rowid) - self.cur.execute("UPDATE object SET nochain = 0 WHERE id = ?", (rowid,)) - except (RuntimeError, rpki.POW.OpenSSLError): - pass - - if spinner: - sys.stderr.write("\r= %d objects in %s.\n" % (len(seen), rpki.sundial.now() - start)) - - #self.cur.execute("DELETE FROM object WHERE nochain = 1") - self.db.commit() + def validate(self): + Verifier(self) if __name__ == "__main__": |