1 /* ownCloud Android client application
2 * Copyright (C) 2012-2014 ownCloud Inc.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2,
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 package com
.owncloud
.android
.ui
.dialog
;
19 import java
.io
.IOException
;
20 import java
.security
.GeneralSecurityException
;
21 import java
.security
.KeyStoreException
;
22 import java
.security
.NoSuchAlgorithmException
;
23 import java
.security
.cert
.CertificateException
;
24 import java
.security
.cert
.X509Certificate
;
25 import java
.util
.Date
;
26 import java
.util
.HashMap
;
29 import javax
.security
.auth
.x500
.X500Principal
;
31 import com
.owncloud
.android
.R
;
32 import com
.owncloud
.android
.authentication
.AuthenticatorActivity
;
33 import com
.owncloud
.android
.lib
.common
.network
.NetworkUtils
;
34 import com
.owncloud
.android
.utils
.Log_OC
;
36 import android
.app
.Activity
;
37 import android
.app
.Dialog
;
38 import android
.content
.Context
;
39 import android
.os
.Bundle
;
40 import android
.view
.LayoutInflater
;
41 import android
.view
.View
;
42 import android
.view
.View
.OnClickListener
;
43 import android
.view
.ViewGroup
;
44 import android
.view
.Window
;
45 import android
.webkit
.SslErrorHandler
;
46 import android
.widget
.Button
;
47 import android
.widget
.TextView
;
50 * Dialog to show an Untrusted Certificate
55 public class SslUntrustedCertDialog
extends SslUntrustedCertDialogABSTRACT
{
57 private final static String TAG
= SslUntrustedCertDialog
.class.getSimpleName();
59 private X509Certificate mCertificate
;
61 private SslErrorHandler mHandler
;
63 private OnSslUntrustedCertListener mListener
;
65 public SslUntrustedCertDialog() {
68 public SslUntrustedCertDialog(X509Certificate cert
, OnSslUntrustedCertListener listener
, SslErrorHandler handler
) {
74 public static SslUntrustedCertDialog
newInstance(Context context
, X509Certificate cert
, OnSslUntrustedCertListener listener
,
75 SslErrorHandler handler
) {
77 SslUntrustedCertDialog dialog
= new SslUntrustedCertDialog(cert
, listener
, handler
);
85 public void onCreate(Bundle savedInstanceState
) {
86 super.onCreate(savedInstanceState
);
87 setRetainInstance(true
);
92 public View
onCreateView(LayoutInflater inflater
, ViewGroup container
, Bundle savedInstanceState
) {
93 // Create a view by inflating desired layout
94 mView
= inflater
.inflate(R
.layout
.ssl_untrusted_cert_layout
, container
, false
);
96 Button ok
= (Button
) mView
.findViewById(R
.id
.untrusted_ok
);
97 ok
.setOnClickListener(new OnClickListener() {
100 public void onClick(View v
) {
104 if (mListener
!= null
) {
105 ((AuthenticatorActivity
)getSherlockActivity()).reloadWebView();
109 Log_OC
.d(TAG
, "Nobody there to notify the certificate was saved");
111 } catch (GeneralSecurityException e
) {
113 if (mListener
!= null
) {
114 ((AuthenticatorActivity
)getSherlockActivity()).cancelWebView();
115 mListener
.onFailedSavingCertificate();
117 Log_OC
.e(TAG
, "Server certificate could not be saved in the known servers trust store ", e
);
119 } catch (IOException e
) {
121 if (mListener
!= null
) {
122 ((AuthenticatorActivity
)getSherlockActivity()).cancelWebView();
123 mListener
.onFailedSavingCertificate();
125 Log_OC
.e(TAG
, "Server certificate could not be saved in the known servers trust store ", e
);
131 Button cancel
= (Button
) mView
.findViewById(R
.id
.untrusted_cancel
);
132 cancel
.setOnClickListener(new OnClickListener() {
135 public void onClick(View v
) {
136 getDialog().cancel();
137 ((AuthenticatorActivity
)getSherlockActivity()).cancelWebView();
141 Button details
= (Button
) mView
.findViewById(R
.id
.untrusted_details_btn
);
142 details
.setOnClickListener(new OnClickListener() {
145 public void onClick(View v
) {
146 View detailsScroll
= mView
.findViewById(R
.id
.untrusted_details_scroll
);
147 if (detailsScroll
.getVisibility() == View
.VISIBLE
) {
148 detailsScroll
.setVisibility(View
.GONE
);
149 ((Button
) v
).setText(R
.string
.ssl_validator_btn_details_see
);
152 detailsScroll
.setVisibility(View
.VISIBLE
);
153 ((Button
) v
).setText(R
.string
.ssl_validator_btn_details_hide
);
155 showCertificateData(mCertificate
);
165 public Dialog
onCreateDialog(Bundle savedInstanceState
) {
166 final Dialog dialog
= super.onCreateDialog(savedInstanceState
);
167 dialog
.requestWindowFeature(Window
.FEATURE_NO_TITLE
);
173 public void onDestroyView() {
174 if (getDialog() != null
&& getRetainInstance())
175 getDialog().setDismissMessage(null
);
176 super.onDestroyView();
179 private void showCertificateData(X509Certificate cert
) {
181 TextView nullCerView
= (TextView
) mView
.findViewById(R
.id
.untrusted_null_cert
);
184 nullCerView
.setVisibility(View
.GONE
);
185 showSubject(cert
.getSubjectX500Principal());
186 showIssuer(cert
.getIssuerX500Principal());
187 showValidity(cert
.getNotBefore(), cert
.getNotAfter());
191 nullCerView
.setVisibility(View
.VISIBLE
);
195 private void showSignature(X509Certificate cert
) {
196 TextView sigView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_signature
));
197 TextView algorithmView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_signature_algorithm
));
198 sigView
.setText(getHex(cert
.getSignature()));
199 algorithmView
.setText(cert
.getSigAlgName());
202 public String
getHex(final byte [] raw
) {
206 final StringBuilder hex
= new StringBuilder(2 * raw
.length
);
207 for (final byte b
: raw
) {
208 final int hiVal
= (b
& 0xF0) >> 4;
209 final int loVal
= b
& 0x0F;
210 hex
.append((char) ('0' + (hiVal
+ (hiVal
/ 10 * 7))));
211 hex
.append((char) ('0' + (loVal
+ (loVal
/ 10 * 7))));
213 return hex
.toString();
216 @SuppressWarnings("deprecation")
217 private void showValidity(Date notBefore
, Date notAfter
) {
218 TextView fromView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_validity_from
));
219 TextView toView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_validity_to
));
220 fromView
.setText(notBefore
.toLocaleString());
221 toView
.setText(notAfter
.toLocaleString());
224 private void showSubject(X500Principal subject
) {
225 Map
<String
, String
> s
= parsePrincipal(subject
);
226 TextView cnView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_subject_CN
));
227 TextView oView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_subject_O
));
228 TextView ouView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_subject_OU
));
229 TextView cView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_subject_C
));
230 TextView stView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_subject_ST
));
231 TextView lView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_subject_L
));
233 if (s
.get("CN") != null
) {
234 cnView
.setText(s
.get("CN"));
235 cnView
.setVisibility(View
.VISIBLE
);
237 cnView
.setVisibility(View
.GONE
);
239 if (s
.get("O") != null
) {
240 oView
.setText(s
.get("O"));
241 oView
.setVisibility(View
.VISIBLE
);
243 oView
.setVisibility(View
.GONE
);
245 if (s
.get("OU") != null
) {
246 ouView
.setText(s
.get("OU"));
247 ouView
.setVisibility(View
.VISIBLE
);
249 ouView
.setVisibility(View
.GONE
);
251 if (s
.get("C") != null
) {
252 cView
.setText(s
.get("C"));
253 cView
.setVisibility(View
.VISIBLE
);
255 cView
.setVisibility(View
.GONE
);
257 if (s
.get("ST") != null
) {
258 stView
.setText(s
.get("ST"));
259 stView
.setVisibility(View
.VISIBLE
);
261 stView
.setVisibility(View
.GONE
);
263 if (s
.get("L") != null
) {
264 lView
.setText(s
.get("L"));
265 lView
.setVisibility(View
.VISIBLE
);
267 lView
.setVisibility(View
.GONE
);
271 private void showIssuer(X500Principal issuer
) {
272 Map
<String
, String
> s
= parsePrincipal(issuer
);
273 TextView cnView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_issuer_CN
));
274 TextView oView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_issuer_O
));
275 TextView ouView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_issuer_OU
));
276 TextView cView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_issuer_C
));
277 TextView stView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_issuer_ST
));
278 TextView lView
= ((TextView
)mView
.findViewById(R
.id
.untrusted_value_issuer_L
));
280 if (s
.get("CN") != null
) {
281 cnView
.setText(s
.get("CN"));
282 cnView
.setVisibility(View
.VISIBLE
);
284 cnView
.setVisibility(View
.GONE
);
286 if (s
.get("O") != null
) {
287 oView
.setText(s
.get("O"));
288 oView
.setVisibility(View
.VISIBLE
);
290 oView
.setVisibility(View
.GONE
);
292 if (s
.get("OU") != null
) {
293 ouView
.setText(s
.get("OU"));
294 ouView
.setVisibility(View
.VISIBLE
);
296 ouView
.setVisibility(View
.GONE
);
298 if (s
.get("C") != null
) {
299 cView
.setText(s
.get("C"));
300 cView
.setVisibility(View
.VISIBLE
);
302 cView
.setVisibility(View
.GONE
);
304 if (s
.get("ST") != null
) {
305 stView
.setText(s
.get("ST"));
306 stView
.setVisibility(View
.VISIBLE
);
308 stView
.setVisibility(View
.GONE
);
310 if (s
.get("L") != null
) {
311 lView
.setText(s
.get("L"));
312 lView
.setVisibility(View
.VISIBLE
);
314 lView
.setVisibility(View
.GONE
);
319 private Map
<String
, String
> parsePrincipal(X500Principal principal
) {
320 Map
<String
, String
> result
= new HashMap
<String
, String
>();
321 String toParse
= principal
.getName();
322 String
[] pieces
= toParse
.split(",");
323 String
[] tokens
= {"CN", "O", "OU", "C", "ST", "L"};
324 for (int i
=0; i
< pieces
.length
; i
++) {
325 for (int j
=0; j
<tokens
.length
; j
++) {
326 if (pieces
[i
].startsWith(tokens
[j
] + "=")) {
327 result
.put(tokens
[j
], pieces
[i
].substring(tokens
[j
].length()+1));
334 private void saveServerCert() throws KeyStoreException
, NoSuchAlgorithmException
, CertificateException
, IOException
{
335 if (mCertificate
!= null
) {
336 // TODO make this asynchronously, it can take some time
337 NetworkUtils
.addCertToKnownServersStore(mCertificate
, getSherlockActivity());
341 public interface OnSslUntrustedCertListener
{
342 public void onFailedSavingCertificate();