Apache HttpClient на Android, создающий исключение CertPathValidatorException (IssuerName! = subjectName)

StackOverflow https://stackoverflow.com/questions/4115101

Вопрос

Я разрабатываю приложение для Android для доступа к Battle.net (https://eu.battle.net) данные учетной записи (для World of Warcraft), и я использую org.apache.http.client.HttpClient сделать это.

Это код, который я использую:

 public static final String USER_AGENT = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 (.NET CLR 3.5.30729)";

  public static class MyHttpClient extends DefaultHttpClient {

    final Context context;

    public MyHttpClient(Context context) {
      super();
      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.battlenetkeystore);
        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);
      }
    }
  }

  private static void maybeCreateHttpClient(Context context) {
    if (mHttpClient == null) {
      mHttpClient = new MyHttpClient(context);

      final HttpParams params = mHttpClient.getParams();
      HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT);
      HttpConnectionParams.setSoTimeout(params, REGISTRATION_TIMEOUT);
      ConnManagerParams.setTimeout(params, REGISTRATION_TIMEOUT);
      Log.d(TAG, LEAVE + "maybeCreateHttpClient()");
    }
  }

public static boolean authenticate(String username, String password, Handler handler,
      final Context context) {

    final HttpResponse resp;

    final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair(PARAM_USERNAME, username));
    params.add(new BasicNameValuePair(PARAM_PASSWORD, password));

    HttpEntity entity = null;
    try {
      entity = new UrlEncodedFormEntity(params);
    } catch (final UnsupportedEncodingException e) {
      // this should never happen.
      throw new AssertionError(e);
    }

    final HttpPost post = new HttpPost(THE_URL);
    post.addHeader(entity.getContentType());
    post.addHeader("User-Agent", USER_AGENT);
    post.setEntity(entity);

    maybeCreateHttpClient(context);

    if (mHttpClient == null) {
      return false;
    }

    try {
      resp = mHttpClient.execute(post);
    } catch (final IOException e) {
      Log.e(TAG, "IOException while authenticating", e);
      return false;
    } finally {
    }
}

Хранилище ключей извлекается (с помощью OpenSSL) следующим образом:

openssl s_client -connect eu.battle.net:443 -showcerts

Я сравнил сертификаты, выданные командой (http://vipsaran.webs.com/openssl_output.txt) с теми, которые я экспортировал из Firefox (http://vipsaran.webs.com/Firefox_output.zip) и они одинаковы.

Следуя советам по этот блог, Я настроил приведенный выше код и импортировал сертификаты (корневые и промежуточные) в хранилище ключей (battlenetkeystore.bks), которое используется для HttpClient.

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

keytool -importcert -v -file ~/lib/ThawteSSLCA.crt -alias thawtesslca -keystore ~/lib/battlenetkeystore.bks -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ~/lib/bcprov-jdk16-145.jar -storetype BKS -storepass mysecret -keypass mysecret -keyalg "RSA" -sigalg "SHA1withRSA"
keytool -importcert -v -file ~/lib/thawtePrimaryRootCA.crt -alias thawteprimaryrootca -keystore ~/lib/battlenetkeystore.bks -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ~/lib/bcprov-jdk16-145.jar -storetype BKS -storepass mysecret -keypass mysecret -keyalg "RSA" -sigalg "SHA1withRSA"

Кстати.я тоже пробовал keytool -import без -keyalg "RSA" -sigalg "SHA1withRSA", но без изменений.

Проблема в том, что я получаю эту ошибку:

javax.net.ssl.SSLException: Not trusted server certificate
    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:371)
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92)
    at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381)
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:164)
    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
    at org.homedns.saran.android.wowcalendarsync.network.NetworkUtilities.authenticateWithPass(NetworkUtilities.java:346)
    at org.homedns.saran.android.wowcalendarsync.network.NetworkUtilities$1.run(NetworkUtilities.java:166)
    at org.homedns.saran.android.wowcalendarsync.network.NetworkUtilities$5.run(NetworkUtilities.java:278)
Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: IssuerName(CN=thawte Primary Root CA, OU="(c) 2006 thawte, Inc. - For authorized use only", OU=Certification Services Division, O="thawte, Inc.", C=US) does not match SubjectName(CN=Thawte SSL CA, O="Thawte, Inc.", C=US) of signing certificate
    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168)
    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:366)
    ... 12 more
