android - 从 android 连接到 REST web 服务抛出 javax.net.ssl.SSLException : Not trusted server certificate

标签 android rest ssl https

我正在 Android 上开发一个使用 REST 网络服务的应用程序。 Web 服务采用 HTTPS。我无法提供 Web 服务的详细信息,因为它是 secret 信息。我按照以下链接中提到的步骤操作:

http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/

到目前为止,该应用程序运行良好,能够下载 Web 服务内容。上周突然连接失败并抛出“javax.net.ssl.SSLException:不可信的服务器证书”。我按照下面提到的步骤进行设置:

第 1 步:我在我的应用程序中使用了 GeoTrust 提供的根证书来启用安全通信。因此从 Geo 信任站点收集了根证书“GeoTrust_Global_CA.cer”:http://www.geotrust.com/resources/root-certificates/index.html

它是一种 Base64 编码的 X.509 格式。

第 2 步:下载 BouncyCaSTLe 提供程序并使用此创建的 keystore 。我从命令行使用 java 6 keytool 运行以下命令以生成 key 存储:

keytool -importcert -v -trustcacerts -file "G:\workspace\TestHttps\GeoTrustglobal.cer"-alias IntermediateCA -keystore "G:\workspace\TestHttps\res\raw\mykeystore.bks"-provider org.bouncycaSTLe .jce.provider.BouncyCaSTLeProvider -providerpath "G:\workspace\TestHttps\SigningProcess\bcprov-jdk16-146.jar"-storetype BKS -storepass mysecret

成功后,它会创建 myKeyStore.bks 并将其复制到我的应用程序的/res/raw 文件夹中。

然后通过运行以下命令验证此 keystore :

keytool -importcert -v -trustcacerts -file "G:\workspace\TestHttps\GeoTrustglobal.cer"-alias IntermediateCA -keystore "G:\workspace\TestHttps\res\raw\mykeystore.bks"-provider org.bouncycaSTLe .jce.provider.BouncyCaSTLeProvider -providerpath "G:\workspace\TestHttps\SigningProcess\bcprov-jdk16-146.jar"-storetype BKS -storepass mysecret

它返回了 1 个带有中间证书的结果,如下所示:

IntermediateCA,22.10.2010,trustedCertEntry,指纹 (MD5):98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43

第 3 步:

现在我编写了以下从 DefaultHttpClient 扩展的代码

public class MyHttpClient extends DefaultHttpClient {

    final Context context;

    public MyHttpClient(Context context) {
        this.context = context;
    }

     @Override
    protected ClientConnectionManager createClientConnectionManager() {
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        // Register for port 443 our SSLSocketFactory with our keystore
        // to the ConnectionManager
        registry.register(new Scheme("https", newSslSocketFactory(), 443));
        return new SingleClientConnManager(getParams(), registry);
    }

    private SSLSocketFactory newSslSocketFactory() {
        try {
            // Get an instance of the Bouncy Castle KeyStore format
            KeyStore trusted = KeyStore.getInstance("BKS");
            // Get the raw resource, which contains the keystore with
            // your trusted certificates (root and any intermediate certs)
            InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
            try {
                // Initialize the keystore with the provided trusted certificates
                // Also provide the password of the keystore
                trusted.load(in, "mysecret".toCharArray());
            } finally {
                in.close();
            }
            // Pass the keystore to the SSLSocketFactory. The factory is responsible
            // for the verification of the server certificate.
            SSLSocketFactory sf = new SSLSocketFactory(trusted);
            // Hostname verification from certificate
            // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
            sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
            return sf;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

然后我使用以下代码调用了 DefaultHttpClient:

package com.test.https;

import java.io.IOException;
import java.net.UnknownHostException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.os.Bundle;

public class TestHttps extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        try {
            startConnect();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void startConnect() throws UnknownHostException{
        DefaultHttpClient client = new MyHttpClient(getApplicationContext());
        HttpGet get = new HttpGet("https://ssltest15.bbtest.net/");
        // Execute the GET call and obtain the response
        HttpResponse getResponse = null;


        try {
            getResponse = client.execute(get);
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch(UnknownHostException uhe){
            uhe.printStackTrace();
            throw new UnknownHostException();           
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        String response = null;
        if(getResponse != null){
            HttpEntity responseEntity = getResponse.getEntity();
            try {
                response = EntityUtils.toString(responseEntity);
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
        }
    }
}

当我执行这段代码时,它抛出以下异常:

java.security.cert.CertPathValidatorException:未找到 CertPath 的 TrustAnchor。

javax.net.ssl.SSLException: 不受信任的服务器证书


因此,我尝试使用同一个应用程序连接到各种其他 Web 服务,包括由 geotrust (https://ssltest15.bbtest.net/) 提供的服务。都抛出相同的异常。我对这个问题的猜测是,

  1. 提供 REST 网络服务的网络服务器可能在其方面进行了一些更改,这导致了此问题

  2. 我使用的 Geo Trust 证书已过期

  3. 我遵循的步骤有一些问题

具有上述代码的同一个应用程序在 1 周前工作正常,现在突然失败意味着服务器端发生了一些变化导致了这个问题。我不清楚确切的问题。

如果有人能帮助我理解这个问题,我们将不胜感激。提前致谢。

最佳答案

您似乎没有正确填充您的信任库。我知道你不能讨论你的网络服务的细节,但你的服务证书是由哪个 CA 签发的?您需要将 那个 链放入您的客户端应用程序的信任 keystore 中。

例如,如果您的 Web 服务已从中间 GeoTrust CA 签署,您应该将中间 GeoTrust CA 的证书以及根 GeoTrust CA 的证书放入您的商店。如果您仍然遇到错误,也请将您的 Web 服务证书也放入您的客户端信任库中。

查看 keytool -list 输出,您的信任库中只有一个条目。

关于android - 从 android 连接到 REST web 服务抛出 javax.net.ssl.SSLException : Not trusted server certificate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6219740/

相关文章:

10000 毫秒后 java.net.SocketTimeoutException : failed to connect to/192. 168.1.8(端口 8383)

java - 如何在 Android 中解压缩 7zip 存档?

node.js - 如何使用 Express 中间件路由在 REST API 中进行错误处理

rest - 如果仅使用 GET/Retrieve,则 API 属于 RESTful

c# - 使用 WCF,REST 和 SOAP 肯定应该协调工作吗?

google-chrome - 带有 SubjectAlternativeName (SAN) 的证书在 Google Chrome 中给出了 ERR_CONNECTION_RESET

java - Netty 中的两种方式的 SSL 身份验证

Android 只能使用 make 版本 3.81 构建

android - 通过蓝牙打印机 Android 打印 Pdf 文件

c++ - BOOST ASIO 加载带有密码的 key.pem