web-dev-qa-db-fra.com

Apache HttpClient sur Android produisant CertPathValidatorException (IssuerName! = SubjectName)

Je développe une application Android pour accéder à certaines données de compte battle.net ( https://eu.battle.net ) (pour World of Warcraft) et j'utilise le org.Apache.http.client.HttpClient pour le faire.

C'est le code que j'utilise:

 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 {
    }
}

Le fichier de clés est récupéré (par OpenSSL) comme ceci:

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

J'ai comparé les certificats produits par cette commande ( http://vipsaran.webs.com/openssl_output.txt ) avec ceux que j'ai exportés depuis Firefox ( http://vipsaran.webs.com/Firefox_output.Zip ) et ils sont les mêmes.

En suivant les conseils sur ce blog , j'ai configuré le code ci-dessus et importé les certs (racine et intermédiaires) dans un magasin de clés (battlenetkeystore.bks) utilisé pour HttpClient.

Voici les commandes que j'ai utilisées pour importer les certificats dans le magasin de clés:

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"

Btw. J'ai aussi essayé keytool -import sans le -keyalg "RSA" -sigalg "SHA1withRSA", mais sans changement.

Le problème est que je reçois cette erreur:

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

et je ne trouve pas le moyen de le résoudre . J'ai essayé d'importer les certificats dans le magasin de clés dans un ordre différent, etc. mais rien n'a fonctionné.

Please help (et concentrez-vous sur les solutions basées sur Apache HttpClient uniquement d'Android).

33
Saran

Je pense que vous avez déjà votre propre solution, mais sinon:

En combinant les idées de 

J'ai réussi à établir une connexion sécurisée avec https://eu.battle.net/login/en/login.xml avec juste les classes suivantes. Notez qu'il n'est pas nécessaire de créer un fichier de clés car l'autorité de certification racine est approuvée par Android. Le problème est simplement que les certificats sont renvoyés dans le mauvais ordre.

(Avertissement: vous n'avez pas passé de temps à nettoyer le code.)

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 (activité)

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();
          }
        }                       
        }
    }      
}
56
Andy G

En regardant "openssl s_client -connect eu.battle.net:443", je vois la chaîne de certificats suivante:

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/[email protected]
 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

Notez que c'est hors d'usage. l'émetteur du certificat "n" de la chaîne doit correspondre au sujet du certificat "n + 1". L'émetteur du dernier certificat doit être auto-signé (sujet == émetteur) et non techniquement inclus.

La chaîne correcte serait commandée comme ceci:

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/[email protected]

Le navigateur Android gère la chaîne hors service en demandant à son Android.net.http.CertificateChainValidator code de réorganiser la chaîne de certificats avant de la transmettre pour validation.

 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         }

Pour gérer cela dans votre propre application, vous voulez créer votre propre javax.net.ssl.SSLSocketFactory à partir d'un SSLContext qui a été initialisé avec un X509TrustManager qui réorganise la chaîne avant d'appeler TrustManager par défaut, TrustManager. 

Je n’ai pas récemment consulté le code du client HTTP Apache pour savoir comment fournir votre javax.net.ssl.SSLSocketFactory personnalisé à leur encapsuleur SSLSocketFactory, mais cela devrait être possible (ou tout simplement ne pas utiliser le client HTTP Apache et simplement URL ("https: // ..") .openConnection () qui vous permet de spécifier le javax.net.ssl.SSLSocketFactory personnalisé sur la connexion HttpsURLConnection.

Enfin, notez que vous ne devez importer que l'autorité de certification racine auto-signée dans votre magasin de clés (et uniquement si elle ne figure pas déjà dans le magasin système, mais que je viens de vérifier et que cette autorité de certification n'est pas présente dans froyo). Le CA que vous voulez dans ce cas a pour sujet:

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

Je suppose que votre problème est résolu pour le moment, mais j’avais le même problème et j’ai également eu du mal à trouver la solution. Peut-être que ça aide quelqu'un.

J'ai aussi utilisé le code de Antoine's Blog mais j'ai changé le constructeur utilisé pour SSLSocketFactory.