Caused by: java.security.cert.CertPathValidatorException: IssuerName(CN=thawte Primary Root CA, OU="(c) 2006 thawte, Inc. - For authorized use only", OU=Certification Services Division, O="thawte, Inc.", C=US) does not match SubjectName(CN=Thawte SSL CA, O="Thawte, Inc.", C=US) of signing certificate
    at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:373)
    at java.security.cert.CertPathValidator.validate(CertPathValidator.java:202)
    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:164)
    ... 13 more

и я не могу найти способ решить эту проблему.Пробовал импортировать сертификаты в хранилище ключей в другом порядке.но ничего не помогло.

Пожалуйста помоги (и, пожалуйста, сосредоточьтесь на решениях, основанных на Apache HttpClient для Android. только).

Это было полезно?

Решение

Я ожидаю, что теперь у вас есть собственное решение, но если нет:

Сочетая идеи от

  • Блог Antoine Hauck
  • http://blog.synyx.de/2010/06/android-and-sels-signed-ssl-sertificates/
  • Отличный ответ от BDC выше
  • Легко-гугул исходный код для «EasySslsocketFactory» и «Easyx509Trustmanager» - предоставит ссылку, если бы я не помешал (впервые отвечая!)

Мне удалось добиться безопасного подключения к https://eu.bate.net/login/en/login.xml. с только следующими занятиями. Обратите внимание, что нет необходимости создавать клавиш-магазин, поскольку корневой CA доверяет Android - проблема в том, что сертификаты возвращаются в неправильном порядке.

(Отказ от ответственности: хотя бы не проводил время очистки кода.)

Easyx509trustmanager:

package com.trustit.trustme;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public 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 
    {  
    // Clean up the certificates chain and build a new one.
        // Theoretically, we shouldn't have to do this, but various web servers
        // in practice are mis-configured to have out-of-order certificates or
        // expired self-issued root certificate.
        int chainLength = certificates.length;
        if (certificates.length > 1) 
        {
          // 1. we clean the received certificates chain.
          // We start from the end-entity certificate, tracing down by matching
          // the "issuer" field and "subject" field until we can't continue.
          // This helps when the certificates are out of order or
          // some certificates are not related to the site.
          int currIndex;
          for (currIndex = 0; currIndex < certificates.length; ++currIndex) 
          {
            boolean foundNext = false;
            for (int nextIndex = currIndex + 1;
                           nextIndex < certificates.length;
                           ++nextIndex) 
            {
              if (certificates[currIndex].getIssuerDN().equals(
                            certificates[nextIndex].getSubjectDN())) 
              {
                foundNext = true;
                // Exchange certificates so that 0 through currIndex + 1 are in proper order
                if (nextIndex != currIndex + 1) 
                {
                  X509Certificate tempCertificate = certificates[nextIndex];
                  certificates[nextIndex] = certificates[currIndex + 1];
                  certificates[currIndex + 1] = tempCertificate;
                }
                break;
            }
            }
            if (!foundNext) break;
      }

          // 2. we exam if the last traced certificate is self issued and it is expired.
          // If so, we drop it and pass the rest to checkServerTrusted(), hoping we might
          // have a similar but unexpired trusted root.
          chainLength = currIndex + 1;
          X509Certificate lastCertificate = certificates[chainLength - 1];
          Date now = new Date();
          if (lastCertificate.getSubjectDN().equals(lastCertificate.getIssuerDN())
                  && now.after(lastCertificate.getNotAfter())) 
          {
            --chainLength;
          }
      } 

    standardTrustManager.checkServerTrusted(certificates, authType);    
    }  

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

