diff --git a/build.xml b/build.xml index ef9066fc92..c1fa8adc75 100644 --- a/build.xml +++ b/build.xml @@ -1438,10 +1438,17 @@ - + + + + + + + + diff --git a/core/java/src/net/i2p/crypto/CertUtil.java b/core/java/src/net/i2p/crypto/CertUtil.java index 31a55ad1a6..cb60326832 100644 --- a/core/java/src/net/i2p/crypto/CertUtil.java +++ b/core/java/src/net/i2p/crypto/CertUtil.java @@ -558,7 +558,7 @@ public final class CertUtil { public static final void main(String[] args) { if (args.length < 2) { - System.out.println("Usage: [loadcert | loadcrl | loadcrldir | loadcrldirs | isrevoked | loadprivatekey] file"); + System.out.println("Usage: [loadcert | loadcrl | loadcrldir | loadcrldirs | isrevoked | loadprivatekey | checkall] file"); System.exit(1); } try { @@ -580,8 +580,11 @@ public final class CertUtil { Certificate cert = loadCert(f); boolean rv = isRevoked(I2PAppContext.getGlobalContext(), cert); System.out.println("Revoked? " + rv); + } else if (args[0].equals("checkall")) { + int rv = checkAll(f); + //System.exit(rv); } else { - System.out.println("Usage: [loadcert | loadcrl | loadprivatekey] file"); + System.out.println("Usage: [loadcert | loadcrl | loadcrldir | loadcrldirs | isrevoked | loadprivatekey | checkall] file"); } } catch (Exception e) { @@ -589,4 +592,75 @@ public final class CertUtil { System.exit(1); } } + + // threshold for warning + private static final long CHECK = 120*24*60*60*1000L; + + /** + * For use in the build process. + * + * @return 0 for success, nonzero for failure + * @since 0.9.38 + */ + private static int checkAll(File dir) { + int good = 0; + int soon = 0; + int bad = 0; + Set crls = new HashSet(8); + File rdir = new File(dir, REVOCATION_DIR); + loadCRLs(crls, rdir); + //System.out.println("Loaded " + crls.size() + " CRLs"); + CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(crls); + CertStore store; + try { + store = CertStore.getInstance("Collection", ccsp); + } catch (GeneralSecurityException gse) { + // shouldn't happen + error("CertStore", gse); + throw new UnsupportedOperationException(gse); + } + long now = System.currentTimeMillis(); + File[] dirs = dir.listFiles(); + if (dirs != null) { + for (int i = 0; i < dirs.length; i++) { + File d = dirs[i]; + if (!d.isDirectory()) + continue; + if (d.getName().equals(REVOCATION_DIR)) + continue; + File[] files = d.listFiles(new FileSuffixFilter(".crt")); + if (files != null) { + for (int j = 0; j < files.length; j++) { + File f = files[j]; + try { + X509Certificate cert = loadCert(f); + if (isRevoked(store, cert)) { + System.out.println("ERROR: Revoked cert " + f); + bad++; + continue; + } + long exp = cert.getNotAfter().getTime() - now; + if (exp < CHECK) { + System.out.println("**** WARNING: Cert " + f + " expires in " + DataHelper.formatDuration(exp)); + soon++; + } else { + good++; + } + } catch (IOException ioe) { + System.out.println("**** ERROR: Cannot load cert from " + f + ": " + ioe); + bad++; + } catch (java.security.cert.CertificateExpiredException cee) { + System.out.println("**** WARNING: Cert expired " + f + ": " + cee); + bad++; + } catch (GeneralSecurityException gse) { + System.out.println("**** ERROR: Cannot load cert from " + f + ": " + gse); + bad++; + } + } + } + } + } + System.out.println("Found " + good + " valid certs, " + bad + " bad certs, " + soon + " about to expire certs"); + return (bad > 0) ? 1 : 0; + } } diff --git a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java index f9e0499c56..221bb71e50 100644 --- a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java +++ b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java @@ -115,12 +115,10 @@ public class Reseeder { "https://itoopie.atomike.ninja/" + ',' + // atomike_at_mail.i2p.crt // CA // Java 8+ only "https://reseed.onion.im/" + ',' + // lazygravy_at_mail.i2p // reseed.onion.im.crt // Java 8+ only "https://reseed.memcpy.io/" + ',' + // hottuna_at_mail.i2p.crt // CA // SNI required - "https://reseed.atomike.ninja/" + ',' + // atomike_at_mail.i2p.crt // CA // SNI required, Java 8+ only + //"https://reseed.atomike.ninja/" + ',' + // atomike_at_mail.i2p.crt // CA // SNI required, Java 8+ only "https://i2p.mooo.com/netDb/" + ',' + // bugme_at_mail.i2p.crt // i2p.mooo.com.crt "https://download.xxlspeed.com/" + ',' + // backup_at_mail.i2p.crt // CA // Java 8+ "https://netdb.i2p2.no/" + ',' + // meeh_at_mail.i2p.crt // CA // SNI required - //"https://us.reseed.i2p2.no:444/" + ',' + // meeh_at_mail.i2p.crt // us.reseed.i2p2.no.crt - //"https://uk.reseed.i2p2.no:444/" + ',' + // meeh_at_mail.i2p.crt // uk.reseed.i2p2.no.crt "https://reseed.i2p-projekt.de/"; // echelon_at_mail.i2p.crt // echelon.reseed2017.crt // Java 8+ private static final String SU3_FILENAME = "i2pseeds.su3";