Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / chrome / android / java / src / org / chromium / chrome / browser / CertificateViewer.java
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
5 package org.chromium.chrome.browser;
6
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;
21
22 import org.chromium.chrome.R;
23
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;
31
32 /**
33  * UI component for displaying certificate information.
34  */
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;
42
43     /**
44      * Show a dialog with the provided certificate information.
45      *
46      * @param context The context this view should display in.
47      * @param derData DER-encoded data representing a X509 certificate chain.
48      */
49     public static void showCertificateChain(Context context, byte[][] derData) {
50         CertificateViewer viewer = new CertificateViewer(context);
51         viewer.showCertificateChain(derData);
52     }
53
54     private CertificateViewer(Context context) {
55         mContext = 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;
60     }
61
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]);
67         }
68         ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(mContext,
69                 android.R.layout.simple_spinner_item,
70                 mTitles);
71         arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
72
73         Spinner spinner = new Spinner(mContext);
74         spinner.setAdapter(arrayAdapter);
75         spinner.setOnItemSelectedListener(this);
76
77         LinearLayout container = new LinearLayout(mContext);
78         container.setOrientation(LinearLayout.VERTICAL);
79         container.addView(spinner);
80
81         for (int i = 0; i < mViews.size(); ++i) {
82             LinearLayout certificateView = mViews.get(i);
83             if (i != 0) {
84                 certificateView.setVisibility(LinearLayout.GONE);
85             }
86             container.addView(certificateView);
87         }
88
89         showDialogForView(container);
90     }
91
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));
101         dialog.show();
102     }
103
104     private void addCertificate(byte[] derData) {
105         try {
106             if (mCertificateFactory == null) {
107                 mCertificateFactory = CertificateFactory.getInstance(X_509);
108             }
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());
114         }
115     }
116
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);
121
122         X509Certificate x509 = (X509Certificate) cert;
123         SslCertificate sslCert = new SslCertificate(x509);
124
125         mTitles.add(sslCert.getIssuedTo().getCName());
126
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(), ':'));
136
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());
144
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()));
151
152         addSectionTitle(certificateView, nativeGetCertFingerprintsText());
153         addItem(certificateView, nativeGetCertSHA256FingerprintText(),
154                 formatBytes(sha256Digest, ' '));
155         addItem(certificateView, nativeGetCertSHA1FingerprintText(),
156                 formatBytes(sha1Digest, ' '));
157     }
158
159     private void addSectionTitle(LinearLayout certificateView, String label) {
160         TextView title = addLabel(certificateView, label);
161         title.setAllCaps(true);
162     }
163
164     private void addItem(LinearLayout certificateView, String label, String value) {
165         if (value.isEmpty()) return;
166
167         addLabel(certificateView, label);
168         addValue(certificateView, value);
169     }
170
171     private TextView addLabel(LinearLayout certificateView, String label) {
172         TextView t = new TextView(mContext);
173         t.setPadding(mPadding, mPadding / 2, mPadding, 0);
174         t.setText(label);
175         t.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
176         certificateView.addView(t);
177         return t;
178     }
179
180     private void addValue(LinearLayout certificateView, String value) {
181         TextView t = new TextView(mContext);
182         t.setText(value);
183         t.setPadding(mPadding, 0, mPadding, mPadding / 2);
184         certificateView.addView(t);
185     }
186
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);
193             }
194         }
195         return sb.toString();
196     }
197
198     private static byte[] getDigest(byte[] bytes, String algorithm) {
199         try {
200             MessageDigest md = MessageDigest.getInstance(algorithm);
201             md.update(bytes);
202             return md.digest();
203         } catch (java.security.NoSuchAlgorithmException e) {
204             return null;
205         }
206     }
207
208     @Override
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);
213         }
214     }
215
216     @Override
217     public void onNothingSelected(AdapterView<?> parent) {
218     }
219
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();
232 }