EasysslsocketFactory.

package com.trustit.trustme;

import java.io.IOException;  
import java.net.InetAddress;  
import java.net.InetSocketAddress;  
import java.net.Socket;  
import java.net.UnknownHostException;  

import javax.net.ssl.SSLContext;  
import javax.net.ssl.SSLSocket;  
import javax.net.ssl.TrustManager;  

import org.apache.http.conn.ConnectTimeoutException;  
import org.apache.http.conn.scheme.LayeredSocketFactory;  
import org.apache.http.conn.scheme.SocketFactory;  
import org.apache.http.params.HttpConnectionParams;  
import org.apache.http.params.HttpParams;  

public class EasySSLSocketFactory implements SocketFactory, LayeredSocketFactory 
{  
    private SSLContext sslcontext = null;  

    private static SSLContext createEasySSLContext() throws IOException 
    {  
      try
      {  
        SSLContext context = SSLContext.getInstance("TLS");  
        context.init(null, new TrustManager[] { new EasyX509TrustManager(null) }, null);  
        return context;  
      }
      catch (Exception e) 
      {  
        throw new IOException(e.getMessage());  
      }  
    }  

    private SSLContext getSSLContext() throws IOException 
    {  
      if (this.sslcontext == null) 
      {  
        this.sslcontext = createEasySSLContext();  
      }  
      return this.sslcontext;  
    }  

    /** 
     * @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket, java.lang.String, int, 
     *      java.net.InetAddress, int, org.apache.http.params.HttpParams) 
     */  
    public Socket connectSocket(Socket sock,
                                    String host,
                                    int port, 
                                    InetAddress localAddress,
                                    int localPort,
                                    HttpParams params) 

                throws IOException, UnknownHostException, ConnectTimeoutException 
    {  
      int connTimeout = HttpConnectionParams.getConnectionTimeout(params);  
      int soTimeout = HttpConnectionParams.getSoTimeout(params);  
      InetSocketAddress remoteAddress = new InetSocketAddress(host, port);  
      SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());  

      if ((localAddress != null) || (localPort > 0)) 
      {  
        // we need to bind explicitly  
        if (localPort < 0) 
        {  
          localPort = 0; // indicates "any"  
        }  
        InetSocketAddress isa = new InetSocketAddress(localAddress, localPort);  
        sslsock.bind(isa);  
      }  

      sslsock.connect(remoteAddress, connTimeout);  
      sslsock.setSoTimeout(soTimeout);  
      return sslsock;    
    }  

    /** 
     * @see org.apache.http.conn.scheme.SocketFactory#createSocket() 
     */  
    public Socket createSocket() throws IOException {  
        return getSSLContext().getSocketFactory().createSocket();  
    }  

    /** 
     * @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket) 
     */  
    public boolean isSecure(Socket socket) throws IllegalArgumentException {  
        return true;  
    }  

    /** 
     * @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket, java.lang.String, int, 
     *      boolean) 
     */  
    public Socket createSocket(Socket socket,
                                   String host, 
                                   int port,
                                   boolean autoClose) throws IOException,  
                                                             UnknownHostException 
    {  
      return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);  
    }  

    // -------------------------------------------------------------------  
    // javadoc in org.apache.http.conn.scheme.SocketFactory says :  
    // Both Object.equals() and Object.hashCode() must be overridden  
    // for the correct operation of some connection managers  
    // -------------------------------------------------------------------  

    public boolean equals(Object obj) {  
        return ((obj != null) && obj.getClass().equals(EasySSLSocketFactory.class));  
    }  

    public int hashCode() {  
        return EasySSLSocketFactory.class.hashCode();  
    }  
}

Myhttpclient.

package com.trustit.trustme;

import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.params.HttpParams;

