android - 获取 SSLHandShakeException

标签 android exception

当我访问 wsdl url 时,我在 android 中遇到异常

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

我使用了 ksoap2 库来执行 WSDL 文件。

我也实现了认证类(class),但我遇到了同样的问题

请告知是否有任何解决方案。

我正在使用这两个类进行认证:

AndroidInsecureHttpsServiceConnectionSE 类:

    package com.example.androidwsdltest;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import org.ksoap2.HeaderProperty;
import org.ksoap2.transport.ServiceConnection;

import android.util.Log;

public class AndroidInsecureHttpsServiceConnectionSE implements
        ServiceConnection {
    private HttpsURLConnection connection;

    public AndroidInsecureHttpsServiceConnectionSE(String host, int port,
            String file, int timeout) throws IOException {
        // allowAllSSL();
        connection = (HttpsURLConnection) new URL("https", host, port, file)
                .openConnection();
        updateConnectionParameters(timeout);
    }

    private static TrustManager[] trustManagers;

    public static class EasyX509TrustManager implements X509TrustManager {

        private X509TrustManager standardTrustManager = null;

        /**
         * Constructor for EasyX509TrustManager.
         */
        public EasyX509TrustManager(KeyStore keystore)
                throws NoSuchAlgorithmException, KeyStoreException {
            super();
            TrustManagerFactory factory = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            factory.init(keystore);
            TrustManager[] trustmanagers = factory.getTrustManagers();
            if (trustmanagers.length == 0) {
                throw new NoSuchAlgorithmException("no trust manager found");
            }
            this.standardTrustManager = (X509TrustManager) trustmanagers[0];
        }

        /**
         * @see 
         *      javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate
         *      [],String authType)
         */
        public void checkClientTrusted(X509Certificate[] certificates,
                String authType) throws CertificateException {
            standardTrustManager.checkClientTrusted(certificates, authType);
        }

        /**
         * @see 
         *      javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate
         *      [],String authType)
         */
        public void checkServerTrusted(X509Certificate[] certificates,
                String authType) throws CertificateException {
            if ((certificates != null) && (certificates.length == 1)) {
                certificates[0].checkValidity();
            } else {
                standardTrustManager.checkServerTrusted(certificates, authType);
            }
        }

        /**
         * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
         */
        public X509Certificate[] getAcceptedIssuers() {
            return this.standardTrustManager.getAcceptedIssuers();
        }

    }

    public static class FakeX509TrustManager implements X509TrustManager {
        private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {};

        public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
        }

        public boolean isClientTrusted(X509Certificate[] chain) {
            return true;
        }

        public boolean isServerTrusted(X509Certificate[] chain) {
            return true;
        }

        public X509Certificate[] getAcceptedIssuers() {
            return (_AcceptedIssuers);
        }
    }

    /**
     * Allow all SSL certificates by setting up a host name verifier that passes
     * everything and as well setting up a SocketFactory with the
     * #FakeX509TrustManager.
     */
    public static void allowAllSSL() {

        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

            @Override
            public boolean verify(String hostname, SSLSession session) {
                // TODO Auto-generated method stub
                return true;
            }

        });

        SSLContext context = null;

        if (trustManagers == null) {
            try {
                trustManagers = new TrustManager[] { new EasyX509TrustManager(
                        null) };
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (KeyStoreException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        try {
            context = SSLContext.getInstance("TLS");
            context.init(null, trustManagers, new SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            Log.e("allowAllSSL", e.toString());
        } catch (KeyManagementException e) {
            Log.e("allowAllSSL", e.toString());
        }
        // HttpsURLConnection.setDefaultAllowUserInteraction(true);
        HttpsURLConnection.setDefaultSSLSocketFactory(context
                .getSocketFactory());
    }

    /**
     * update the connection with the timeout parameter as well as allowing SSL
     * if the Android version is 7 or lower (since these versions have a broken
     * certificate manager, which throws a SSL exception saying "Not trusted
     * security certificate"
     * 
     * @param timeout
     */
    private void updateConnectionParameters(int timeout) {
        connection.setConnectTimeout(timeout); // 20 seconds
        connection.setReadTimeout(timeout); // even if we connect fine we want
                                            // to time out if we cant read
                                            // anything..
        connection.setUseCaches(false);
        connection.setDoOutput(true);
        connection.setDoInput(true);

        allowAllSSL();

        /*
         * int buildVersion = Build.VERSION.SDK_INT; if (buildVersion <= 7) {
         * Log.d("Detected old operating system version " + buildVersion +
         * " with SSL certificate problems. Allowing " + "all certificates.",
         * String.valueOf(buildVersion)); allowAllSSL(); } else {
         * Log.d("Full SSL active on new operating system version ",
         * String.valueOf(buildVersion)); }
         */
    }

    public void connect() throws IOException {
        connection.connect();
    }

    public void disconnect() {
        connection.disconnect();
    }

    public List getResponseProperties() {
        Map properties = connection.getHeaderFields();
        Set keys = properties.keySet();
        List retList = new LinkedList();

        for (Iterator i = keys.iterator(); i.hasNext();) {
            String key = (String) i.next();
            List values = (List) properties.get(key);

            for (int j = 0; j < values.size(); j++) {
                retList.add(new HeaderProperty(key, (String) values.get(j)));
            }
        }

        return retList;
    }

    public void setRequestProperty(String key, String value) {
        // We want to ignore any setting of "Connection: close" because
        // it is buggy with Android SSL.
        if ("Connection".equalsIgnoreCase(key)
                && "close".equalsIgnoreCase(value)) {
            // do nothing
        } else {
            connection.setRequestProperty(key, value);
        }
    }

    public void setRequestMethod(String requestMethod) throws IOException {
        connection.setRequestMethod(requestMethod);
    }

    public OutputStream openOutputStream() throws IOException {
        return connection.getOutputStream();
    }

    public InputStream openInputStream() throws IOException {
        return connection.getInputStream();
    }

    public InputStream getErrorStream() {
        return connection.getErrorStream();
    }

    public String getHost() {
        return connection.getURL().getHost();
    }

    public int getPort() {
        return connection.getURL().getPort();
    }

    public String getPath() {
        return connection.getURL().getPath();
    }

}

AndroidInsecureKeepAliveHttpsTransportSE 类:

 package com.example.androidwsdltest;

import java.io.IOException;

import org.ksoap2.transport.HttpsTransportSE;
import org.ksoap2.transport.ServiceConnection;

public class AndroidInsecureKeepAliveHttpsTransportSE extends HttpsTransportSE {

    private AndroidInsecureHttpsServiceConnectionSE conn = null;
    private final String host;
    private final int port;
    private final String file;
    private final int timeout;

    public AndroidInsecureKeepAliveHttpsTransportSE(String host, int port,
            String file, int timeout) {
        super(host, port, file, timeout);
        this.host = host;
        this.port = port;
        this.file = file;
        this.timeout = timeout;
    }

    @Override
    protected ServiceConnection getServiceConnection() throws IOException {
        super.getServiceConnection();
        conn = new AndroidInsecureHttpsServiceConnectionSE(host, port, file,
                timeout);
        conn.setRequestProperty("Connection", "keep-alive");

        return conn;
    }
}

在使用这些认证类(class)后,我得到了同样的异常

请帮帮我..

提前致谢......:)

最佳答案

您应该有授权的 SSL 证书 - 这可能会解决问题,这是解决问题的最佳方法。

如果没有,你还得努力一点:

这个概念是,当使用 SSL 时,Android 会比平时更严格一些,并且你应该在你的 android 上拥有证书权限,因此为此,你应该在你的 Android 上有一个基本的 keystore (就像谷歌商店,但免费,以及在您自己的 Android 上),并通过一些基本操作让您自己的 Android 可信。

  1. 在服务器上找到您的证书,并使用私钥导出(您应具有管理员权限)。这可以通过从 start->run + certmgr.msc 运行来完成。 寻找“受信任的根证书颁发机构”。找到你的证书并导出( key 工具可以加载现有的 pfx 证书。在 *.cer 类型的证书上,可能没有什么问题。
  2. 你应该有一个 key 工具。您可以在 http://keytool.sourceforge.net/ 上找到解释 您可以安装,但我更喜欢以下建议: 这是通过帮助 - 软件更新 - 查找并安装 - 搜索新功能.... 单击新建远程站点并添加 http://keytool.sourceforge.net/update在名称和 URL 中,并确保已选中。 点击完成。
  3. 添加一个新的 keystore ,并加载您的证书(使用 pcs12 协议(protocol),选择您能记住的密码)。
  4. 需要添加的代码如下: http://developer.android.com/training/articles/security-ssl.html#UnknownCa
  5. 你应该联系你。 您可以像示例一样使用 HttpTransportSE::ServiceConnection::setSSLSocketFactory。 https://code.google.com/p/androidzon/source/browse/Androidzon/src/it/marco/ksoap2/HttpTransportSE.java?r=77 (只需创建您自己的新功能,并将其连接到 Web 服务。如果不起作用,请删除 ?wsdl)

祝你好运!!!

关于android - 获取 SSLHandShakeException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15762249/

相关文章:

android - 工具栏中的波纹颜色子菜单项

c++ - vector 异常处理程序和 Microsoft C 运行时错误处理

java - Servlet/JSP 流程控制 : Enums, 异常,还是其他原因?

excel - 为什么错误处理例程中的消息被打印两次?

java - Android for 循环不像 java 那样工作

android - 在服务器端验证应用程序是否是我的

android - Gson会忽略序列化时枚举的自定义@SerializedName值

android - 将 post 数组改造为 php 文件

java - 在类声明中抛出异常

multithreading - 在 Windows 上等待 Network.Socket.accept 的 Haskell 或 Haskell OS 线程能否被杀死?