Соединение с REST webservice из android throws javax.net.ssl.SSLException: Ненадежный сертификат сервера - PullRequest
0 голосов
/ 03 июня 2011

Я разрабатываю приложение на Android, которое использует веб-сервис REST.Веб-сервис находится в HTTPS.Я не могу предоставить информацию о веб-сервисе, так как это конфиденциально.Я выполнил действия, указанные в ссылке ниже:

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

Приложение до сих пор работало нормально и могло загружать контент веб-службы.Внезапно в последнюю неделю он не смог подключиться и выдает «javax.net.ssl.SSLException: сертификат недоверенного сервера».Я выполнил следующие шаги, чтобы настроить это:

Шаг 1: Я использовал корневой сертификат, предоставленный GeoTrust, в своем приложении для обеспечения безопасной связи.Собранный корневой сертификат «GeoTrust_Global_CA.cer» с трастового сайта Geo: 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 "-storestype BKS -reprepmysecret

После успешной работы он создает 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 ,rustCertEntry, отпечаток большого пальца (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: TrustAnchor for CertPath не найден.

javax.net.ssl.SSLException: недоверенный сертификат сервера


Поэтому я попытался использовать то же приложение для подключения к различным другим веб-службам, включая ту, которая предоставляется geotrust (https://ssltest15.bbtest.net/).Все бросают одно и то же исключение.Я полагаю, что

  1. Веб-сервер, который предоставляет веб-службу REST, может иметь некоторые изменения на их стороне, что вызывает эту проблему

  2. Срок действия сертификата Geo Trust, который я использую, истек

  3. Шаги, которые я выполнил, имеют некоторые проблемы

То же приложение, что и вышекод работал нормально до 1 недели, теперь внезапно происходит сбой, значит, произошли некоторые изменения на стороне сервера, вызвавшие эту проблему.Я неясно о точной проблеме.

Если кто-нибудь может помочь мне понять проблему, мы будем очень признательны.Заранее спасибо.

1 Ответ

0 голосов
/ 04 июня 2011

Похоже, у вас не правильно заполнено хранилище доверия. Я знаю, что вы не можете обсуждать детали своего веб-сервиса, но из какого CA подписан сертификат вашего сервиса? Вам необходимо поместить цепочку в хранилище ключей доверия для клиентского приложения.

Например, если ваша веб-служба вышла из промежуточного CA GeoTrust, вы должны поместить в свой магазин промежуточный сертификат CA GeoTrust CA, а также сертификат корневого CA GeoTrust. Если вы по-прежнему получаете ошибки, также поместите сертификат вашего веб-сервиса в доверенное хранилище клиента.

Если посмотреть на вывод списка ключей, в вашем хранилище доверенных сертификатов есть только одна запись.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...