import android.content.Context;

public class MyHttpClient extends DefaultHttpClient 
{    
  final Context context;

  public MyHttpClient(HttpParams hparms, Context context)
  {
    super(hparms);
    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", new EasySSLSocketFactory(), 443));

    //http://blog.synyx.de/2010/06/android-and-self-signed-ssl-certificates/
    return new SingleClientConnManager(getParams(), registry);
  }
}

Trustme (деятельность)

package com.trustit.trustme;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

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

public class TrustMe extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView tv = (TextView)findViewById(R.id.tv1);


        HttpParams httpParameters = new BasicHttpParams();
        // Set the timeout in milliseconds until a connection is established.
        int timeoutConnection = 10000;
        HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
        // Set the default socket timeout (SO_TIMEOUT) 
        // in milliseconds which is the timeout for waiting for data.
        int timeoutSocket = 10000;
        HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

        // Instantiate the custom HttpClient
        HttpClient client = new MyHttpClient(httpParameters,
                                             getApplicationContext());
      HttpGet request = new HttpGet("https://eu.battle.net/login/en/login.xml"); 

        BufferedReader in = null;
        try 
        {
        HttpResponse response = client.execute(request);
        in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

        StringBuffer sb = new StringBuffer("");
        String line = "";
        String NL = System.getProperty("line.separator");
        while ((line = in.readLine()) != null)
        {
          sb.append(line + NL);
        }
        in.close();
        String page = sb.toString();
        //System.out.println(page);

        tv.setText(page);
            }
        catch (ClientProtocolException e) 
            {
                e.printStackTrace();
            }
        catch (IOException e) 
        {
                e.printStackTrace();
            }
        finally
        {
        if (in != null) 
        {
          try
          {
            in.close();
          }
          catch (IOException e) 
          {
            e.printStackTrace();
          }
        }                       
        }
    }      
}

Другие советы

Глядя на "openssl s_client -connect eu.battle.net:443", я вижу следующую сеть с сертиями:

Certificate chain
 0 s:/C=US/ST=California/L=Irvine/O=Blizzard Entertainment, Inc./CN=*.battle.net
   i:/C=US/O=Thawte, Inc./CN=Thawte SSL CA
 1 s:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA
   i:/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
 2 s:/C=US/O=Thawte, Inc./CN=Thawte SSL CA
   i:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA

Обратите внимание, что не в порядке. Эмитент CERT «N» в цепочке должен соответствовать предмету сертификата «N + 1». Эмитент последнего сертификата должен быть подписан на себя (субъект == эмитент) и технически не включен.

Правильная цепь будет заказана, как это:

Certificate chain
 0 s:/C=US/ST=California/L=Irvine/O=Blizzard Entertainment, Inc./CN=*.battle.net
   i:/C=US/O=Thawte, Inc./CN=Thawte SSL CA
 1 s:/C=US/O=Thawte, Inc./CN=Thawte SSL CA
   i:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA
 2 s:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA
   i:/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com

