Main.java Source code

Java tutorial

Introduction

Here is the source code for Main.java

Source

//package com.java2s;
// Use of this source code is governed by a BSD-style license that can be

import android.util.Log;
import android.util.Pair;

import java.io.File;

import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.Certificate;

import java.security.cert.X509Certificate;

import java.util.Set;

import javax.security.auth.x500.X500Principal;

public class Main {
    private static final String TAG = "X509Util";
    /**
     * The system key store. This is used to determine whether a trust anchor is a system trust
     * anchor or user-installed.
     */
    private static KeyStore sSystemKeyStore;
    /**
     * The directory where system certificates are stored. This is used to determine whether a
     * trust anchor is a system trust anchor or user-installed. The KeyStore API alone is not
     * sufficient to efficiently query whether a given X500Principal, PublicKey pair is a trust
     * anchor.
     */
    private static File sSystemCertificateDirectory;
    /**
     * An in-memory cache of which trust anchors are system trust roots. This avoids reading and
     * decoding the root from disk on every verification. Mirrors a similar in-memory cache in
     * Conscrypt's X509TrustManager implementation.
     */
    private static Set<Pair<X500Principal, PublicKey>> sSystemTrustAnchorCache;
    /**
     * Lock object used to synchronize all calls that modify or depend on the trust managers.
     */
    private static final Object sLock = new Object();
    private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
            'e', 'f', };

    private static boolean isKnownRoot(X509Certificate root) throws NoSuchAlgorithmException, KeyStoreException {
        assert Thread.holdsLock(sLock);

        // Could not find the system key store. Conservatively report false.
        if (sSystemKeyStore == null)
            return false;

        // Check the in-memory cache first; avoid decoding the anchor from disk
        // if it has been seen before.
        Pair<X500Principal, PublicKey> key = new Pair<X500Principal, PublicKey>(root.getSubjectX500Principal(),
                root.getPublicKey());

        if (sSystemTrustAnchorCache.contains(key))
            return true;

        // Note: It is not sufficient to call sSystemKeyStore.getCertificiateAlias. If the server
        // supplies a copy of a trust anchor, X509TrustManagerExtensions returns the server's
        // version rather than the system one. getCertificiateAlias will then fail to find an anchor
        // name. This is fixed upstream in https://android-review.googlesource.com/#/c/91605/
        //
        // TODO(davidben): When the change trickles into an Android release, query sSystemKeyStore
        // directly.

        // System trust anchors are stored under a hash of the principal. In case of collisions,
        // a number is appended.
        String hash = hashPrincipal(root.getSubjectX500Principal());
        for (int i = 0; true; i++) {
            String alias = hash + '.' + i;
            if (!new File(sSystemCertificateDirectory, alias).exists())
                break;

            Certificate anchor = sSystemKeyStore.getCertificate("system:" + alias);
            // It is possible for this to return null if the user deleted a trust anchor. In
            // that case, the certificate remains in the system directory but is also added to
            // another file. Continue iterating as there may be further collisions after the
            // deleted anchor.
            if (anchor == null)
                continue;

            if (!(anchor instanceof X509Certificate)) {
                // This should never happen.
                String className = anchor.getClass().getName();
                Log.e(TAG, "Anchor " + alias + " not an X509Certificate: " + className);
                continue;
            }

            // If the subject and public key match, this is a system root.
            X509Certificate anchorX509 = (X509Certificate) anchor;
            if (root.getSubjectX500Principal().equals(anchorX509.getSubjectX500Principal())
                    && root.getPublicKey().equals(anchorX509.getPublicKey())) {
                sSystemTrustAnchorCache.add(key);
                return true;
            }
        }

        return false;
    }

    private static String hashPrincipal(X500Principal principal) throws NoSuchAlgorithmException {
        // Android hashes a principal as the first four bytes of its MD5 digest, encoded in
        // lowercase hex and reversed. Verified in 4.2, 4.3, and 4.4.
        byte[] digest = MessageDigest.getInstance("MD5").digest(principal.getEncoded());
        char[] hexChars = new char[8];
        for (int i = 0; i < 4; i++) {
            hexChars[2 * i] = HEX_DIGITS[(digest[3 - i] >> 4) & 0xf];
            hexChars[2 * i + 1] = HEX_DIGITS[digest[3 - i] & 0xf];
        }
        return new String(hexChars);
    }
}