Changeset 5c4189ab


Ignore:
Timestamp:
Nov 24, 2015 3:23:13 PM (5 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
92bb2db
Parents:
2400a77
Message:

KeyStoreUtil?: Implement system cert blacklist
Fix creation of empty keystore
test enhancements

Location:
core/java/src/net/i2p/crypto
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/crypto/CertUtil.java

    r2400a77 r5c4189ab  
    7878     */
    7979    public static String getSubjectValue(X509Certificate cert, String type) {
     80        X500Principal p = cert.getSubjectX500Principal();
     81        return getValue(p, type);
     82    }
     83
     84    /**
     85     *  Get a value out of the issuer distinguished name.
     86     *
     87     *  Warning - unsupported in Android (no javax.naming), returns null.
     88     *
     89     *  @param type e.g. "CN"
     90     *  @return value or null if not found
     91     *  @since 0.9.24
     92     */
     93    public static String getIssuerValue(X509Certificate cert, String type) {
     94        X500Principal p = cert.getIssuerX500Principal();
     95        return getValue(p, type);
     96    }
     97
     98    /**
     99     *  Get a value out of a X500Principal.
     100     *
     101     *  Warning - unsupported in Android (no javax.naming), returns null.
     102     *
     103     *  @param type e.g. "CN"
     104     *  @return value or null if not found
     105     */
     106    private static String getValue(X500Principal p, String type) {
    80107        if (SystemVersion.isAndroid()) {
    81108            error("Don't call this in Android", new UnsupportedOperationException("I did it"));
    82109            return null;
    83110        }
     111        if (p == null)
     112            return null;
    84113        type = type.toUpperCase(Locale.US);
    85         X500Principal p = cert.getSubjectX500Principal();
    86114        String subj = p.getName();
    87115        try {
  • core/java/src/net/i2p/crypto/KeyStoreUtil.java

    r2400a77 r5c4189ab  
    66import java.io.IOException;
    77import java.io.OutputStream;
     8import java.math.BigInteger;
    89import java.security.GeneralSecurityException;
    910import java.security.KeyStore;
     
    3637    private static final int DEFAULT_KEY_SIZE = 2048;
    3738    private static final int DEFAULT_KEY_VALID_DAYS = 3652;  // 10 years
     39
     40    /**
     41     *  No reports of these in a Java keystore but just to be safe...
     42     */
     43    private static final BigInteger[] BLACKLIST_SERIAL = new BigInteger[] {
     44        // Superfish http://blog.erratasec.com/2015/02/extracting-superfish-certificate.html
     45        new BigInteger("d2:fc:13:87:a9:44:dc:e7".replace(":", ""), 16),
     46        // eDellRoot https://www.reddit.com/r/technology/comments/3twmfv/dell_ships_laptops_with_rogue_root_ca_exactly/
     47        new BigInteger("6b:c5:7b:95:18:93:aa:97:4b:62:4a:c0:88:fc:3b:b6".replace(":", ""), 16)
     48    };
     49
     50    /**
     51     *  Corresponding issuer CN for the serial number.
     52     *  Must be same number of entries as BLACKLIST_SERIAL.
     53     *  See removeBlacklistedCerts() below for alternatives if we want
     54     *  to blacklist a cert without an issuer CN.
     55     */
     56    private static final String[] BLACKLIST_ISSUER_CN = new String[] {
     57        "Superfish, Inc.",
     58        "eDellRoot"
     59    };
    3860
    3961    /**
     
    6486            OutputStream fos = null;
    6587            try {
     88                // must be initted
     89                ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
    6690                fos = new SecureFileOutputStream(ksFile);
    6791                ks.store(fos, pwchars);
     
    111135        }
    112136
    113         if (!success) {
     137        if (success) {
     138            removeBlacklistedCerts(ks);
     139        } else {
    114140            try {
    115141                // must be initted
     
    172198                String alias = e.nextElement();
    173199                if (ks.isCertificateEntry(alias)) {
    174                     info("Found cert " + alias);
     200                    //info("Found cert " + alias);
    175201                    count++;
     202                }
     203            }
     204        } catch (GeneralSecurityException e) {}
     205        return count;
     206    }
     207
     208    /**
     209     *  Remove all blacklisted X509 Certs in a key store.
     210     *  Match by serial number and issuer CN, which should uniquely identify a cert,
     211     *  if the CN is present. Should be faster than fingerprints.
     212     *
     213     *  @return number successfully removed
     214     *  @since 0.9.24
     215     */
     216    private static int removeBlacklistedCerts(KeyStore ks) {
     217        // This matches on the CN in the issuer,
     218        // and we can't do that on Android.
     219        // We could just match the whole string, and we will have to
     220        // if we want do it on Android or match a cert that has an issuer without a CN.
     221        // Or, most certs that don't have a CN have an OU, that could be a fallback.
     222        // Or do sha1hash(cert.getEncoded()) but that would be slower.
     223        if (SystemVersion.isAndroid())
     224            return 0;
     225        int count = 0;
     226        try {
     227            for(Enumeration<String> e = ks.aliases(); e.hasMoreElements();) {
     228                String alias = e.nextElement();
     229                if (ks.isCertificateEntry(alias)) {
     230                    Certificate c = ks.getCertificate(alias);
     231                    if (c != null && (c instanceof X509Certificate)) {
     232                        X509Certificate xc = (X509Certificate) c;
     233                        BigInteger serial = xc.getSerialNumber();
     234                        for (int i = 0; i < BLACKLIST_SERIAL.length; i++) {
     235                            // debug:
     236                            //String xname = CertUtil.getIssuerValue(xc, "CN");
     237                            //info("Found \"" + xname + "\" s/n: " + serial.toString(16));
     238                            //if (xname == null)
     239                            //    info("name is null, full issuer: " + xc.getIssuerX500Principal().getName());
     240                            if (BLACKLIST_SERIAL[i].equals(serial)) {
     241                                String name = CertUtil.getIssuerValue(xc, "CN");
     242                                if (BLACKLIST_ISSUER_CN[i].equals(name)) {
     243                                    ks.deleteEntry(alias);
     244                                    warn("Ignoring blacklisted certificate \"" + alias +
     245                                         "\" issued by: \"" + name +
     246                                         "\" s/n: " + serial.toString(16), null);
     247                                    count++;
     248                                }
     249                            }
     250                        }
     251                    }
    176252                }
    177253            }
     
    514590/****
    515591    public static void main(String[] args) {
    516         try {
    517             if (args.length > 0) {
    518                 File ksf = new File(args[0]);
     592        File ksf = (args.length > 0) ? new File(args[0]) : null;
     593        try {
     594            if (ksf != null && !ksf.exists()) {
    519595                createKeyStore(ksf, DEFAULT_KEYSTORE_PASSWORD);
    520596                System.out.println("Created empty keystore " + ksf);
     
    525601                    int count = countCerts(ks);
    526602                    System.out.println("Found " + count + " certs");
     603                    if (ksf != null && ksf.isDirectory()) {
     604                        count = addCerts(ksf, ks);
     605                        System.out.println("Found " + count + " certs in " + ksf);
     606                        if (count > 0) {
     607                            // rerun blacklist as a test
     608                            count = removeBlacklistedCerts(ks);
     609                            if (count > 0)
     610                                System.out.println("Found " + count + " blacklisted certs in " + ksf);
     611                        }
     612                    }
    527613                } else {
    528614                    System.out.println("FAIL");
Note: See TracChangeset for help on using the changeset viewer.