Donc j'utilise 

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

à cet effet j'ai créé deux KeyStores

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();
}

J'ai créé les magasins BKS avec Portecle . Dans le fichier signature_truststore.bks, j'ai importé le certificat racine et dans le fichier signature_certstore.bks, vous devez importer un ou plusieurs certificats intermédiaires.

Le reste du code est exactement le même que celui du blog.

4
Sandra

Btw, je suis l'auteur du blog mentionné ci-dessus;) J'essaie de répondre à votre question ici.

J'ai examiné les sorties de certificat de Firefox et OpenSL et trouvé quelque chose d'intéressant.

Regardez le certificat racine ca (index 1) à votre sortie openssl. Le nom de l'émetteur est: Thawte Premium Server CA Le nom du sujet est: thawte CA racine principale Les noms du sujet et de l'émetteur sont différents. Par conséquent, ce certificat n'est pas considéré comme l'autorité de certification racine, car il a été émis par une autre instance . Par conséquent, le fournisseur bouncycastle considère ce certificat comme étant l'autorité de certification racine, mais il se plaint car les problèmes et le sujet sont différents.

Je ne sais pas comment vous avez obtenu le "mauvais" certificat de l'autorité de certification racine. Lorsque je regarde le certificat de l'autorité de certification racine dans Firefox, le sujet et l'émetteur sont les mêmes, comme il se doit.

Essayez d'obtenir le bon CA racine et réessayez.

J'espère que cela vous aidera . Salutations et bonne chance;)

0
saxos

J'ai finalement résolu la même exception "nom_du_scripteur ne correspond pas à Nom_du_sujet". J'ai suivi le même blog d'Antoine et ce qui est décrit ici de nombreuses fois, et voici comment le faire fonctionner enfin:

1) Notre site Web utilise deux certificats de GeoTrust: l'autorité de certification intermédiaire nous est émise par une autorité de certification SSL GeoTrust et l'autorité de certification racine est émise pour une autorité de certification GeoTrust SSL par une autorité de certification GeoTrust Global;

2) Si seul l'autorité de certification racine ou les autorités de certification racine et intermédiaire de 1) sont utilisées, j'obtiens l'exception d'incompatibilité, car Android ne prend en charge que un nombre limité d'autorités de certification racines de confiance , et GeoTrust Global CA n'est pas présent. la liste;

3) Dans la page de support de www.geotrust.com, il y a une page appelée GeoTrust Cross Root CA, il suffit de le télécharger enregistrez-le sous un nom tel que crossroot.pem et utilisez cette commande pour générer le magasin de clés:

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

L'étape 2 du blog d'Antonie contient un lien pour télécharger BouncyCastleProvider;

4) Ajoutez le fichier de clés au projet Android, et cela fonctionne - cela est logique, car Android trouve maintenant une autorité de certification racine sécurisée Equifax (voir la liste ci-dessus 1 ) dont le nom de sujet GeoTrust Global CA correspond à la racine de notre site IssuerName .

5) Le code de l'étape 3 de blog fonctionne bien, et pour le rendre plus complet, j'ai copié mon code de test ci-dessous:

    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();

La partie difficile de ce problème est que si l'émetteur de votre autorité de certification racine ne figure pas dans la liste de confiance d'Android, vous devez vous en procurer auprès de la société qui vous délivre les certificats. Demandez-leur de vous fournir une autorité de certification transversale ayant la racine. émetteur en tant qu'une des autorités de certification racine approuvées d'Android. 

0
Jeff Tang

Je n'ai pas de solution pour réparer le chemin. Mais j'ai une solution pour ignorer les certificats. J'utilise cette méthode pour ignorer les certificats auto-signés en développement. Voyez si ça aide. 

 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);
0
Amir Raminfar

cela peut aider: http://blog.antoine.li/index.php/2010/10/Android-trusting-ssl-certificates/ , Avez-vous des certificats de confiance d'un CA (comme Versign ou Geotrust)? ou vous utilisez un certificat auto-signé ... je faisais face au même problème et je l'ai résolu aujourd'hui ...

0
vinay