diff --git a/core/java/src/net/i2p/crypto/CertUtil.java b/core/java/src/net/i2p/crypto/CertUtil.java
index 97032065acbadfc7d11ccfc52f3f0b55fcd4dced..3bee6d2d3a54f0d8d3f63555815fea97b5a4b3d9 100644
--- a/core/java/src/net/i2p/crypto/CertUtil.java
+++ b/core/java/src/net/i2p/crypto/CertUtil.java
@@ -15,6 +15,9 @@ import java.security.PublicKey;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertStore;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.CRL;
 import java.security.cert.CRLException;
 import java.security.cert.X509Certificate;
 import java.security.cert.X509CRL;
@@ -23,8 +26,10 @@ import java.security.spec.KeySpec;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.EnumSet;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
@@ -45,6 +50,8 @@ import net.i2p.util.SystemVersion;
  */
 public final class CertUtil {
         
+    private static final String CERT_DIR = "certificates";
+    private static final String REVOCATION_DIR = "revocations";
     private static final int LINE_LENGTH = 64;
 
     /**
@@ -371,10 +378,123 @@ public final class CertUtil {
         writePEM(buf, "X509 CRL", out);
     }
 
+    /**
+     *  Is the certificate revoked?
+     *
+     *  @since 0.9.25
+     */
+    public static boolean isRevoked(I2PAppContext ctx, Certificate cert) {
+        CertStore store = loadCRLs(ctx);
+        return isRevoked(store, cert);
+    }
+
+    /**
+     *  Is the certificate revoked?
+     *
+     *  @since 0.9.25
+     */
+    public static boolean isRevoked(CertStore store, Certificate cert) {
+        try {
+            for (CRL crl : store.getCRLs(null)) {
+                if (crl.isRevoked(cert))
+                    return true;
+            }
+        } catch (GeneralSecurityException gse) {}
+        return false;
+    }
+
+    /**
+     *  Load CRLs from standard locations.
+     *
+     *  @return non-null, possibly empty
+     *  @since 0.9.25
+     */
+    public static CertStore loadCRLs(I2PAppContext ctx) {
+        Set<X509CRL> crls = new HashSet<X509CRL>(8);
+        File dir = new File(ctx.getBaseDir(), CERT_DIR);
+        dir = new File(dir, REVOCATION_DIR);
+        loadCRLs(crls, dir);
+        boolean diff = true;
+        try {
+            diff = !ctx.getBaseDir().getCanonicalPath().equals(ctx.getConfigDir().getCanonicalPath());
+        } catch (IOException ioe) {}
+        if (diff) {
+            File dir2 = new File(ctx.getConfigDir(), CERT_DIR);
+            dir2 = new File(dir2, REVOCATION_DIR);
+            loadCRLs(crls, dir2);
+        }
+        CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(crls);
+        try {
+            CertStore store = CertStore.getInstance("Collection", ccsp);
+            return store;
+        } catch (GeneralSecurityException gse) {
+            // shouldn't happen
+            error("CertStore", gse);
+            throw new UnsupportedOperationException(gse);
+        }
+    }
+
+    /**
+     *  Load CRLs from the directory into the set.
+     *
+     *  @since 0.9.25
+     */
+    private static void loadCRLs(Set<X509CRL> crls, File dir) {
+        if (dir.exists() && dir.isDirectory()) {
+            File[] files = dir.listFiles();
+            if (files != null) {
+                for (int i = 0; i < files.length; i++) {
+                    File f = files[i];
+                    if (!f.isFile())
+                        continue;
+                    if (f.getName().endsWith(".crl")) {
+                        try {
+                            X509CRL crl = loadCRL(f);
+                            crls.add(crl);
+                        } catch (IOException ioe) {
+                            error("Cannot load CRL from " + f, ioe);
+                        } catch (GeneralSecurityException crle) {
+                            error("Cannot load CRL from " + f, crle);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     *  Load a CRL.
+     *
+     *  @return non-null, possibly empty
+     *  @since 0.9.25
+     */
+    private static X509CRL loadCRL(File file) throws IOException, GeneralSecurityException {
+        InputStream in = null;
+        try {
+            in = new FileInputStream(file);
+            return loadCRL(in);
+        } finally {
+            if (in != null) try { in.close(); } catch (IOException ioe) {}
+        }
+    }
+
+    /**
+     *  Load a CRL. Does NOT Close the stream.
+     *
+     *  @return non-null
+     *  @since 0.9.25
+     */
+    private static X509CRL loadCRL(InputStream in) throws GeneralSecurityException {
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        return (X509CRL) cf.generateCRL(in);
+    }
+
+
+
 /****
     public static final void main(String[] args) {
         if (args.length < 2) {
-            System.out.println("Usage: [loadcert | loadcrl | loadprivatekey] file");
+            System.out.println("Usage: [loadcert | loadcrl | loadcrldir | loadcrldirs | isrevoked | loadprivatekey] file");
             System.exit(1);
         }
         try {
@@ -382,7 +502,21 @@ public final class CertUtil {
             if (args[0].equals("loadcert")) {
                 loadCert(f);
             } else if (args[0].equals("loadcrl")) {
+                loadCRL(f);
+            } else if (args[0].equals("loadcrldir")) {
+                Set<X509CRL> crls = new HashSet<X509CRL>(8);
+                loadCRLs(crls, f);
+                System.out.println("Found " + crls.size() + " CRLs");
+            } else if (args[0].equals("loadcrldirs")) {
+                CertStore store = loadCRLs(I2PAppContext.getGlobalContext());
+                Collection<? extends CRL> crls = store.getCRLs(null);
+                System.out.println("Found " + crls.size() + " CRLs");
+            } else if (args[0].equals("isrevoked")) {
+                Certificate cert = loadCert(f);
+                boolean rv = isRevoked(I2PAppContext.getGlobalContext(), cert);
+                System.out.println("Revoked? " + rv);
             } else {
+                System.out.println("Usage: [loadcert | loadcrl | loadprivatekey] file");
             }
 
         } catch (Exception e) {