tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

EnterpriseRoots.java (3677B)


      1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 package org.mozilla.gecko;
      7 
      8 import android.util.Log;
      9 import java.io.IOException;
     10 import java.security.KeyStore;
     11 import java.security.KeyStoreException;
     12 import java.security.NoSuchAlgorithmException;
     13 import java.security.cert.Certificate;
     14 import java.security.cert.CertificateEncodingException;
     15 import java.security.cert.CertificateException;
     16 import java.util.ArrayList;
     17 import java.util.Enumeration;
     18 import org.mozilla.gecko.annotation.WrapForJNI;
     19 
     20 // This class implements the functionality needed to find third-party root
     21 // certificates that have been added to the android CA store.
     22 public class EnterpriseRoots {
     23  private static final String LOGTAG = "EnterpriseRoots";
     24 
     25  // Gecko calls this function from C++ to find third-party root certificates
     26  // it can use as trust anchors for TLS connections.
     27  @WrapForJNI
     28  private static byte[][] gatherEnterpriseRoots() {
     29 
     30    // The KeyStore "AndroidCAStore" contains the certificates we're
     31    // interested in.
     32    final KeyStore ks;
     33    try {
     34      ks = KeyStore.getInstance("AndroidCAStore");
     35    } catch (final KeyStoreException kse) {
     36      Log.e(LOGTAG, "getInstance() failed", kse);
     37      return new byte[0][0];
     38    }
     39    try {
     40      ks.load(null);
     41    } catch (final CertificateException ce) {
     42      Log.e(LOGTAG, "load() failed", ce);
     43      return new byte[0][0];
     44    } catch (final IOException ioe) {
     45      Log.e(LOGTAG, "load() failed", ioe);
     46      return new byte[0][0];
     47    } catch (final NoSuchAlgorithmException nsae) {
     48      Log.e(LOGTAG, "load() failed", nsae);
     49      return new byte[0][0];
     50    }
     51    // Given the KeyStore, we get an identifier for each object in it. For
     52    // each one that is a Certificate, we try to distinguish between
     53    // entries that shipped with the OS and entries that were added by the
     54    // user or an administrator. The former we ignore and the latter we
     55    // collect in an array of byte arrays and return.
     56    final Enumeration<String> aliases;
     57    try {
     58      aliases = ks.aliases();
     59    } catch (final KeyStoreException kse) {
     60      Log.e(LOGTAG, "aliases() failed", kse);
     61      return new byte[0][0];
     62    }
     63    final ArrayList<byte[]> roots = new ArrayList<byte[]>();
     64    while (aliases.hasMoreElements()) {
     65      final String alias = aliases.nextElement();
     66      final boolean isCertificate;
     67      try {
     68        isCertificate = ks.isCertificateEntry(alias);
     69      } catch (final KeyStoreException kse) {
     70        Log.e(LOGTAG, "isCertificateEntry() failed", kse);
     71        continue;
     72      }
     73      // Built-in certificate aliases start with "system:", whereas
     74      // 3rd-party certificate aliases start with "user:". It's
     75      // unfortunate to be relying on this implementation detail, but
     76      // there appears to be no other way to differentiate between the
     77      // two.
     78      if (isCertificate && alias.startsWith("user:")) {
     79        final Certificate certificate;
     80        try {
     81          certificate = ks.getCertificate(alias);
     82        } catch (final KeyStoreException kse) {
     83          Log.e(LOGTAG, "getCertificate() failed", kse);
     84          continue;
     85        }
     86        try {
     87          roots.add(certificate.getEncoded());
     88        } catch (final CertificateEncodingException cee) {
     89          Log.e(LOGTAG, "getEncoded() failed", cee);
     90        }
     91      }
     92    }
     93    Log.d(LOGTAG, "found " + roots.size() + " enterprise roots");
     94    return roots.toArray(new byte[0][0]);
     95  }
     96 }