diff --git a/core/java/src/net/i2p/crypto/CertUtil.java b/core/java/src/net/i2p/crypto/CertUtil.java index 3bee6d2d3a54f0d8d3f63555815fea97b5a4b3d9..ae6667c8bea05a3e47f26f888daee081cbc5e45d 100644 --- a/core/java/src/net/i2p/crypto/CertUtil.java +++ b/core/java/src/net/i2p/crypto/CertUtil.java @@ -226,17 +226,24 @@ public final class CertUtil { * Get the Java public key from a X.509 certificate file. * Throws if the certificate is invalid (e.g. expired). * + * This DOES check for revocation. + * * @return non-null, throws on all errors including certificate invalid * @since 0.9.24 moved from SU3File private method */ public static PublicKey loadKey(File kd) throws IOException, GeneralSecurityException { - return loadCert(kd).getPublicKey(); + X509Certificate cert = loadCert(kd); + if (isRevoked(cert)) + throw new CRLException("Certificate is revoked"); + return cert.getPublicKey(); } /** * Get the certificate from a X.509 certificate file. * Throws if the certificate is invalid (e.g. expired). * + * This does NOT check for revocation. + * * @return non-null, throws on all errors including certificate invalid * @since 0.9.24 adapted from SU3File private method */ @@ -314,6 +321,8 @@ public final class CertUtil { * Throws if any certificate is invalid (e.g. expired). * Does NOT close the stream. * + * This does NOT check for revocation. + * * @return non-null, non-empty, throws on all errors including certificate invalid * @since 0.9.25 */ @@ -380,6 +389,19 @@ public final class CertUtil { /** * Is the certificate revoked? + * This loads the CRLs from disk. + * For efficiency, call loadCRLs() and then pass to isRevoked(). + * + * @since 0.9.25 + */ + public static boolean isRevoked(Certificate cert) { + return isRevoked(I2PAppContext.getGlobalContext(), cert); + } + + /** + * Is the certificate revoked? + * This loads the CRLs from disk. + * For efficiency, call loadCRLs() and then pass to isRevoked(). * * @since 0.9.25 */ @@ -403,6 +425,16 @@ public final class CertUtil { return false; } + /** + * Load CRLs from standard locations. + * + * @return non-null, possibly empty + * @since 0.9.25 + */ + public static CertStore loadCRLs() { + return loadCRLs(I2PAppContext.getGlobalContext()); + } + /** * Load CRLs from standard locations. * @@ -423,6 +455,7 @@ public final class CertUtil { dir2 = new File(dir2, REVOCATION_DIR); loadCRLs(crls, dir2); } + //System.out.println("Loaded " + crls.size() + " CRLs"); CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(crls); try { CertStore store = CertStore.getInstance("Collection", ccsp); diff --git a/core/java/src/net/i2p/crypto/DirKeyRing.java b/core/java/src/net/i2p/crypto/DirKeyRing.java index 899f41847dec24d1d05fa92df2891aa646a52a40..4728379fbb92d88e88cd82c1b01d06f89c11a9d5 100644 --- a/core/java/src/net/i2p/crypto/DirKeyRing.java +++ b/core/java/src/net/i2p/crypto/DirKeyRing.java @@ -12,6 +12,7 @@ import java.io.IOException; import java.security.GeneralSecurityException; import java.security.PublicKey; import java.security.cert.CertificateFactory; +import java.security.cert.CRLException; import java.security.cert.X509Certificate; import net.i2p.util.SystemVersion; @@ -34,6 +35,8 @@ class DirKeyRing implements KeyRing { * Cert must be in the file (escaped keyName).crt, * and have a CN == keyName. * + * This DOES do a revocation check. + * * CN check unsupported on Android. * * @return null if file doesn't exist, throws on all other errors @@ -50,6 +53,8 @@ class DirKeyRing implements KeyRing { if (!kd.exists()) return null; X509Certificate cert = CertUtil.loadCert(kd); + if (CertUtil.isRevoked(cert)) + throw new CRLException("Certificate is revoked"); if (!SystemVersion.isAndroid()) { // getSubjectValue() unsupported on Android. // Any cert problems will be caught in non-Android testing. diff --git a/core/java/src/net/i2p/crypto/KeyStoreUtil.java b/core/java/src/net/i2p/crypto/KeyStoreUtil.java index 68fcc50c7d8ac49b38d8d54d601d61ac76d542b4..91999d66480b3e8720e6ed457b65b1e137850df7 100644 --- a/core/java/src/net/i2p/crypto/KeyStoreUtil.java +++ b/core/java/src/net/i2p/crypto/KeyStoreUtil.java @@ -13,6 +13,7 @@ import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertStore; import java.security.cert.X509Certificate; import java.security.cert.X509CRL; import java.util.ArrayList; @@ -332,6 +333,8 @@ public final class KeyStoreUtil { * Load all X509 Certs from a directory and add them to the * trusted set of certificates in the key store * + * This DOES check for revocation. + * * @return number successfully added * @since 0.8.2, moved from SSLEepGet in 0.9.9 */ @@ -341,6 +344,7 @@ public final class KeyStoreUtil { if (dir.exists() && dir.isDirectory()) { File[] files = dir.listFiles(); if (files != null) { + CertStore cs = CertUtil.loadCRLs(); for (int i = 0; i < files.length; i++) { File f = files[i]; if (!f.isFile()) @@ -354,7 +358,7 @@ public final class KeyStoreUtil { alias.endsWith(".p7c") || alias.endsWith(".pfx") || alias.endsWith(".p12") || alias.endsWith(".cer")) alias = alias.substring(0, alias.length() - 4); - boolean success = addCert(f, alias, ks); + boolean success = addCert(f, alias, ks, cs); if (success) added++; } @@ -367,10 +371,26 @@ public final class KeyStoreUtil { * Load an X509 Cert from a file and add it to the * trusted set of certificates in the key store * + * This does NOT check for revocation. + * * @return success * @since 0.8.2, moved from SSLEepGet in 0.9.9 */ public static boolean addCert(File file, String alias, KeyStore ks) { + return addCert(file, alias, ks, null); + } + + /** + * Load an X509 Cert from a file and add it to the + * trusted set of certificates in the key store + * + * This DOES check for revocation, IF cs is non-null. + * + * @param cs may be null; if non-null, check for revocation + * @return success + * @since 0.9.25 + */ + public static boolean addCert(File file, String alias, KeyStore ks, CertStore cs) { try { X509Certificate cert = CertUtil.loadCert(file); info("Read X509 Certificate from " + file.getAbsolutePath() + @@ -378,6 +398,10 @@ public final class KeyStoreUtil { " Serial: " + cert.getSerialNumber().toString(16) + "; Valid From: " + cert.getNotBefore() + " To: " + cert.getNotAfter()); + if (cs != null && CertUtil.isRevoked(cs, cert)) { + error("Certificate is revoked: " + file, new Exception()); + return false; + } ks.setCertificateEntry(alias, cert); info("Now trusting X509 Certificate, Issuer: " + cert.getIssuerX500Principal()); } catch (CertificateExpiredException cee) {