<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.net;

import android.util.Log;

import org.chromium.net.CertVerifyResultAndroid;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.List;

import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class X509Util {

    private static final String TAG = X509Util.class.getName();

    private static CertificateFactory sCertificateFactory;

    private static final String OID_TLS_SERVER_AUTH = "172.16.17.32.5.5.7.3.1";
    private static final String OID_ANY_EKU = "2.5.29.37.0";
    // Server-Gated Cryptography (necessary to support a few legacy issuers):
    //    Netscape:
    private static final String OID_SERVER_GATED_NETSCAPE = "2.16.840.1.113730.4.1";
    //    Microsoft:
    private static final String OID_SERVER_GATED_MICROSOFT = "172.16.17.32.4.1.311.10.3.3";

    /**
     * Trust manager backed up by the read-only system certificate store.
     */
    private static X509TrustManager sDefaultTrustManager;

    /**
     * Trust manager backed up by a custom certificate store. We need such manager to plant test
     * root CA to the trust store in testing.
     */
    private static X509TrustManager sTestTrustManager;
    private static KeyStore sTestKeyStore;

    /**
     * Lock object used to synchronize all calls that modify or depend on the trust managers.
     */
    private static final Object sLock = new Object();

    /**
     * Ensures that the trust managers and certificate factory are initialized.
     */
    private static void ensureInitialized() throws CertificateException,
            KeyStoreException, NoSuchAlgorithmException {
        synchronized(sLock) {
            if (sCertificateFactory == null) {
                sCertificateFactory = CertificateFactory.getInstance("X.509");
            }
            if (sDefaultTrustManager == null) {
                sDefaultTrustManager = X509Util.createTrustManager(null);
            }
            if (sTestKeyStore == null) {
                sTestKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                try {
                    sTestKeyStore.load(null);
                } catch(IOException e) {}  // No IO operation is attempted.
            }
            if (sTestTrustManager == null) {
                sTestTrustManager = X509Util.createTrustManager(sTestKeyStore);
            }
        }
    }

    /**
     * Creates a X509TrustManager backed up by the given key store. When null is passed as a key
     * store, system default trust store is used.
     * @throws KeyStoreException, NoSuchAlgorithmException on error initializing the TrustManager.
     */
    private static X509TrustManager createTrustManager(KeyStore keyStore) throws KeyStoreException,
            NoSuchAlgorithmException {
        String algorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
        tmf.init(keyStore);

        for (TrustManager tm : tmf.getTrustManagers()) {
            if (tm instanceof X509TrustManager) {
                return (X509TrustManager) tm;
            }
        }
        return null;
    }

    /**
     * After each modification of test key store, trust manager has to be generated again.
     */
    private static void reloadTestTrustManager() throws KeyStoreException,
            NoSuchAlgorithmException {
        sTestTrustManager = X509Util.createTrustManager(sTestKeyStore);
    }

    /**
     * Convert a DER encoded certificate to an X509Certificate.
     */
    public static X509Certificate createCertificateFromBytes(byte[] derBytes) throws
            CertificateException, KeyStoreException, NoSuchAlgorithmException {
        ensureInitialized();
        return (X509Certificate) sCertificateFactory.generateCertificate(
                new ByteArrayInputStream(derBytes));
    }

    public static void addTestRootCertificate(byte[] rootCertBytes) throws CertificateException,
            KeyStoreException, NoSuchAlgorithmException {
        ensureInitialized();
        X509Certificate rootCert = createCertificateFromBytes(rootCertBytes);
        synchronized (sLock) {
            sTestKeyStore.setCertificateEntry(
                    "root_cert_" + Integer.toString(sTestKeyStore.size()), rootCert);
            reloadTestTrustManager();
        }
    }

    public static void clearTestRootCertificates() throws NoSuchAlgorithmException,
            CertificateException, KeyStoreException {
        ensureInitialized();
        synchronized (sLock) {
            try {
                sTestKeyStore.load(null);
                reloadTestTrustManager();
            } catch (IOException e) {}  // No IO operation is attempted.
        }
    }

    /**
     * If an EKU extension is present in the end-entity certificate, it MUST contain either the
     * anyEKU or serverAuth or netscapeSGC or Microsoft SGC EKUs.
     *
     * @return true if there is no EKU extension or if any of the EKU extensions is one of the valid
     * OIDs for web server certificates.
     *
     * TODO(palmer): This can be removed after the equivalent change is made to the Android default
     * TrustManager and that change is shipped to a large majority of Android users.
     */
    static boolean verifyKeyUsage(X509Certificate certificate) throws CertificateException {
        List<String> ekuOids = certificate.getExtendedKeyUsage();
        if (ekuOids == null)
            return true;

        for (String ekuOid : ekuOids) {
            if (ekuOid.equals(OID_TLS_SERVER_AUTH) ||
                ekuOid.equals(OID_ANY_EKU) ||
                ekuOid.equals(OID_SERVER_GATED_NETSCAPE) ||
                ekuOid.equals(OID_SERVER_GATED_MICROSOFT)) {
                return true;
            }
        }

        return false;
    }

    public static int verifyServerCertificates(byte[][] certChain, String authType)
            throws KeyStoreException, NoSuchAlgorithmException {
        if (certChain == null || certChain.length == 0 || certChain[0] == null) {
            throw new IllegalArgumentException("Expected non-null and non-empty certificate " +
                    "chain passed as |certChain|. |certChain|=" + certChain);
        }

        try {
            ensureInitialized();
        } catch (CertificateException e) {
            return CertVerifyResultAndroid.VERIFY_FAILED;
        }

        X509Certificate[] serverCertificates = new X509Certificate[certChain.length];
        try {
            for (int i = 0; i < certChain.length; ++i) {
                serverCertificates[i] = createCertificateFromBytes(certChain[i]);
            }
        } catch (CertificateException e) {
            return CertVerifyResultAndroid.VERIFY_UNABLE_TO_PARSE;
        }

        // Expired and not yet valid certificates would be rejected by the trust managers, but the
        // trust managers report all certificate errors using the general CertificateException. In
        // order to get more granular error information, cert validity time range is being checked
        // separately.
        try {
            serverCertificates[0].checkValidity();
            if (!verifyKeyUsage(serverCertificates[0]))
                return CertVerifyResultAndroid.VERIFY_INCORRECT_KEY_USAGE;
        } catch (CertificateExpiredException e) {
            return CertVerifyResultAndroid.VERIFY_EXPIRED;
        } catch (CertificateNotYetValidException e) {
            return CertVerifyResultAndroid.VERIFY_NOT_YET_VALID;
        } catch (CertificateException e) {
            return CertVerifyResultAndroid.VERIFY_FAILED;
        }

        synchronized (sLock) {
            try {
                sDefaultTrustManager.checkServerTrusted(serverCertificates, authType);
                return CertVerifyResultAndroid.VERIFY_OK;
            } catch (CertificateException eDefaultManager) {
                try {
                    sTestTrustManager.checkServerTrusted(serverCertificates, authType);
                    return CertVerifyResultAndroid.VERIFY_OK;
                } catch (CertificateException eTestManager) {
                    // Neither of the trust managers confirms the validity of the certificate chain,
                    // log the error message returned by the system trust manager.
                    Log.i(TAG, "Failed to validate the certificate chain, error: " +
                              eDefaultManager.getMessage());
                    return CertVerifyResultAndroid.VERIFY_NO_TRUSTED_ROOT;
                }
            }
        }
    }
}
<commit_msg>Handle NullPointerException when verifying EKU extension.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.net;

