FileDocCategorySizeDatePackage
CertificateChainValidator.javaAPI DocAndroid 5.1 API10620Thu Mar 12 22:22:10 GMT 2015android.net.http

CertificateChainValidator

public class CertificateChainValidator extends Object
Class responsible for all server certificate validation functionality {@hide}

Fields Summary
private static final String
TAG
private X509TrustManager
mTrustManager
Constructors Summary
private CertificateChainValidator()
Creates a new certificate chain validator. This is a private constructor. If you need a Certificate chain validator, call getInstance().

        try {
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("X.509");
            tmf.init((KeyStore) null);
            for (TrustManager tm : tmf.getTrustManagers()) {
                if (tm instanceof X509TrustManager) {
                    mTrustManager = (X509TrustManager) tm;
                }
            }
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("X.509 TrustManagerFactory must be available", e);
        } catch (KeyStoreException e) {
            throw new RuntimeException("X.509 TrustManagerFactory cannot be initialized", e);
        }

        if (mTrustManager == null) {
            throw new RuntimeException(
                    "None of the X.509 TrustManagers are X509TrustManager");
        }
    
Methods Summary
private voidcloseSocketThrowException(javax.net.ssl.SSLSocket socket, java.lang.String errorMessage, java.lang.String defaultErrorMessage)

        closeSocketThrowException(
            socket, errorMessage != null ? errorMessage : defaultErrorMessage);
    
private voidcloseSocketThrowException(javax.net.ssl.SSLSocket socket, java.lang.String errorMessage)

        if (HttpLog.LOGV) {
            HttpLog.v("validation error: " + errorMessage);
        }

        if (socket != null) {
            SSLSession session = socket.getSession();
            if (session != null) {
                session.invalidate();
            }

            socket.close();
        }

        throw new SSLHandshakeException(errorMessage);
    
public SslErrordoHandshakeAndValidateServerCertificates(HttpsConnection connection, javax.net.ssl.SSLSocket sslSocket, java.lang.String domain)
Performs the handshake and server certificates validation Notice a new chain will be rebuilt by tracing the issuer and subject before calling checkServerTrusted(). And if the last traced certificate is self issued and it is expired, it will be dropped.

param
sslSocket The secure connection socket
param
domain The website domain
return
An SSL error object if there is an error and null otherwise

        // get a valid SSLSession, close the socket if we fail
        SSLSession sslSession = sslSocket.getSession();
        if (!sslSession.isValid()) {
            closeSocketThrowException(sslSocket, "failed to perform SSL handshake");
        }

        // retrieve the chain of the server peer certificates
        Certificate[] peerCertificates =
            sslSocket.getSession().getPeerCertificates();

        if (peerCertificates == null || peerCertificates.length == 0) {
            closeSocketThrowException(
                sslSocket, "failed to retrieve peer certificates");
        } else {
            // update the SSL certificate associated with the connection
            if (connection != null) {
                if (peerCertificates[0] != null) {
                    connection.setCertificate(
                        new SslCertificate((X509Certificate)peerCertificates[0]));
                }
            }
        }

        return verifyServerDomainAndCertificates((X509Certificate[]) peerCertificates, domain, "RSA");
    
public static android.net.http.CertificateChainValidatorgetInstance()

return
The singleton instance of the certificates chain validator


                  
        
        return NoPreloadHolder.sInstance;
    
private javax.net.ssl.X509TrustManagergetTrustManager()
Returns the platform default {@link X509TrustManager}.

        return mTrustManager;
    
public static voidhandleTrustStorageUpdate()
Handles updates to credential storage.

        TrustManagerFactory tmf;
        try {
            tmf = TrustManagerFactory.getInstance("X.509");
            tmf.init((KeyStore) null);
        } catch (NoSuchAlgorithmException e) {
            Slog.w(TAG, "Couldn't find default X.509 TrustManagerFactory");
            return;
        } catch (KeyStoreException e) {
            Slog.w(TAG, "Couldn't initialize default X.509 TrustManagerFactory", e);
            return;
        }

        TrustManager[] tms = tmf.getTrustManagers();
        boolean sentUpdate = false;
        for (TrustManager tm : tms) {
            try {
                Method updateMethod = tm.getClass().getDeclaredMethod("handleTrustStorageUpdate");
                updateMethod.setAccessible(true);
                updateMethod.invoke(tm);
                sentUpdate = true;
            } catch (Exception e) {
            }
        }
        if (!sentUpdate) {
            Slog.w(TAG, "Didn't find a TrustManager to handle CA list update");
        }
    
public static SslErrorverifyServerCertificates(byte[][] certChain, java.lang.String domain, java.lang.String authType)
Similar to doHandshakeAndValidateServerCertificates but exposed to JNI for use by Chromium HTTPS stack to validate the cert chain.

param
certChain The bytes for certificates in ASN.1 DER encoded certificates format.
param
domain The full website hostname and domain
param
authType The authentication type for the cert chain
return
An SSL error object if there is an error and null otherwise


        if (certChain == null || certChain.length == 0) {
            throw new IllegalArgumentException("bad certificate chain");
        }

        X509Certificate[] serverCertificates = new X509Certificate[certChain.length];

        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            for (int i = 0; i < certChain.length; ++i) {
                serverCertificates[i] = (X509Certificate) cf.generateCertificate(
                        new ByteArrayInputStream(certChain[i]));
            }
        } catch (CertificateException e) {
            throw new IOException("can't read certificate", e);
        }

        return verifyServerDomainAndCertificates(serverCertificates, domain, authType);
    
private static SslErrorverifyServerDomainAndCertificates(java.security.cert.X509Certificate[] chain, java.lang.String domain, java.lang.String authType)
Common code of doHandshakeAndValidateServerCertificates and verifyServerCertificates. Calls DomainNamevalidator to verify the domain, and TrustManager to verify the certs.

param
chain the cert chain in X509 cert format.
param
domain The full website hostname and domain
param
authType The authentication type for the cert chain
return
An SSL error object if there is an error and null otherwise

        // check if the first certificate in the chain is for this site
        X509Certificate currCertificate = chain[0];
        if (currCertificate == null) {
            throw new IllegalArgumentException("certificate for this site is null");
        }

        boolean valid = domain != null
                && !domain.isEmpty()
                && NoPreloadHolder.sVerifier.verify(domain,
                        new DelegatingSSLSession.CertificateWrap(currCertificate));
        if (!valid) {
            if (HttpLog.LOGV) {
                HttpLog.v("certificate not for this host: " + domain);
            }
            return new SslError(SslError.SSL_IDMISMATCH, currCertificate);
        }

        try {
            X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultX509TrustManager();
            if (x509TrustManager instanceof TrustManagerImpl) {
                TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
                trustManager.checkServerTrusted(chain, authType, domain);
            } else {
                x509TrustManager.checkServerTrusted(chain, authType);
            }
            return null;  // No errors.
        } catch (GeneralSecurityException e) {
            if (HttpLog.LOGV) {
                HttpLog.v("failed to validate the certificate chain, error: " +
                    e.getMessage());
            }
            return new SslError(SslError.SSL_UNTRUSTED, currCertificate);
        }