Браузер Android справляется с цепочкой из заказа у его android.net.http.certificatechainvalidator. Код переупорядочить цепочку сертификации перед передачей его для проверки.

 136         // Clean up the certificates chain and build a new one.
 137         // Theoretically, we shouldn't have to do this, but various web servers
 138         // in practice are mis-configured to have out-of-order certificates or
 139         // expired self-issued root certificate.
 140         int chainLength = serverCertificates.length;
 141         if (serverCertificates.length > 1) {
 142           // 1. we clean the received certificates chain.
 143           // We start from the end-entity certificate, tracing down by matching
 144           // the "issuer" field and "subject" field until we can't continue.
 145           // This helps when the certificates are out of order or
 146           // some certificates are not related to the site.
 147           int currIndex;
 148           for (currIndex = 0; currIndex < serverCertificates.length; ++currIndex) {
 149             boolean foundNext = false;
 150             for (int nextIndex = currIndex + 1;
 151                  nextIndex < serverCertificates.length;
 152                  ++nextIndex) {
 153               if (serverCertificates[currIndex].getIssuerDN().equals(
 154                   serverCertificates[nextIndex].getSubjectDN())) {
 155                 foundNext = true;
 156                 // Exchange certificates so that 0 through currIndex + 1 are in proper order
 157                 if (nextIndex != currIndex + 1) {
 158                   X509Certificate tempCertificate = serverCertificates[nextIndex];
 159                   serverCertificates[nextIndex] = serverCertificates[currIndex + 1];
 160                   serverCertificates[currIndex + 1] = tempCertificate;
 161                 }
 162                 break;
 163               }
 164             }
 165             if (!foundNext) break;
 166           }
 167 
 168           // 2. we exam if the last traced certificate is self issued and it is expired.
 169           // If so, we drop it and pass the rest to checkServerTrusted(), hoping we might
 170           // have a similar but unexpired trusted root.
 171           chainLength = currIndex + 1;
 172           X509Certificate lastCertificate = serverCertificates[chainLength - 1];
 173           Date now = new Date();
 174           if (lastCertificate.getSubjectDN().equals(lastCertificate.getIssuerDN())
 175               && now.after(lastCertificate.getNotAfter())) {
 176             --chainLength;
 177           }
 178         }

Чтобы разобраться с этим в вашем собственном приложении, вы хотите создать свой собственный javax.net.ssl.sslsocketfactory из SSLContext, который был инициализирован с X509Trustmanager, который пересматривает цепочку перед вызовом TrustMactory TrustMactory по умолчанию.

Я недавно не посмотрел код клиента Apache HTTP, чтобы увидеть, как предоставить свой пользовательский пользовательский javax.net.ssl.sslsocketFactory на их обертку SSLSocketFactory, но это должно быть возможно (или просто не использовать клиент Apache HTTP и просто использовать новый URL («HTTPS: // ..») .OpenConnection (), который позволяет указывать пользовательский javax.net.ssl.sslsocketFactory на httpsurlconnection.

Наконец, обратите внимание, что вам нужно только импортировать самооценку CAN CA в свой ключевой магазин (и только если его не уже в системном магазине, но я только что проверил, и этот CA нет в Froyo). CA, который вы хотите в этом случае, имеет тему:

/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA

Думаю, ваша проблема решается прямо сейчас, но у меня было то же самое, и я также изо всех сил боролся, чтобы найти правильное решение. Может быть, это поможет кому-то.

Я также использовал код из Блог Antoine Но я поменял конструктор, используемый для SSLSocketFactory.

Так что я использую

SSLSocketFactory sf = new SSLSocketFactory(certStore, "some_password", trustStore);

Там создал две клавишные магазины

KeyStore trustStore = KeyStore.getInstance("BKS");
KeyStore certStore = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.signature_certstore);
try {
    certStore.load(in, "some_password".toCharArray());
} finally {
    in.close();
}

in = context.getResources().openRawResource(R.raw.signature_truststore);
try {
    trustStore.load(in, "some_password".toCharArray());
} finally {
    in.close();
}

Я создал магазины БКС с Oortecle.. Отказ В Signature_trustStore.bks I импортировал корневой сертификат и в Signature_Certstore.bks, вы должны импортировать один или несколько промежуточных сертификатов.

Остальная часть кода точно такой же, как один из блога.

У меня нет решения, чтобы исправить путь. Но у меня есть решение для игнорирования сертификатов. Я использую этот метод, чтобы игнорировать самостоятельно подписанные сертификаты в разработке. Посмотрите, поможет ли это.

 protected final static ClientConnectionManager clientConnectionManager;
    protected final static HttpParams params;
    // ......
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
    params = new BasicHttpParams();
    params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 1);
    params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(1));
    params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
    HttpProtocolParams.setUserAgent(params, "android-client-v1.0");
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    HttpProtocolParams.setContentCharset(params, "utf8");
    clientConnectionManager = new ThreadSafeClientConnManager(params, schemeRegistry);
    // and later do this
    HttpClient client = new DefaultHttpClient(clientConnectionManager, params);
    HttpGet request = new HttpGet(uri);
    HttpResponse response = client.execute(request);