import android.util.Log;

import org.chromium.net.CertVerifyResultAndroid;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.List;

import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class X509Util {

    private static final String TAG = X509Util.class.getName();

    private static CertificateFactory sCertificateFactory;

    private static final String OID_TLS_SERVER_AUTH = "172.16.17.32.5.5.7.3.1";
    private static final String OID_ANY_EKU = "2.5.29.37.0";
    // Server-Gated Cryptography (necessary to support a few legacy issuers):
    //    Netscape:
    private static final String OID_SERVER_GATED_NETSCAPE = "2.16.840.1.113730.4.1";
    //    Microsoft:
    private static final String OID_SERVER_GATED_MICROSOFT = "1.3.6.1.4.1.311.10.3.3";

    /**
     * Trust manager backed up by the read-only system certificate store.
     */
    private static X509TrustManager sDefaultTrustManager;

    /**
     * Trust manager backed up by a custom certificate store. We need such manager to plant test
     * root CA to the trust store in testing.
     */
    private static X509TrustManager sTestTrustManager;
    private static KeyStore sTestKeyStore;

    /**
     * Lock object used to synchronize all calls that modify or depend on the trust managers.
     */
    private static final Object sLock = new Object();

    /**
     * Ensures that the trust managers and certificate factory are initialized.
     */
    private static void ensureInitialized() throws CertificateException,
            KeyStoreException, NoSuchAlgorithmException {
        synchronized(sLock) {
            if (sCertificateFactory == null) {
                sCertificateFactory = CertificateFactory.getInstance("X.509");
            }
            if (sDefaultTrustManager == null) {
                sDefaultTrustManager = X509Util.createTrustManager(null);
            }
            if (sTestKeyStore == null) {
                sTestKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                try {
                    sTestKeyStore.load(null);
                } catch(IOException e) {}  // No IO operation is attempted.
            }
            if (sTestTrustManager == null) {
                sTestTrustManager = X509Util.createTrustManager(sTestKeyStore);
            }
        }
    }

    /**
     * Creates a X509TrustManager backed up by the given key store. When null is passed as a key
     * store, system default trust store is used.
     * @throws KeyStoreException, NoSuchAlgorithmException on error initializing the TrustManager.
     */
    private static X509TrustManager createTrustManager(KeyStore keyStore) throws KeyStoreException,
            NoSuchAlgorithmException {
        String algorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
        tmf.init(keyStore);

        for (TrustManager tm : tmf.getTrustManagers()) {
            if (tm instanceof X509TrustManager) {
                return (X509TrustManager) tm;
            }
        }
        return null;
    }

    /**
     * After each modification of test key store, trust manager has to be generated again.
     */
    private static void reloadTestTrustManager() throws KeyStoreException,
            NoSuchAlgorithmException {
        sTestTrustManager = X509Util.createTrustManager(sTestKeyStore);
    }

    /**
     * Convert a DER encoded certificate to an X509Certificate.
     */
    public static X509Certificate createCertificateFromBytes(byte[] derBytes) throws
            CertificateException, KeyStoreException, NoSuchAlgorithmException {
        ensureInitialized();
        return (X509Certificate) sCertificateFactory.generateCertificate(
                new ByteArrayInputStream(derBytes));
    }

    public static void addTestRootCertificate(byte[] rootCertBytes) throws CertificateException,
            KeyStoreException, NoSuchAlgorithmException {
        ensureInitialized();
        X509Certificate rootCert = createCertificateFromBytes(rootCertBytes);
        synchronized (sLock) {
            sTestKeyStore.setCertificateEntry(
                    "root_cert_" + Integer.toString(sTestKeyStore.size()), rootCert);
            reloadTestTrustManager();
        }
    }

    public static void clearTestRootCertificates() throws NoSuchAlgorithmException,
            CertificateException, KeyStoreException {
        ensureInitialized();
        synchronized (sLock) {
            try {
                sTestKeyStore.load(null);
                reloadTestTrustManager();
            } catch (IOException e) {}  // No IO operation is attempted.
        }
    }

    /**
     * If an EKU extension is present in the end-entity certificate, it MUST contain either the
     * anyEKU or serverAuth or netscapeSGC or Microsoft SGC EKUs.
     *
     * @return true if there is no EKU extension or if any of the EKU extensions is one of the valid
     * OIDs for web server certificates.
     *
     * TODO(palmer): This can be removed after the equivalent change is made to the Android default
     * TrustManager and that change is shipped to a large majority of Android users.
     */
    static boolean verifyKeyUsage(X509Certificate certificate) throws CertificateException {
        List<String> ekuOids;
        try {
            ekuOids = certificate.getExtendedKeyUsage();
        } catch (NullPointerException e) {
            // getExtendedKeyUsage() can crash due to an Android platform bug. This probably
            // happens when the EKU extension data is malformed so return false here.
            // See http://crbug.com/233610
            return false;
        }
        if (ekuOids == null)
            return true;

        for (String ekuOid : ekuOids) {
            if (ekuOid.equals(OID_TLS_SERVER_AUTH) ||
                ekuOid.equals(OID_ANY_EKU) ||
                ekuOid.equals(OID_SERVER_GATED_NETSCAPE) ||
                ekuOid.equals(OID_SERVER_GATED_MICROSOFT)) {
                return true;
            }
        }

        return false;
    }

    public static int verifyServerCertificates(byte[][] certChain, String authType)
            throws KeyStoreException, NoSuchAlgorithmException {
        if (certChain == null || certChain.length == 0 || certChain[0] == null) {
            throw new IllegalArgumentException("Expected non-null and non-empty certificate " +
                    "chain passed as |certChain|. |certChain|=" + certChain);
        }

        try {
            ensureInitialized();
        } catch (CertificateException e) {
            return CertVerifyResultAndroid.VERIFY_FAILED;
        }

        X509Certificate[] serverCertificates = new X509Certificate[certChain.length];
        try {
            for (int i = 0; i < certChain.length; ++i) {
                serverCertificates[i] = createCertificateFromBytes(certChain[i]);
            }
        } catch (CertificateException e) {
            return CertVerifyResultAndroid.VERIFY_UNABLE_TO_PARSE;
        }

        // Expired and not yet valid certificates would be rejected by the trust managers, but the
        // trust managers report all certificate errors using the general CertificateException. In
        // order to get more granular error information, cert validity time range is being checked
        // separately.
        try {
            serverCertificates[0].checkValidity();
            if (!verifyKeyUsage(serverCertificates[0]))
                return CertVerifyResultAndroid.VERIFY_INCORRECT_KEY_USAGE;
        } catch (CertificateExpiredException e) {
            return CertVerifyResultAndroid.VERIFY_EXPIRED;
        } catch (CertificateNotYetValidException e) {
            return CertVerifyResultAndroid.VERIFY_NOT_YET_VALID;
        } catch (CertificateException e) {
            return CertVerifyResultAndroid.VERIFY_FAILED;
        }

        synchronized (sLock) {
            try {
                sDefaultTrustManager.checkServerTrusted(serverCertificates, authType);
                return CertVerifyResultAndroid.VERIFY_OK;
            } catch (CertificateException eDefaultManager) {
                try {
                    sTestTrustManager.checkServerTrusted(serverCertificates, authType);
                    return CertVerifyResultAndroid.VERIFY_OK;
                } catch (CertificateException eTestManager) {
                    // Neither of the trust managers confirms the validity of the certificate chain,
                    // log the error message returned by the system trust manager.
                    Log.i(TAG, "Failed to validate the certificate chain, error: " +
                              eDefaultManager.getMessage());
                    return CertVerifyResultAndroid.VERIFY_NO_TRUSTED_ROOT;
                }
            }
        }
    }
}

{'fraction_non_alphanumeric': 0.07186390375748582, 'fraction_numerical': 0.013408235730563357, 'mean_word_length': 2.4573103700989374, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 10, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5006613', 'n_tokens_mistral': 4986, 'n_tokens_neox': 4679, 'n_words': 1337}