X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/301b2760ba37347ad98e896058fceb0c0bc349e4..1551a5280afc682baf84582c150b3a9a4e47f219:/src/com/owncloud/android/ui/dialog/SslValidatorDialog.java diff --git a/src/com/owncloud/android/ui/dialog/SslValidatorDialog.java b/src/com/owncloud/android/ui/dialog/SslValidatorDialog.java index 90fad539..1e31c0ca 100644 --- a/src/com/owncloud/android/ui/dialog/SslValidatorDialog.java +++ b/src/com/owncloud/android/ui/dialog/SslValidatorDialog.java @@ -1,10 +1,12 @@ -/* ownCloud Android client application - * Copyright (C) 2011 Bartek Przybylski +/** + * ownCloud Android client application + * + * @author David A. Velasco + * Copyright (C) 2015 ownCloud Inc. * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -15,46 +17,45 @@ * along with this program. If not, see . * */ + package com.owncloud.android.ui.dialog; import java.io.IOException; +import java.security.GeneralSecurityException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; -import java.security.cert.CertPath; -import java.security.cert.CertPathValidatorException; -import java.security.cert.Certificate; import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; -import java.util.List; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.x500.X500Principal; -import javax.net.ssl.SSLPeerUnverifiedException; +import com.owncloud.android.R; import android.app.Dialog; import android.content.Context; import android.os.Bundle; -import android.util.Log; import android.view.View; import android.view.Window; +import android.widget.Button; import android.widget.TextView; -import com.owncloud.android.R; -import com.owncloud.android.network.OwnCloudClientUtils; -import com.owncloud.android.network.SslAnalyzer; -import com.owncloud.android.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.network.CertificateCombinedException; +import com.owncloud.android.lib.common.network.NetworkUtils; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; /** * Dialog to request the user about a certificate that could not be validated with the certificates store in the system. - * - * @author David A. Velasco */ public class SslValidatorDialog extends Dialog { private final static String TAG = SslValidatorDialog.class.getSimpleName(); private OnSslValidatorListener mListener; - private Exception mException = null; + private CertificateCombinedException mException = null; private View mView; @@ -65,11 +66,11 @@ public class SslValidatorDialog extends Dialog { * @param context Android context where the dialog will live. * @param result Result of a failed remote operation. * @param listener Object to notice when the server certificate was added to the local certificates store. - * @return A new SslValidatorDialog instance, or NULL if the operation can not be recovered + * @return A new SslValidatorDialog instance. NULL if the operation can not be recovered * by setting the certificate as reliable. */ public static SslValidatorDialog newInstance(Context context, RemoteOperationResult result, OnSslValidatorListener listener) { - if (SslAnalyzer.isRecoverable(result)) { + if (result != null && result.isSslRecoverableException()) { SslValidatorDialog dialog = new SslValidatorDialog(context, listener); return dialog; } else { @@ -100,7 +101,6 @@ public class SslValidatorDialog extends Dialog { requestWindowFeature(Window.FEATURE_NO_TITLE); mView = getLayoutInflater().inflate(R.layout.ssl_validator_layout, null); setContentView(mView); - //setTitle(R.string.ssl_validator_title); mView.findViewById(R.id.ok).setOnClickListener( new View.OnClickListener() { @@ -112,13 +112,19 @@ public class SslValidatorDialog extends Dialog { if (mListener != null) mListener.onSavedCertificate(); else - Log.d(TAG, "Nobody there to notify the certificate was saved"); + Log_OC.d(TAG, "Nobody there to notify the certificate was saved"); + + } catch (GeneralSecurityException e) { + dismiss(); + if (mListener != null) + mListener.onFailedSavingCertificate(); + Log_OC.e(TAG, "Server certificate could not be saved in the known servers trust store ", e); - } catch (Exception e) { + } catch (IOException e) { dismiss(); if (mListener != null) mListener.onFailedSavingCertificate(); - Log.e(TAG, "Server certificate could not be saved in the known servers trust store ", e); + Log_OC.e(TAG, "Server certificate could not be saved in the known servers trust store ", e); } } }); @@ -130,56 +136,216 @@ public class SslValidatorDialog extends Dialog { cancel(); } }); + + mView.findViewById(R.id.details_btn).setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + View detailsScroll = findViewById(R.id.details_scroll); + if (detailsScroll.getVisibility() == View.VISIBLE) { + detailsScroll.setVisibility(View.GONE); + ((Button) v).setText(R.string.ssl_validator_btn_details_see); + + } else { + detailsScroll.setVisibility(View.VISIBLE); + ((Button) v).setText(R.string.ssl_validator_btn_details_hide); + } + } + }); } public void updateResult(RemoteOperationResult result) { - mException = SslAnalyzer.getRecoverableException(result); - if (mException instanceof CertPathValidatorException ) { - showCertificateData(((CertPathValidatorException)mException).getCertPath()); - ((TextView)mView.findViewById(R.id.reason_cert_not_trusted)).setVisibility(View.VISIBLE); - ((TextView)mView.findViewById(R.id.reason_cert_expired)).setVisibility(View.GONE); - ((TextView)mView.findViewById(R.id.reason_cert_not_yet_valid)).setVisibility(View.GONE); - ((TextView)mView.findViewById(R.id.reason_hostname_not_vertified)).setVisibility(View.GONE); + if (result.isSslRecoverableException()) { + mException = (CertificateCombinedException) result.getException(); + + /// clean + mView.findViewById(R.id.reason_cert_not_trusted).setVisibility(View.GONE); + mView.findViewById(R.id.reason_cert_expired).setVisibility(View.GONE); + mView.findViewById(R.id.reason_cert_not_yet_valid).setVisibility(View.GONE); + mView.findViewById(R.id.reason_hostname_not_verified).setVisibility(View.GONE); + mView.findViewById(R.id.details_scroll).setVisibility(View.GONE); + + /// refresh + if (mException.getCertPathValidatorException() != null) { + ((TextView)mView.findViewById(R.id.reason_cert_not_trusted)).setVisibility(View.VISIBLE); + } + + if (mException.getCertificateExpiredException() != null) { + ((TextView)mView.findViewById(R.id.reason_cert_expired)).setVisibility(View.VISIBLE); + } - } else if (mException instanceof CertificateExpiredException ) { - ((TextView)mView.findViewById(R.id.reason_cert_not_trusted)).setVisibility(View.GONE); - ((TextView)mView.findViewById(R.id.reason_cert_expired)).setVisibility(View.VISIBLE); - ((TextView)mView.findViewById(R.id.reason_cert_not_yet_valid)).setVisibility(View.GONE); - ((TextView)mView.findViewById(R.id.reason_hostname_not_vertified)).setVisibility(View.GONE); + if (mException.getCertificateNotYetValidException() != null) { + ((TextView)mView.findViewById(R.id.reason_cert_not_yet_valid)).setVisibility(View.VISIBLE); + } + + if (mException.getSslPeerUnverifiedException() != null ) { + ((TextView)mView.findViewById(R.id.reason_hostname_not_verified)).setVisibility(View.VISIBLE); + } - } else if (mException instanceof CertificateNotYetValidException ) { - ((TextView)mView.findViewById(R.id.reason_cert_not_trusted)).setVisibility(View.GONE); - ((TextView)mView.findViewById(R.id.reason_cert_expired)).setVisibility(View.GONE); - ((TextView)mView.findViewById(R.id.reason_cert_not_yet_valid)).setVisibility(View.VISIBLE); - ((TextView)mView.findViewById(R.id.reason_hostname_not_vertified)).setVisibility(View.GONE); - } else if (mException instanceof SSLPeerUnverifiedException ) { - ((TextView)mView.findViewById(R.id.reason_cert_not_trusted)).setVisibility(View.GONE); - ((TextView)mView.findViewById(R.id.reason_cert_expired)).setVisibility(View.GONE); - ((TextView)mView.findViewById(R.id.reason_cert_not_yet_valid)).setVisibility(View.GONE); - ((TextView)mView.findViewById(R.id.reason_hostname_not_vertified)).setVisibility(View.VISIBLE); + showCertificateData(mException.getServerCertificate()); } } - private void showCertificateData(CertPath certPath) { - final List certs = certPath.getCertificates(); - /*X509Certificate badCert = null; - if (e.getIndex() >= 0 && e.getIndex() < certs.size()) - badCert = (X509Certificate) certs.get(e.getIndex());*/ - if (certs.size() > 0) { - X509Certificate serverCert = (X509Certificate) certs.get(0); - String text = serverCert.getSubjectDN().getName(); - text = text.substring(text.indexOf(",") + 1); - ((TextView)mView.findViewById(R.id.issuer)).setText(text); + private void showCertificateData(X509Certificate cert) { + + if (cert != null) { + showSubject(cert.getSubjectX500Principal()); + showIssuer(cert.getIssuerX500Principal()); + showValidity(cert.getNotBefore(), cert.getNotAfter()); + showSignature(cert); + + } else { + // this should not happen + // TODO + } + } + + private void showSignature(X509Certificate cert) { + TextView sigView = ((TextView)mView.findViewById(R.id.value_signature)); + TextView algorithmView = ((TextView)mView.findViewById(R.id.value_signature_algorithm)); + sigView.setText(getHex(cert.getSignature())); + algorithmView.setText(cert.getSigAlgName()); + } + + public String getHex(final byte [] raw) { + if (raw == null) { + return null; + } + final StringBuilder hex = new StringBuilder(2 * raw.length); + for (final byte b : raw) { + final int hiVal = (b & 0xF0) >> 4; + final int loVal = b & 0x0F; + hex.append((char) ('0' + (hiVal + (hiVal / 10 * 7)))); + hex.append((char) ('0' + (loVal + (loVal / 10 * 7)))); + } + return hex.toString(); + } + + @SuppressWarnings("deprecation") + private void showValidity(Date notBefore, Date notAfter) { + TextView fromView = ((TextView)mView.findViewById(R.id.value_validity_from)); + TextView toView = ((TextView)mView.findViewById(R.id.value_validity_to)); + fromView.setText(notBefore.toLocaleString()); + toView.setText(notAfter.toLocaleString()); + } + + private void showSubject(X500Principal subject) { + Map s = parsePrincipal(subject); + TextView cnView = ((TextView)mView.findViewById(R.id.value_subject_CN)); + TextView oView = ((TextView)mView.findViewById(R.id.value_subject_O)); + TextView ouView = ((TextView)mView.findViewById(R.id.value_subject_OU)); + TextView cView = ((TextView)mView.findViewById(R.id.value_subject_C)); + TextView stView = ((TextView)mView.findViewById(R.id.value_subject_ST)); + TextView lView = ((TextView)mView.findViewById(R.id.value_subject_L)); + + if (s.get("CN") != null) { + cnView.setText(s.get("CN")); + cnView.setVisibility(View.VISIBLE); + } else { + cnView.setVisibility(View.GONE); + } + if (s.get("O") != null) { + oView.setText(s.get("O")); + oView.setVisibility(View.VISIBLE); + } else { + oView.setVisibility(View.GONE); + } + if (s.get("OU") != null) { + ouView.setText(s.get("OU")); + ouView.setVisibility(View.VISIBLE); + } else { + ouView.setVisibility(View.GONE); + } + if (s.get("C") != null) { + cView.setText(s.get("C")); + cView.setVisibility(View.VISIBLE); + } else { + cView.setVisibility(View.GONE); + } + if (s.get("ST") != null) { + stView.setText(s.get("ST")); + stView.setVisibility(View.VISIBLE); + } else { + stView.setVisibility(View.GONE); + } + if (s.get("L") != null) { + lView.setText(s.get("L")); + lView.setVisibility(View.VISIBLE); + } else { + lView.setVisibility(View.GONE); + } + } + + private void showIssuer(X500Principal issuer) { + Map s = parsePrincipal(issuer); + TextView cnView = ((TextView)mView.findViewById(R.id.value_issuer_CN)); + TextView oView = ((TextView)mView.findViewById(R.id.value_issuer_O)); + TextView ouView = ((TextView)mView.findViewById(R.id.value_issuer_OU)); + TextView cView = ((TextView)mView.findViewById(R.id.value_issuer_C)); + TextView stView = ((TextView)mView.findViewById(R.id.value_issuer_ST)); + TextView lView = ((TextView)mView.findViewById(R.id.value_issuer_L)); + + if (s.get("CN") != null) { + cnView.setText(s.get("CN")); + cnView.setVisibility(View.VISIBLE); + } else { + cnView.setVisibility(View.GONE); + } + if (s.get("O") != null) { + oView.setText(s.get("O")); + oView.setVisibility(View.VISIBLE); + } else { + oView.setVisibility(View.GONE); + } + if (s.get("OU") != null) { + ouView.setText(s.get("OU")); + ouView.setVisibility(View.VISIBLE); + } else { + ouView.setVisibility(View.GONE); + } + if (s.get("C") != null) { + cView.setText(s.get("C")); + cView.setVisibility(View.VISIBLE); + } else { + cView.setVisibility(View.GONE); + } + if (s.get("ST") != null) { + stView.setText(s.get("ST")); + stView.setVisibility(View.VISIBLE); + } else { + stView.setVisibility(View.GONE); + } + if (s.get("L") != null) { + lView.setText(s.get("L")); + lView.setVisibility(View.VISIBLE); + } else { + lView.setVisibility(View.GONE); + } + } + + + private Map parsePrincipal(X500Principal principal) { + Map result = new HashMap(); + String toParse = principal.getName(); + String[] pieces = toParse.split(","); + String[] tokens = {"CN", "O", "OU", "C", "ST", "L"}; + for (int i=0; i < pieces.length ; i++) { + for (int j=0; j