summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/main/java/org/mozilla/gecko/EnterpriseRoots.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/gecko/EnterpriseRoots.java')
-rw-r--r--mobile/android/geckoview/src/main/java/org/mozilla/gecko/EnterpriseRoots.java96
1 files changed, 96 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/EnterpriseRoots.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/EnterpriseRoots.java
new file mode 100644
index 0000000000..0aacef39a4
--- /dev/null
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/EnterpriseRoots.java
@@ -0,0 +1,96 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko;
+
+import android.util.Log;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import org.mozilla.gecko.annotation.WrapForJNI;
+
+// This class implements the functionality needed to find third-party root
+// certificates that have been added to the android CA store.
+public class EnterpriseRoots {
+ private static final String LOGTAG = "EnterpriseRoots";
+
+ // Gecko calls this function from C++ to find third-party root certificates
+ // it can use as trust anchors for TLS connections.
+ @WrapForJNI
+ private static byte[][] gatherEnterpriseRoots() {
+
+ // The KeyStore "AndroidCAStore" contains the certificates we're
+ // interested in.
+ final KeyStore ks;
+ try {
+ ks = KeyStore.getInstance("AndroidCAStore");
+ } catch (final KeyStoreException kse) {
+ Log.e(LOGTAG, "getInstance() failed", kse);
+ return new byte[0][0];
+ }
+ try {
+ ks.load(null);
+ } catch (final CertificateException ce) {
+ Log.e(LOGTAG, "load() failed", ce);
+ return new byte[0][0];
+ } catch (final IOException ioe) {
+ Log.e(LOGTAG, "load() failed", ioe);
+ return new byte[0][0];
+ } catch (final NoSuchAlgorithmException nsae) {
+ Log.e(LOGTAG, "load() failed", nsae);
+ return new byte[0][0];
+ }
+ // Given the KeyStore, we get an identifier for each object in it. For
+ // each one that is a Certificate, we try to distinguish between
+ // entries that shipped with the OS and entries that were added by the
+ // user or an administrator. The former we ignore and the latter we
+ // collect in an array of byte arrays and return.
+ final Enumeration<String> aliases;
+ try {
+ aliases = ks.aliases();
+ } catch (final KeyStoreException kse) {
+ Log.e(LOGTAG, "aliases() failed", kse);
+ return new byte[0][0];
+ }
+ final ArrayList<byte[]> roots = new ArrayList<byte[]>();
+ while (aliases.hasMoreElements()) {
+ final String alias = aliases.nextElement();
+ final boolean isCertificate;
+ try {
+ isCertificate = ks.isCertificateEntry(alias);
+ } catch (final KeyStoreException kse) {
+ Log.e(LOGTAG, "isCertificateEntry() failed", kse);
+ continue;
+ }
+ // Built-in certificate aliases start with "system:", whereas
+ // 3rd-party certificate aliases start with "user:". It's
+ // unfortunate to be relying on this implementation detail, but
+ // there appears to be no other way to differentiate between the
+ // two.
+ if (isCertificate && alias.startsWith("user:")) {
+ final Certificate certificate;
+ try {
+ certificate = ks.getCertificate(alias);
+ } catch (final KeyStoreException kse) {
+ Log.e(LOGTAG, "getCertificate() failed", kse);
+ continue;
+ }
+ try {
+ roots.add(certificate.getEncoded());
+ } catch (final CertificateEncodingException cee) {
+ Log.e(LOGTAG, "getEncoded() failed", cee);
+ }
+ }
+ }
+ Log.d(LOGTAG, "found " + roots.size() + " enterprise roots");
+ return roots.toArray(new byte[0][0]);
+ }
+}