Это может помочь: http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/ Вы доверяли сертификаты от CA (например, в версии или GeoTrust)? Или вы используете самооценка сертификата ... Я сталкивался с аналогичными проблемами и решил сегодня ...

Кстати, я автор из упомянутого блога выше;) Я пытаюсь ответить на ваш вопрос здесь.

Я посмотрел на ваш сертификат выходов от Firefox и OpenSSL и нашел что-то интересное.

Посмотрите сертификат CORT CA (индекс 1) на выходе OpenSSL. Название эмитента: Thawte Premium Server CA Название субъекта: Thawte основной корневой CA У субъекта и названия эмитента разные. Следовательно, этот сертификат не рассматривается как корневой CA, потому что он был выдан другим экземпляром. Следовательно, поставщик BounCyctlecle рассматривает этот сертификат как корневой CA, но он жалуется, потому что проблемы и субъект разные.

Я понятия не имею, как вы получили «неправильный» сертификат корня. Когда я смотрю на сертификат CORT CA в Firefox, предмет и эмитент одинаковы, как это должно быть.

Попробуйте получить правильный корневой CA и попробуйте снова.

Надеюсь это поможет. Приветствую и удачи;)

Я наконец-то решил свое исключение «Имя эмитента не соответствует имени субъекта».Я много раз следил за одним и тем же блогом Антуана и тем, что здесь описано, и вот как заставить его наконец работать:

1) Наш сайт использует два сертификата GeoTrust:промежуточный ЦС выдается нам центром сертификации GeoTrust SSL, а корневой ЦС выдается ЦС GeoTrust SSL глобальным ЦС GeoTrust;

2) Если используются только корневой центр сертификации или как корневой, так и промежуточный центр сертификации в пункте 1), я получаю исключение несоответствия, поскольку Android поддерживает только ограниченное количество доверенных корневых центров сертификации, а GeoTrust Global CA нет в списке;

3) На странице поддержки www.geotrust.com есть страница под названием GeoTrust Cross Root CA, просто загрузите ее, сохраните под именем, например crossroot.pem, и используйте эту команду для создания хранилища ключей:

C:\Program Files\Java\jdk1.6.0_24\bin>keytool -importcert -v -trustcacerts -file c:\ssl\crossroot.pem -alias newroot -keystore c:\ssl\crossroot.bks -provider org.bouncycastle .jce.provider.BouncyCastleProvider -providerpath "c:\downloads\bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

Шаг 2 блога Антони содержит ссылку для загрузки BouncyCastleProvider;

4) Добавьте файл хранилища ключей в проект Android, и все заработает — это имеет смысл, поскольку теперь Android находит доверенный корневой центр сертификации Equifax Secure (см. список выше). 1), чье имя субъекта GeoTrust Global CA соответствует корневому имени эмитента нашего сайта.

5) Код из шага 3 блога работает нормально, и, чтобы сделать его более полным, я скопировал свой тестовый код ниже:

    HttpResponse response = client.execute(get);
    HttpEntity entity = response.getEntity();

    BufferedReader in = new BufferedReader(new InputStreamReader(entity.getContent()));

    String line;
    while ((line = in.readLine()) != null) 
    System.out.println(line);
    in.close();

Сложная часть этой проблемы заключается в том, что если эмитент вашего корневого центра сертификации не входит в список доверенных лиц Android, вам придется получить его от компании, которая выдает вам сертификаты — попросите их предоставить вам перекрестный корневой центр сертификации, имеющий корневой центр сертификации. эмитент как один из доверенных корневых центров сертификации Android.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top