EMMA Coverage Report (generated Fri Aug 23 16:39:17 PDT 2013)
[all classes][org.chromium.chrome.browser]

COVERAGE SUMMARY FOR SOURCE FILE [SSLClientCertificateRequest.java]

nameclass, %method, %block, %line, %
SSLClientCertificateRequest.java0%   (0/2)0%   (0/8)0%   (0/240)0%   (0/58)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class SSLClientCertificateRequest0%   (0/1)0%   (0/6)0%   (0/210)0%   (0/53)
SSLClientCertificateRequest (int): void 0%   (0/1)0%   (0/16)0%   (0/6)
access$002 (SSLClientCertificateRequest, String): String 0%   (0/1)0%   (0/5)0%   (0/1)
alias (String): void 0%   (0/1)0%   (0/7)0%   (0/2)
doInBackground (Void []): Void 0%   (0/1)0%   (0/107)0%   (0/25)
onPostExecute (Void): void 0%   (0/1)0%   (0/8)0%   (0/2)
selectClientCertificate (int, String [], byte [][], String, int): boolean 0%   (0/1)0%   (0/67)0%   (0/17)
     
class SSLClientCertificateRequest$10%   (0/1)0%   (0/2)0%   (0/30)0%   (0/6)
SSLClientCertificateRequest$1 (SSLClientCertificateRequest, String): void 0%   (0/1)0%   (0/9)0%   (0/1)
run (): void 0%   (0/1)0%   (0/21)0%   (0/5)

1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4 
5package org.chromium.chrome.browser;
6 
7import java.security.cert.CertificateEncodingException;
8import java.security.cert.X509Certificate;
9import java.security.Principal;
10import java.security.PrivateKey;
11import javax.security.auth.x500.X500Principal;
12 
13import android.app.Activity;
14import android.content.Context;
15import android.os.AsyncTask;
16import android.security.KeyChain;
17import android.security.KeyChainAliasCallback;
18import android.security.KeyChainException;
19import android.util.Log;
20 
21import org.chromium.base.ActivityStatus;
22import org.chromium.base.CalledByNative;
23import org.chromium.base.JNINamespace;
24import org.chromium.base.ThreadUtils;
25 
26@JNINamespace("chrome::android")
27class SSLClientCertificateRequest extends AsyncTask<Void, Void, Void>
28        implements KeyChainAliasCallback {
29 
30    static final String TAG = "SSLClientCertificateRequest";
31 
32    // ClientCertRequest models an asynchronous client certificate request on the Java side. Use
33    // selectClientCertificate() on the UI thread to start/create a new request, this will launch a
34    // system activity through KeyChain.choosePrivateKeyAlias() to let the user select a client
35    // certificate.
36    //
37    // The selected certificate will be sent back as a string alias, which is used to call
38    // KeyChain.getCertificateChain() and KeyChain.getPrivateKey(). Unfortunately, these APIs are
39    // blocking, thus can't be called from the UI thread.
40    //
41    // To solve this, start an AsyncTask when the alias is received. It will retrieve the
42    // certificate chain and private key in the background, then later send the result back to the
43    // UI thread.
44    //
45    private final int mNativePtr;
46    private String mAlias;
47    private byte[][] mEncodedChain;
48    private PrivateKey mPrivateKey;
49 
50    private SSLClientCertificateRequest(int nativePtr) {
51        mNativePtr = nativePtr;
52        mAlias = null;
53        mEncodedChain = null;
54        mPrivateKey = null;
55    }
56 
57    // KeyChainAliasCallback implementation
58    @Override
59    public void alias(final String alias) {
60        // This is called by KeyChainActivity in a background thread. Post task to handle the
61        // certificate selection on the UI thread.
62        ThreadUtils.runOnUiThread(new Runnable() {
63            @Override
64            public void run() {
65                if (alias == null) {
66                    // No certificate was selected.
67                    onPostExecute(null);
68                } else {
69                    mAlias = alias;
70                    // Launch background thread.
71                    execute();
72                }
73            }
74        });
75    }
76 
77    @Override
78    protected Void doInBackground(Void... params) {
79        // Executed in a background thread, can call blocking APIs.
80        X509Certificate[] chain = null;
81        PrivateKey key = null;
82        Context context = ActivityStatus.getActivity().getApplicationContext();
83        try {
84            key = KeyChain.getPrivateKey(context, mAlias);
85            chain = KeyChain.getCertificateChain(context, mAlias);
86        } catch (KeyChainException e) {
87            Log.w(TAG, "KeyChainException when looking for '" + mAlias + "' certificate");
88            return null;
89        } catch (InterruptedException e) {
90            Log.w(TAG, "InterruptedException when looking for '" + mAlias + "'certificate");
91            return null;
92        }
93 
94        if (key == null || chain == null || chain.length == 0) {
95            Log.w(TAG, "Empty client certificate chain?");
96            return null;
97        }
98 
99        // Get the encoded certificate chain.
100        byte[][] encoded_chain = new byte[chain.length][];
101        try {
102            for (int i = 0; i < chain.length; ++i) {
103                encoded_chain[i] = chain[i].getEncoded();
104            }
105        } catch (CertificateEncodingException e) {
106            Log.w(TAG, "Could not retrieve encoded certificate chain: " + e);
107            return null;
108        }
109 
110        mEncodedChain = encoded_chain;
111        mPrivateKey = key;
112        return null;
113    }
114 
115    @Override
116    protected void onPostExecute(Void result) {
117        // Back to the UI thread.
118        nativeOnSystemRequestCompletion(mNativePtr, mEncodedChain, mPrivateKey);
119    }
120 
121 
122    /**
123     * Create a new asynchronous request to select a client certificate.
124     *
125     * @param nativePtr The native object responsible for this request.
126     * @param keyTypes The list of supported key exchange types.
127     * @param encodedPrincipals The list of CA DistinguishedNames.
128     * @param host_name The server host name is available (empty otherwise).
129     * @param port The server port if available (0 otherwise).
130     * @return true on success.
131     * Note that nativeOnSystemRequestComplete will be called iff this method returns true.
132     */
133    @CalledByNative
134    static private boolean selectClientCertificate(
135            int nativePtr, String[] keyTypes, byte[][] encodedPrincipals, String hostName,
136            int port) {
137        ThreadUtils.assertOnUiThread();
138 
139        Activity activity = ActivityStatus.getActivity();
140        if (activity == null) {
141            Log.w(TAG, "No active Chromium main activity!?");
142            return false;
143        }
144 
145        // Build the list of principals from encoded versions.
146        Principal[] principals = null;
147        if (encodedPrincipals.length > 0) {
148            principals = new X500Principal[encodedPrincipals.length];
149            try {
150                for (int n = 0; n < encodedPrincipals.length; n++) {
151                    principals[n] = new X500Principal(encodedPrincipals[n]);
152                }
153            } catch (Exception e) {
154                // Bail on error.
155                Log.w(TAG, "Exception while decoding issuers list: " + e);
156                return false;
157            }
158        }
159 
160        // All good, create new request, add it to our list and launch the certificate selection
161        // activity.
162        SSLClientCertificateRequest request = new SSLClientCertificateRequest(nativePtr);
163 
164        KeyChain.choosePrivateKeyAlias(
165                activity, request, keyTypes, principals, hostName, port, null);
166        return true;
167    }
168 
169    // Called to pass request results to native side.
170    private static native void nativeOnSystemRequestCompletion(
171            int requestPtr, byte[][] certChain, PrivateKey privateKey);
172}

[all classes][org.chromium.chrome.browser]
EMMA 2.0.5312 (C) Vladimir Roubtsov