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.
5 package org.chromium.chrome.browser;
7 import android.app.Dialog;
8 import android.content.Context;
9 import android.graphics.Typeface;
10 import android.net.http.SslCertificate;
11 import android.text.format.DateFormat;
12 import android.util.Log;
13 import android.view.View;
14 import android.widget.AdapterView;
15 import android.widget.AdapterView.OnItemSelectedListener;
16 import android.widget.ArrayAdapter;
17 import android.widget.LinearLayout;
18 import android.widget.ScrollView;
19 import android.widget.Spinner;
20 import android.widget.TextView;
22 import org.chromium.chrome.R;
24 import java.io.ByteArrayInputStream;
25 import java.security.MessageDigest;
26 import java.security.cert.Certificate;
27 import java.security.cert.CertificateException;
28 import java.security.cert.CertificateFactory;
29 import java.security.cert.X509Certificate;
30 import java.util.ArrayList;
33 * UI component for displaying certificate information.
35 class CertificateViewer implements OnItemSelectedListener {
36 private static final String X_509 = "X.509";
37 private final Context mContext;
38 private final ArrayList<LinearLayout> mViews;
39 private final ArrayList<String> mTitles;
40 private final int mPadding;
41 private CertificateFactory mCertificateFactory;
44 * Show a dialog with the provided certificate information.
46 * @param context The context this view should display in.
47 * @param derData DER-encoded data representing a X509 certificate chain.
49 public static void showCertificateChain(Context context, byte[][] derData) {
50 CertificateViewer viewer = new CertificateViewer(context);
51 viewer.showCertificateChain(derData);
54 private CertificateViewer(Context context) {
56 mViews = new ArrayList<LinearLayout>();
57 mTitles = new ArrayList<String>();
58 mPadding = (int) context.getResources().getDimension(
59 R.dimen.certificate_viewer_padding_wide) / 2;
62 // Show information about an array of DER-encoded data representing a X509 certificate chain.
63 // A spinner will be displayed allowing the user to select which certificate to display.
64 private void showCertificateChain(byte[][] derData) {
65 for (int i = 0; i < derData.length; i++) {
66 addCertificate(derData[i]);
68 ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(mContext,
69 android.R.layout.simple_spinner_item,
71 arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
73 Spinner spinner = new Spinner(mContext);
74 spinner.setAdapter(arrayAdapter);
75 spinner.setOnItemSelectedListener(this);
77 LinearLayout container = new LinearLayout(mContext);
78 container.setOrientation(LinearLayout.VERTICAL);
79 container.addView(spinner);
81 for (int i = 0; i < mViews.size(); ++i) {
82 LinearLayout certificateView = mViews.get(i);
84 certificateView.setVisibility(LinearLayout.GONE);
86 container.addView(certificateView);
89 showDialogForView(container);
92 // Displays a dialog with scrolling for the given view.
93 private void showDialogForView(View view) {
94 Dialog dialog = new Dialog(mContext);
95 dialog.setTitle(R.string.certtitle);
96 ScrollView scrollView = new ScrollView(mContext);
97 scrollView.addView(view);
98 dialog.addContentView(scrollView,
99 new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
100 LinearLayout.LayoutParams.MATCH_PARENT));
104 private void addCertificate(byte[] derData) {
106 if (mCertificateFactory == null) {
107 mCertificateFactory = CertificateFactory.getInstance(X_509);
109 Certificate cert = mCertificateFactory.generateCertificate(
110 new ByteArrayInputStream(derData));
111 addCertificateDetails(cert, getDigest(derData, "SHA-256"), getDigest(derData, "SHA-1"));
112 } catch (CertificateException e) {
113 Log.e("CertViewer", "Error parsing certificate" + e.toString());
117 private void addCertificateDetails(Certificate cert, byte[] sha256Digest, byte[] sha1Digest) {
118 LinearLayout certificateView = new LinearLayout(mContext);
119 mViews.add(certificateView);
120 certificateView.setOrientation(LinearLayout.VERTICAL);
122 X509Certificate x509 = (X509Certificate) cert;
123 SslCertificate sslCert = new SslCertificate(x509);
125 mTitles.add(sslCert.getIssuedTo().getCName());
127 addSectionTitle(certificateView, nativeGetCertIssuedToText());
128 addItem(certificateView, nativeGetCertInfoCommonNameText(),
129 sslCert.getIssuedTo().getCName());
130 addItem(certificateView, nativeGetCertInfoOrganizationText(),
131 sslCert.getIssuedTo().getOName());
132 addItem(certificateView, nativeGetCertInfoOrganizationUnitText(),
133 sslCert.getIssuedTo().getUName());
134 addItem(certificateView, nativeGetCertInfoSerialNumberText(),
135 formatBytes(x509.getSerialNumber().toByteArray(), ':'));
137 addSectionTitle(certificateView, nativeGetCertIssuedByText());
138 addItem(certificateView, nativeGetCertInfoCommonNameText(),
139 sslCert.getIssuedBy().getCName());
140 addItem(certificateView, nativeGetCertInfoOrganizationText(),
141 sslCert.getIssuedBy().getOName());
142 addItem(certificateView, nativeGetCertInfoOrganizationUnitText(),
143 sslCert.getIssuedBy().getUName());
145 addSectionTitle(certificateView, nativeGetCertValidityText());
146 java.text.DateFormat dateFormat = DateFormat.getDateFormat(mContext);
147 addItem(certificateView, nativeGetCertIssuedOnText(),
148 dateFormat.format(sslCert.getValidNotBeforeDate()));
149 addItem(certificateView, nativeGetCertExpiresOnText(),
150 dateFormat.format(sslCert.getValidNotAfterDate()));
152 addSectionTitle(certificateView, nativeGetCertFingerprintsText());
153 addItem(certificateView, nativeGetCertSHA256FingerprintText(),
154 formatBytes(sha256Digest, ' '));
155 addItem(certificateView, nativeGetCertSHA1FingerprintText(),
156 formatBytes(sha1Digest, ' '));
159 private void addSectionTitle(LinearLayout certificateView, String label) {
160 TextView title = addLabel(certificateView, label);
161 title.setAllCaps(true);
164 private void addItem(LinearLayout certificateView, String label, String value) {
165 if (value.isEmpty()) return;
167 addLabel(certificateView, label);
168 addValue(certificateView, value);
171 private TextView addLabel(LinearLayout certificateView, String label) {
172 TextView t = new TextView(mContext);
173 t.setPadding(mPadding, mPadding / 2, mPadding, 0);
175 t.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
176 certificateView.addView(t);
180 private void addValue(LinearLayout certificateView, String value) {
181 TextView t = new TextView(mContext);
183 t.setPadding(mPadding, 0, mPadding, mPadding / 2);
184 certificateView.addView(t);
187 private static String formatBytes(byte[] bytes, char separator) {
188 StringBuilder sb = new StringBuilder();
189 for (int i = 0; i < bytes.length; i++) {
190 sb.append(String.format("%02X", bytes[i]));
191 if (i != bytes.length - 1) {
192 sb.append(separator);
195 return sb.toString();
198 private static byte[] getDigest(byte[] bytes, String algorithm) {
200 MessageDigest md = MessageDigest.getInstance(algorithm);
203 } catch (java.security.NoSuchAlgorithmException e) {
209 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
210 for (int i = 0; i < mViews.size(); ++i) {
211 mViews.get(i).setVisibility(
212 i == position ? LinearLayout.VISIBLE : LinearLayout.GONE);
217 public void onNothingSelected(AdapterView<?> parent) {
220 private static native String nativeGetCertIssuedToText();
221 private static native String nativeGetCertInfoCommonNameText();
222 private static native String nativeGetCertInfoOrganizationText();
223 private static native String nativeGetCertInfoSerialNumberText();
224 private static native String nativeGetCertInfoOrganizationUnitText();
225 private static native String nativeGetCertIssuedByText();
226 private static native String nativeGetCertValidityText();
227 private static native String nativeGetCertIssuedOnText();
228 private static native String nativeGetCertExpiresOnText();
229 private static native String nativeGetCertFingerprintsText();
230 private static native String nativeGetCertSHA256FingerprintText();
231 private static native String nativeGetCertSHA1FingerprintText();