从android连接到REST webservice抛出javax.net.ssl.SSLException:不受信任的服务器证书

时间:2011-06-02 20:02:41

标签: android rest ssl https

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

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

该应用程序到目前为止工作正常,并能够下载Web服务内容。突然持续一周它无法连接并抛出“javax.net.ssl.SSLException:不可信服务器证书”。我按照下面提到的步骤来设置:

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

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

步骤2:下载BouncyCastle提供程序并使用此创建的密钥库。我从命令行使用java 6 keytool运行以下命令来生成密钥存储:

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文件夹中。

然后通过运行以下命令验证此密钥库:

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,Thumbprint(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 Web服务的Web服务器可能会有一些更改,导致此问题

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

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

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

    如果有人能帮助我理解这个问题,我们非常感谢。提前谢谢。

1 个答案:

答案 0 :(得分:0)

您似乎没有正确填充您的信任存储区。我知道你不能讨论你的网络服务的细节,但是你的服务证书是什么?您需要将 链放在您的客户端应用程序的信任密钥库中。

例如,如果您的Web服务是从中间GeoTrust CA签名的,那么您应该将中间GeoTrust CA的证书以及根GeoTrust CA的证书放入您的商店。如果仍然出现错误,也请将您的Web服务证书放入客户端信任存储区。

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